From b0d31909837b25bfa1ac6cd4e998a16d311070b9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:13:19 -0500 Subject: [PATCH] Import 2.1.41 --- Makefile | 2 +- drivers/isdn/isdn_net.c | 2 +- drivers/pnp/parport_procfs.c | 2 +- drivers/pnp/parport_share.c | 1 + drivers/scsi/README.st | 42 +- drivers/scsi/st.c | 165 +- drivers/scsi/st.h | 3 + drivers/scsi/st_options.h | 8 +- drivers/sound/.version | 4 +- drivers/sound/CHANGELOG | 10 +- drivers/sound/Config.in | 286 +-- drivers/sound/Config.std | 2 +- drivers/sound/Makefile | 28 + drivers/sound/Readme | 8 +- drivers/sound/Readme.cards | 74 +- drivers/sound/Readme.linux | 177 +- drivers/sound/Readme.v30 | 140 -- drivers/sound/ad1848.c | 186 +- drivers/sound/ad1848_mixer.h | 119 +- drivers/sound/audio.c | 191 +- drivers/sound/configure.c | 2 +- drivers/sound/dev_table.c | 24 +- drivers/sound/dev_table.h | 41 +- drivers/sound/dmabuf.c | 510 +++-- drivers/sound/dmasound.c | 3435 ++++++++++++++++++++++++++++ drivers/sound/dmasound.h | 36 + drivers/sound/gus_card.c | 2 +- drivers/sound/gus_midi.c | 1 + drivers/sound/gus_wave.c | 274 ++- drivers/sound/lowlevel/Config.tmpl | 2 +- drivers/sound/lowlevel/aci.c | 4 +- drivers/sound/maui.c | 2 +- drivers/sound/midi_synth.c | 2 +- drivers/sound/midibuf.c | 1 + drivers/sound/mpu401.c | 1 + drivers/sound/opl3.c | 2 + drivers/sound/os.h | 6 + drivers/sound/pas2_card.c | 2 +- drivers/sound/pas2_midi.c | 1 + drivers/sound/pas2_pcm.c | 4 +- drivers/sound/pnp.c | 36 + drivers/sound/pnp.h | 112 + drivers/sound/sb.h | 1 + drivers/sound/sb_common.c | 37 +- drivers/sound/sb_midi.c | 13 +- drivers/sound/sequencer.c | 38 +- drivers/sound/sound_calls.h | 18 +- drivers/sound/sound_pnp.c | 1513 ++++++++++++ drivers/sound/sound_switch.c | 13 +- drivers/sound/soundcard.c | 121 +- drivers/sound/soundvers.h | 4 +- drivers/sound/sscape.c | 110 +- drivers/sound/trix.c | 10 + drivers/sound/uart401.c | 1 + drivers/sound/uart6850.c | 1 + drivers/sound/ulaw.h | 128 +- fs/autofs/autofs_i.h | 14 + fs/autofs/inode.c | 1 + fs/autofs/root.c | 25 +- fs/autofs/waitq.c | 44 + fs/nfs/write.c | 2 +- fs/proc/array.c | 12 +- include/linux/mtio.h | 4 + include/linux/soundcard.h | 27 +- kernel/exit.c | 15 +- mm/page_alloc.c | 1 - mm/slab.c | 1 + mm/vmscan.c | 18 +- 68 files changed, 6615 insertions(+), 1507 deletions(-) delete mode 100644 drivers/sound/Readme.v30 create mode 100644 drivers/sound/dmasound.c create mode 100644 drivers/sound/dmasound.h create mode 100644 drivers/sound/pnp.c create mode 100644 drivers/sound/pnp.h create mode 100644 drivers/sound/sound_pnp.c diff --git a/Makefile b/Makefile index 41a620e1e6e9..b2f2c833cda8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 40 +SUBLEVEL = 41 ARCH := $(shell uname -m | sed s/i.86/i386/ | sed s/sun4u/sparc64/) diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index b6b076360fdd..7d7bdad8dea7 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -374,7 +374,7 @@ isdn_net_stat_callback(int idx, int cmd) return 1; } } - if (clear_bit(0, (void *) &(p->dev.tbusy))) + if (test_and_clear_bit(0, (void *) &(p->dev.tbusy))) mark_bh(NET_BH); } return 1; diff --git a/drivers/pnp/parport_procfs.c b/drivers/pnp/parport_procfs.c index 896abbdd4a88..77574991b9ca 100644 --- a/drivers/pnp/parport_procfs.c +++ b/drivers/pnp/parport_procfs.c @@ -16,10 +16,10 @@ #include #include #include -#include #include #include #include +#include #include diff --git a/drivers/pnp/parport_share.c b/drivers/pnp/parport_share.c index fc19fffd411f..9b854f1389cf 100644 --- a/drivers/pnp/parport_share.c +++ b/drivers/pnp/parport_share.c @@ -220,6 +220,7 @@ struct ppd *parport_register_device(struct parport *port, const char *name, tmp->preempt = pf; tmp->wakeup = kf; tmp->private = handle; + tmp->flags = flags; tmp->irq_func = irq_func; tmp->ctr = port->ctr; tmp->ecr = port->ecr; diff --git a/drivers/scsi/README.st b/drivers/scsi/README.st index fc3ff8e3906e..06d2c71dfdfe 100644 --- a/drivers/scsi/README.st +++ b/drivers/scsi/README.st @@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver. The driver is currently maintained by Kai M{kisara (email Kai.Makisara@metla.fi) -Last modified: Wed Jan 1 15:44:49 1997 by makisara@kai.makisara.fi +Last modified: Tue May 27 22:29:24 1997 by makisara@home BASICS @@ -159,6 +159,15 @@ where buffers is bounded also by the number of drives detected) +MODULE PARAMETERS + +The same parameters can be also set when the driver is loaded as a +module. The keywords are: + +buffer_kbs=xxx the buffer size in kilobytes is set to xxx +write_threshold_kbs=xxx the write threshold in kilobytes set to xxx +max_buffers=xxx the maximum number of tape buffer set to xxx + IOCTLS The tape is positioned and the drive parameters are set with ioctls @@ -253,6 +262,7 @@ MTSETDRVBUFFER the device dependent address. It is recommended to set this flag unless there are tapes using the device dependent (from the old times) (global) + MT_ST_SYSV sets the SYSV sematics (mode) MT_ST_DEBUGGING debugging (global; debugging must be compiled into the driver) MT_ST_SETBOOLEANS @@ -272,6 +282,16 @@ MTSETDRVBUFFER MT_ST_CLEAR_DEFAULT (0xfffff), the default will not be used any more. Otherwise the lower-most bits of the value contain the new value of the parameter. + MT_ST_SET_TIMEOUT + Set the normal timeout in seconds for this device. The + default is 900 seconds (15 minutes). The timeout should be + long enough for the retries done by the device while + reading/writing. + MT_ST_SET_LONG_TIMEOUT + Set the long timeout that is used for operations that are + known to take a long time. The default is 14000 seconds + (3.9 hours). For erase this value is further multiplied by + eight. The following ioctl uses the structure mtpos: MTIOCPOS Reads the current position from the drive. Uses @@ -331,3 +351,23 @@ within file can be obtained if ST_IN_FILE_POS is defined at compile time or the MT_ST_CAN_BSR bit is set for the drive with an ioctl. (The driver always backs over a filemark crossed by read ahead if the user does not request data that far.) + + +DEBUGGING HINTS + +To enable debugging messages, edit st.c and #define DEBUG 1. As seen +above, debugging can be switched off with an ioctl if debugging is +compiled into the driver. The debugging output is not not voluminuous. + +If the tape seems to hang, I would be very interested to hear where +the driver is waiting. With the command 'ps -l' you can see the state +of the process using the tape. If the state is D, the process is +waiting for something. The field WCHAN tells where the driver is +waiting. If you have the current System.map in the correct place (in +/boot for the procps I use) or have updated /etc/psdatabase (for kmem +ps), ps writes the function name in the WCHAN field. If not, you have +to look up the function from System.map. + +Note also that the timeouts are very long compared to most other +drivers. This means that the Linux driver may appear hung although the +real reason is that the tape firmware has got confused. diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 339ba6714502..07fa2bf58e2b 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -11,7 +11,7 @@ Copyright 1992 - 1997 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Wed Jan 1 15:26:54 1997 by makisara@kai.makisara.fi + Last modified: Tue May 27 22:29:00 1997 by makisara@home Some small formal changes - aeb, 950809 */ @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -48,14 +49,23 @@ #include "st.h" #include "constants.h" +#ifdef MODULE +MODULE_PARM(buffer_kbs, "i"); +MODULE_PARM(write_threshold_kbs, "i"); +MODULE_PARM(max_buffers, "i"); +static int buffer_kbs = 0; +static int write_threshold_kbs = 0; +static int max_buffers = 0; +#endif + /* The default definitions have been moved to st_options.h */ -#define ST_BLOCK_SIZE 1024 +#define ST_KILOBYTE 1024 #include "st_options.h" -#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE) -#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE) +#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_KILOBYTE) +#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) /* The buffer size should fit into the 24 bits for length in the 6-byte SCSI read and write commands. */ @@ -220,6 +230,7 @@ st_sleep_done (Scsi_Cmnd * SCpnt) } else (STp->buffer)->last_result = SCpnt->result; +#if 0 if ((STp->buffer)->writing) { /* Process errors before releasing request */ (STp->buffer)->last_result_fatal = st_chk_result(SCpnt); @@ -227,6 +238,10 @@ st_sleep_done (Scsi_Cmnd * SCpnt) } else SCpnt->request.rq_status = RQ_SCSI_DONE; +#else + SCpnt->request.rq_status = RQ_SCSI_DONE; + (STp->buffer)->last_SCpnt = SCpnt; +#endif #if DEBUG STp->write_pending = 0; @@ -286,6 +301,9 @@ write_behind_check(Scsi_Tape *STp) down(&(STp->sem)); + (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt); + ((STp->buffer)->last_SCpnt)->request.rq_status = RQ_INACTIVE; + if (STbuffer->writing < STbuffer->buffer_bytes) memcpy(STbuffer->b_data, STbuffer->b_data + STbuffer->writing, @@ -327,7 +345,7 @@ cross_eof(Scsi_Tape *STp, int forward) TAPE_NR(STp->devt), forward ? "forward" : "backward"); #endif - SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_TIMEOUT, MAX_RETRIES); + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES); if (!SCpnt) return (-EBUSY); @@ -387,7 +405,7 @@ flush_write_buffer(Scsi_Tape *STp) cmd[3] = blks >> 8; cmd[4] = blks; - SCpnt = st_do_scsi(NULL, STp, cmd, transfer, ST_TIMEOUT, MAX_WRITE_RETRIES); + SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES); if (!SCpnt) return (-EBUSY); @@ -594,7 +612,7 @@ scsi_tape_open(struct inode * inode, struct file * filp) memset ((void *) &cmd[0], 0, 10); cmd[0] = TEST_UNIT_READY; - SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES); if (!SCpnt) { if (scsi_tapes[dev].device->host->hostt->module) __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module); @@ -608,7 +626,7 @@ scsi_tape_open(struct inode * inode, struct file * filp) memset ((void *) &cmd[0], 0, 10); cmd[0] = TEST_UNIT_READY; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, ST_LONG_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES); (STp->device)->was_reset = 0; STp->partition = STp->new_partition = 0; @@ -649,7 +667,7 @@ scsi_tape_open(struct inode * inode, struct file * filp) memset ((void *) &cmd[0], 0, 10); cmd[0] = READ_BLOCK_LIMITS; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, ST_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES); if (!SCpnt->result && !SCpnt->sense_buffer[0]) { STp->max_block = ((STp->buffer)->b_data[1] << 16) | @@ -675,7 +693,7 @@ scsi_tape_open(struct inode * inode, struct file * filp) cmd[0] = MODE_SENSE; cmd[4] = 12; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, ST_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES); if ((STp->buffer)->last_result_fatal != 0) { #if DEBUG @@ -807,7 +825,7 @@ scsi_tape_open(struct inode * inode, struct file * filp) static int scsi_tape_close(struct inode * inode, struct file * filp) { - int result; + int result = 0, result2; static unsigned char cmd[10]; Scsi_Cmnd * SCpnt; Scsi_Tape * STp; @@ -823,7 +841,7 @@ scsi_tape_close(struct inode * inode, struct file * filp) STps = &(STp->ps[STp->partition]); if (STp->can_partitions && - update_partition(inode) < 0) { + (result = update_partition(inode)) < 0) { #if DEBUG if (debugging) printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev); @@ -850,7 +868,7 @@ scsi_tape_close(struct inode * inode, struct file * filp) cmd[0] = WRITE_FILEMARKS; cmd[4] = 1 + STp->two_fm; - SCpnt = st_do_scsi(NULL, STp, cmd, 0, ST_TIMEOUT, MAX_WRITE_RETRIES); + SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES); if (!SCpnt) goto out; @@ -862,8 +880,12 @@ scsi_tape_close(struct inode * inode, struct file * filp) ((SCpnt->sense_buffer[0] & 0x80) != 0 && (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] | SCpnt->sense_buffer[5] | - SCpnt->sense_buffer[6]) == 0))) /* Filter out successful write at EOM */ - printk(KERN_ERR "st%d: Error on write filemark.\n", dev); + SCpnt->sense_buffer[6]) == 0))) { + /* Filter out successful write at EOM */ + printk(KERN_ERR "st%d: Error on write filemark.\n", dev); + if (result == 0) + result = (-EIO); + } else { if (STps->drv_file >= 0) STps->drv_file++ ; @@ -884,9 +906,10 @@ scsi_tape_close(struct inode * inode, struct file * filp) STps = &(STp->ps[STp->partition]); if (!STm->sysv || STps->rw != ST_READING) { if (STp->can_bsr) - flush_buffer(inode, filp, 0); + result = flush_buffer(inode, filp, 0); else if (STps->eof == ST_FM_HIT) { - if (cross_eof(STp, FALSE)) { + result = cross_eof(STp, FALSE); + if (result) { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; @@ -896,7 +919,8 @@ scsi_tape_close(struct inode * inode, struct file * filp) STps->eof = ST_NOEOF; } } - else if ((STps->eof == ST_NOEOF && !cross_eof(STp, TRUE)) || + else if ((STps->eof == ST_NOEOF && + !(result = cross_eof(STp, TRUE))) || STps->eof == ST_FM_HIT) { if (STps->drv_file >= 0) STps->drv_file++; @@ -906,8 +930,11 @@ scsi_tape_close(struct inode * inode, struct file * filp) } out: - if (STp->rew_at_close) - st_int_ioctl(inode, MTREW, 1); + if (STp->rew_at_close) { + result2 = st_int_ioctl(inode, MTREW, 1); + if (result == 0) + result = result2; + } if (STp->door_locked == ST_LOCKED_AUTO) st_int_ioctl(inode, MTUNLOCK, 0); @@ -923,7 +950,7 @@ out: if(st_template.module) __MOD_DEC_USE_COUNT(st_template.module); - return 0; + return result; } @@ -1083,7 +1110,7 @@ st_write(struct inode * inode, struct file * filp, const char * buf, cmd[3] = blks >> 8; cmd[4] = blks; - SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, ST_TIMEOUT, MAX_WRITE_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES); if (!SCpnt) return (-EBUSY); @@ -1177,7 +1204,8 @@ st_write(struct inode * inode, struct file * filp, const char * buf, } if (STm->do_async_writes && - ((STp->buffer)->buffer_bytes >= STp->write_threshold || + (((STp->buffer)->buffer_bytes >= STp->write_threshold && + (STp->buffer)->buffer_bytes >= STp->block_size) || STp->block_size == 0) ) { /* Schedule an asynchronous write */ if (!SCpnt) { @@ -1211,7 +1239,7 @@ st_write(struct inode * inode, struct file * filp, const char * buf, scsi_do_cmd (SCpnt, (void *) cmd, (STp->buffer)->b_data, (STp->buffer)->writing, - st_sleep_done, ST_TIMEOUT, MAX_WRITE_RETRIES); + st_sleep_done, STp->timeout, MAX_WRITE_RETRIES); } else if (SCpnt != NULL) SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ @@ -1270,7 +1298,7 @@ read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt) cmd[4] = blks; SCpnt = *aSCpnt; - SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, ST_TIMEOUT, MAX_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES); *aSCpnt = SCpnt; if (!SCpnt) return (-EBUSY); @@ -1572,6 +1600,8 @@ st_log_options(Scsi_Tape *STp, ST_mode *STm, int dev) "st%d: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); + printk(KERN_INFO +"st%d: sysv: %d\n", dev, STm->sysv); #if DEBUG printk(KERN_INFO "st%d: debugging: %d\n", @@ -1615,6 +1645,7 @@ st_set_options(struct inode * inode, long options) if ((STp->device)->scsi_level >= SCSI_2) STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; + STm->sysv = (options & MT_ST_SYSV) != 0; #if DEBUG debugging = (options & MT_ST_DEBUGGING) != 0; #endif @@ -1645,6 +1676,8 @@ st_set_options(struct inode * inode, long options) STp->can_partitions = value; if ((options & MT_ST_SCSI2LOGICAL) != 0) STp->scsi2_logical = value; + if ((options & MT_ST_SYSV) != 0) + STm->sysv = value; #if DEBUG if ((options & MT_ST_DEBUGGING) != 0) debugging = value; @@ -1652,7 +1685,7 @@ st_set_options(struct inode * inode, long options) st_log_options(STp, STm, dev); } else if (code == MT_ST_WRITE_THRESHOLD) { - value = (options & ~MT_ST_OPTIONS) * ST_BLOCK_SIZE; + value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; if (value < 1 || value > st_buffer_size) { printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n", dev, value); @@ -1674,6 +1707,19 @@ st_set_options(struct inode * inode, long options) dev, STm->default_blksize); } } + else if (code == MT_ST_TIMEOUTS) { + value = (options & ~MT_ST_OPTIONS); + if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { + STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; + printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev, + (value & ~MT_ST_SET_LONG_TIMEOUT)); + } + else { + STp->timeout = value * HZ; + printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev, + value); + } + } else if (code == MT_ST_DEF_OPTIONS) { code = (options & ~MT_ST_CLEAR_DEFAULT); value = (options & MT_ST_CLEAR_DEFAULT); @@ -1746,7 +1792,7 @@ st_compression(Scsi_Tape * STp, int state) cmd[2] = COMPRESSION_PAGE; cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_TIMEOUT, 0); + SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0); if (SCpnt == NULL) return (-EBUSY); dev = TAPE_NR(SCpnt->request.rq_dev); @@ -1789,7 +1835,7 @@ st_compression(Scsi_Tape * STp, int state) (STp->buffer)->b_data[0] = 0; /* Reserved data length */ (STp->buffer)->b_data[1] = 0; /* Reserved media type byte */ (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_TIMEOUT, 0); + SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0); if ((STp->buffer)->last_result_fatal != 0) { #if DEBUG @@ -1817,7 +1863,7 @@ st_compression(Scsi_Tape * STp, int state) st_int_ioctl(struct inode * inode, unsigned int cmd_in, unsigned long arg) { - int timeout = ST_LONG_TIMEOUT; + int timeout; long ltmp; int i, ioctl_result; int chg_eof = TRUE; @@ -1831,6 +1877,7 @@ st_int_ioctl(struct inode * inode, STp = &(scsi_tapes[dev]); if (STp->ready != ST_READY && cmd_in != MTLOAD) return (-EIO); + timeout = STp->long_timeout; STps = &(STp->ps[STp->partition]); fileno = STps->drv_file; blkno = STps->drv_block; @@ -1961,7 +2008,7 @@ st_int_ioctl(struct inode * inode, cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; - timeout = ST_TIMEOUT; + timeout = STp->timeout; #if DEBUG if (debugging) { if (cmd_in == MTWEOF) @@ -1981,7 +2028,7 @@ st_int_ioctl(struct inode * inode, cmd[0] = REZERO_UNIT; #if ST_NOWAIT cmd[1] = 1; /* Don't wait for completion */ - timeout = ST_TIMEOUT; + timeout = STp->timeout; #endif #if DEBUG if (debugging) @@ -2012,9 +2059,9 @@ st_int_ioctl(struct inode * inode, } #if ST_NOWAIT cmd[1] = 1; /* Don't wait for completion */ - timeout = ST_TIMEOUT; + timeout = STp->timeout; #else - timeout = ST_LONG_TIMEOUT * 8; + timeout = STp->long_timeout; #endif #if DEBUG if (debugging) { @@ -2037,7 +2084,7 @@ st_int_ioctl(struct inode * inode, cmd[0] = START_STOP; #if ST_NOWAIT cmd[1] = 1; /* Don't wait for completion */ - timeout = ST_TIMEOUT; + timeout = STp->timeout; #endif cmd[4] = 3; #if DEBUG @@ -2076,9 +2123,9 @@ st_int_ioctl(struct inode * inode, cmd[1] = 1; /* To the end of tape */ #if ST_NOWAIT cmd[1] |= 2; /* Don't wait for completion */ - timeout = ST_TIMEOUT; + timeout = STp->timeout; #else - timeout = ST_LONG_TIMEOUT * 8; + timeout = STp->long_timeout * 8; #endif #if DEBUG if (debugging) @@ -2147,7 +2194,7 @@ st_int_ioctl(struct inode * inode, (STp->buffer)->b_data[9] = (ltmp >> 16); (STp->buffer)->b_data[10] = (ltmp >> 8); (STp->buffer)->b_data[11] = ltmp; - timeout = ST_TIMEOUT; + timeout = STp->timeout; #if DEBUG if (debugging) { if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) @@ -2338,7 +2385,7 @@ get_location(struct inode * inode, unsigned int *block, int *partition, if (!logical && !STp->scsi2_logical) scmd[1] = 1; } - SCpnt = st_do_scsi(NULL, STp, scmd, 20, ST_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES); if (!SCpnt) return (-EBUSY); @@ -2394,13 +2441,14 @@ set_location(struct inode * inode, unsigned int block, int partition, int dev = TAPE_NR(inode->i_rdev); int result, p; unsigned int blk; - int timeout = ST_LONG_TIMEOUT; + int timeout; unsigned char scmd[10]; Scsi_Cmnd *SCpnt; STp = &(scsi_tapes[dev]); if (STp->ready != ST_READY) return (-EIO); + timeout = STp->long_timeout; STps = &(STp->ps[STp->partition]); #if DEBUG @@ -2457,7 +2505,7 @@ set_location(struct inode * inode, unsigned int block, int partition, } #if ST_NOWAIT scmd[1] |= 1; /* Don't wait for completion */ - timeout = ST_TIMEOUT; + timeout = STp->timeout; #endif SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES); @@ -2554,7 +2602,7 @@ nbr_partitions(struct inode * inode) cmd[2] = PART_PAGE; cmd[4] = 200; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, ST_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES); if (SCpnt == NULL) return (-EBUSY); SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ @@ -2628,7 +2676,7 @@ partition_tape(struct inode * inode, int size) cmd[1] = 0x10; cmd[4] = length + MODE_HEADER_LENGTH; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_LONG_TIMEOUT, MAX_READY_RETRIES); + SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, MAX_READY_RETRIES); if (SCpnt == NULL) return (-EBUSY); SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ @@ -2979,13 +3027,13 @@ normalize_buffer(ST_buffer *STbuffer) /* Set the boot options. Syntax: st=xxx,yyy where xxx is buffer size in 1024 byte blocks and yyy is write threshold in 1024 byte blocks. */ - void -st_setup(char *str, int *ints) + __initfunc( void +st_setup(char *str, int *ints)) { if (ints[0] > 0 && ints[1] > 0) - st_buffer_size = ints[1] * ST_BLOCK_SIZE; + st_buffer_size = ints[1] * ST_KILOBYTE; if (ints[0] > 1 && ints[2] > 0) { - st_write_threshold = ints[2] * ST_BLOCK_SIZE; + st_write_threshold = ints[2] * ST_KILOBYTE; if (st_write_threshold > st_buffer_size) st_write_threshold = st_buffer_size; } @@ -3045,12 +3093,14 @@ static int st_attach(Scsi_Device * SDp){ tpnt->can_partitions = 0; tpnt->two_fm = ST_TWO_FM; tpnt->fast_mteom = ST_FAST_MTEOM; - tpnt->scsi2_logical = 0; + tpnt->scsi2_logical = ST_SCSI2LOGICAL; tpnt->write_threshold = st_write_threshold; tpnt->default_drvbuffer = 0xff; /* No forced buffering */ tpnt->partition = 0; tpnt->new_partition = 0; tpnt->nbr_partitions = 0; + tpnt->timeout = ST_TIMEOUT; + tpnt->long_timeout = ST_LONG_TIMEOUT; for (i=0; i < ST_NBR_MODES; i++) { STm = &(tpnt->modes[i]); @@ -3099,7 +3149,7 @@ static int st_detect(Scsi_Device * SDp) static int st_registered = 0; -/* Driver initialization */ +/* Driver initialization (not __initfunc because may be called later) */ static int st_init() { int i; @@ -3213,8 +3263,25 @@ static void st_detach(Scsi_Device * SDp) #ifdef MODULE int init_module(void) { + int result; + st_template.module = &__this_module; - return scsi_register_module(MODULE_SCSI_DEV, &st_template); + result = scsi_register_module(MODULE_SCSI_DEV, &st_template); + if (result) + return result; + + if (buffer_kbs > 0) + st_buffer_size = buffer_kbs * ST_KILOBYTE; + if (write_threshold_kbs > 0) + st_write_threshold = write_threshold_kbs * ST_KILOBYTE; + if (st_write_threshold > st_buffer_size) + st_write_threshold = st_buffer_size; + if (max_buffers > 0) + st_max_buffers = max_buffers; +printk(KERN_INFO "st: bufsize %d, wrt %d, max buffers %d.\n", +st_buffer_size, st_write_threshold, st_max_buffers); + + return 0; } void cleanup_module( void) diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index c29455fa6deb..c25c80cc7af2 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -20,6 +20,7 @@ typedef struct { int writing; int last_result; int last_result_fatal; + Scsi_Cmnd *last_SCpnt; unsigned char *b_data; int orig_size; unsigned char *orig_b_data; @@ -78,6 +79,8 @@ typedef struct { unsigned char scsi2_logical; unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ int write_threshold; + int timeout; /* timeout for normal commands */ + int long_timeout; /* timeout for commands known to take long time*/ /* Mode characteristics */ ST_mode modes[ST_NBR_MODES]; diff --git a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h index f6041860894f..205940441965 100644 --- a/drivers/scsi/st_options.h +++ b/drivers/scsi/st_options.h @@ -3,7 +3,7 @@ Copyright 1995 Kai Makisara. - Last modified: Thu Dec 14 21:51:27 1995 by root@kai.makisara.fi + Last modified: Tue May 27 22:29:15 1997 by makisara@home */ #ifndef _ST_OPTIONS_H @@ -88,8 +88,14 @@ files and the file number status is retained. */ #define ST_FAST_MTEOM 0 +/* If ST_SCSI2LOGICAL is nonzero, the logical block addresses are used for + MTIOCPOS and MTSEEK by default. Vendor addresses are used if ST_SCSI2LOGICAL + is zero. */ +#define ST_SCSI2LOGICAL 0 + /* If ST_SYSV is non-zero, the tape behaves according to the SYS V semantics. The default is BSD semantics. */ #define ST_SYSV 0 + #endif diff --git a/drivers/sound/.version b/drivers/sound/.version index b344e143cd55..56cbb7db2801 100644 --- a/drivers/sound/.version +++ b/drivers/sound/.version @@ -1,2 +1,2 @@ -3.8-beta9 -0x030803 +3.8a +0x030804 diff --git a/drivers/sound/CHANGELOG b/drivers/sound/CHANGELOG index 3b82d35ce57e..17c2dad5f32d 100644 --- a/drivers/sound/CHANGELOG +++ b/drivers/sound/CHANGELOG @@ -1,5 +1,11 @@ -Changelog for version 3.8-beta8 -------------------------------- +Changelog for version 3.8 +-------------------------- + +Since 3.8-beta21 +- Fixed all known bugs (I think). + +Since 3.8-beta8 +- Lot of fixes to audio playback code in dmabuf.c Since 3.8-beta6 - Fixed the famous Quake delay bug. diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index f7567a4962e1..310bf01bf1f4 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -1,277 +1,15 @@ -bool 'ProAudioSpectrum 16 support' CONFIG_PAS -bool '_TRUE_ Sound Blaster (SB, SBPro, SB16/32/64, ESS, Jazz16) support' CONFIG_SB -bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB -bool 'Gravis Ultrasound support' CONFIG_GUS -bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 -bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS -bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 -bool 'GUS MAX support' CONFIG_GUSMAX -bool 'Microsoft Sound System support' CONFIG_MSS -bool 'Ensoniq SoundScape support' CONFIG_SSCAPE -bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX -bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16 -bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 -bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI -bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 - -if [ "$CONFIG_AEDSP16" = "y" ]; then -hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 -fi - -if [ "$CONFIG_SB" = "y" ]; then -hex 'I/O base for SB Check from manual of the card' SBC_BASE 220 -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7 -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1 -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5 -fi - -if [ "$CONFIG_SB" = "y" ]; then -hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330 -fi - - -if [ "$CONFIG_SB" = "y" ]; then -comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.' -fi - - -if [ "$CONFIG_SB" = "y" ]; then -comment 'Enter -1 to the following question if you have something else such as SB16/32.' -fi - -if [ "$CONFIG_SB" = "y" ]; then -int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1 -fi - -if [ "$CONFIG_PAS" = "y" ]; then -int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10 -fi - -if [ "$CONFIG_PAS" = "y" ]; then -int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6 -fi - -if [ "$CONFIG_GUS" = "y" ]; then -int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1 -fi - -if [ "$CONFIG_GUS16" = "y" ]; then -hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530 -fi - -if [ "$CONFIG_GUS16" = "y" ]; then -int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7 -fi - -if [ "$CONFIG_GUS16" = "y" ]; then -int 'GUS DMA 0, 1 or 3' GUS16_DMA 3 -fi - -if [ "$CONFIG_MPU401" = "y" ]; then -hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330 -fi - -if [ "$CONFIG_MPU401" = "y" ]; then -int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9 -fi - - -if [ "$CONFIG_MAUI" = "y" ]; then -comment 'ERROR! You have to use old sound configuration method with Maui.' -fi - -if [ "$CONFIG_MAUI" = "y" ]; then -hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330 -fi - -if [ "$CONFIG_MAUI" = "y" ]; then -int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9 -fi - -if [ "$CONFIG_UART6850" = "y" ]; then -hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0 -fi - -if [ "$CONFIG_UART6850" = "y" ]; then -int 'UART6850 IRQ (Unknown)' U6850_IRQ -1 -fi - - -if [ "$CONFIG_PSS" = "y" ]; then -comment 'ERROR! You have to use old sound configuration method with PSS cards.' -fi - -if [ "$CONFIG_PSS" = "y" ]; then -hex 'PSS I/O base 220 or 240' PSS_BASE 220 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330 -fi - -if [ "$CONFIG_PSS" = "y" ]; then -int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3 -fi - -if [ "$CONFIG_MSS" = "y" ]; then -int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534 -fi - -if [ "$CONFIG_SSCAPE" = "y" ]; then -int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11 -fi - - -if [ "$CONFIG_TRIX" = "y" ]; then -comment 'ERROR! You have to use old sound configuration method with AudioTrix.' -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7 -fi - -if [ "$CONFIG_TRIX" = "y" ]; then -int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330 -fi - -if [ "$CONFIG_CS4232" = "y" ]; then -int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330 -fi - -if [ "$CONFIG_MAD16" = "y" ]; then -int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9 -fi # -$MAKE -C drivers/sound kernelconfig || exit 1 +# Sound driver configuration +# +#-------- +# There is another confic script which is compatible with rest of +# the kernel. It can be activated by running 'make mkscript' in this +# directory. Please note that this is an _experimental_ feature which +# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). +#-------- +# +$MAKE -C drivers/sound config || exit 1 + bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then @@ -306,7 +44,7 @@ if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then fi fi - if [ "$CONFIG_MIDI" = "y" ]; then + if [ "$CONFIG_MPU401" = "y" ]; then bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then comment 'Audio Excel DSP 16 [MPU-401]' diff --git a/drivers/sound/Config.std b/drivers/sound/Config.std index fb8a76753ce6..310bf01bf1f4 100644 --- a/drivers/sound/Config.std +++ b/drivers/sound/Config.std @@ -44,7 +44,7 @@ if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then fi fi - if [ "$CONFIG_MIDI" = "y" ]; then + if [ "$CONFIG_MPU401" = "y" ]; then bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then comment 'Audio Excel DSP 16 [MPU-401]' diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 499521c9f73b..b0a3483d54f7 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -4,7 +4,33 @@ # parent makes. (hopefully) # # +# +# +ifeq ($(ARCH),m68k) + L_TARGET := sound.a + L_OBJS := + M_OBJS := + ifeq ($(CONFIG_DMASOUND),y) + L_OBJS += dmasound.o + else + ifeq ($(CONFIG_DMASOUND),m) + M_OBJS += dmasound.o + endif + endif + + include $(TOPDIR)/Rules.make + + clean: + rm -f core *.o *.a *.s + + # dummy rule to keep 'make xconfig' happy + mkscript: + +# More dummy targets for make [menu]config +mkscript: +kernelconfig: +else .PHONY: dummy SUB_DIRS = lowlevel VERSION = `head -1 .version` @@ -36,6 +62,7 @@ build: install: sound.o cp sound.o $(MODULEDIR) +else endif .c.o: @@ -161,3 +188,4 @@ ifeq (.depend,$(wildcard .depend)) include .depend endif endif +endif diff --git a/drivers/sound/Readme b/drivers/sound/Readme index a859afb12fff..c5002a1f793f 100644 --- a/drivers/sound/Readme +++ b/drivers/sound/Readme @@ -1,5 +1,5 @@ -OSS Lite version 3.8-beta release notes ---------------------------------------- +OSS Lite version 3.8 release notes +---------------------------------- Most up to date information about this driver is available from http://www.4front-tech.com/ossfree or http://personal.eunet.fi/pp/voxware @@ -16,10 +16,10 @@ Please check http://www.4front-tech.com/pguide for more info about programming with OSS. ==================================================== -- THIS VERSION ____REQUIRES____ Linux 2.1.26 OR LATER. +- THIS VERSION ____REQUIRES____ Linux 2.1.36 OR LATER. ==================================================== -Packages "snd-util-3.7.tar.gz" and "snd-data-0.1.tar.Z" +Packages "snd-util-3.8.tar.gz" and "snd-data-0.1.tar.Z" contain useful utilities to be used with this driver. See http://www.4front-tech.com/ossfree/getting.html for download instructions. diff --git a/drivers/sound/Readme.cards b/drivers/sound/Readme.cards index 7f89cf17cab3..148afd6b08e9 100644 --- a/drivers/sound/Readme.cards +++ b/drivers/sound/Readme.cards @@ -43,8 +43,8 @@ IMPORTANT! This document covers only cards that were "known" when -THE BIGGEST MISTAKE YOU CAN DO -============================== +THE BIGGEST MISTAKES YOU CAN DO +=============================== 1. Assuming that the card is Sound Blaster compatible when it's not. -------------------------------------------------------------------- @@ -106,21 +106,24 @@ for PnP models of soudcards even you have managed to wake up the card properly. Many PnP cards are simply too much different than their original non PnP ancestors which are covered by this document. + Cards that are not (fully) supported by this driver =================================================== See http://www.4front-tech.com/ossfree for information about soundcards to be supported in future. + How to use sound without recompiling kernel and/or sound driver ---------------------------------------------------------------- +=============================================================== There is commercial sound driver which should be released during Apr 96. It comes in precompiled form and doesn't require recompiling of kernel. See http://www.4Front-tech.com/oss.html for more info. + Configuring PnP cards ---------------------- +===================== New versions of most soundcards use so called ISA PnP protocol for soft configuring their I/O, IRQ, DMA and shared memory resources. @@ -170,8 +173,9 @@ See http://www.4front-tech.com/linux.html for more info. This is the way you probably like to do it if you don't waste hours of time in recompiling kernel and the required tools. + Read this before trying to configure the driver ------------------------------------------------ +=============================================== There are currently many cards that work with this driver. Some of the cards have native support while others work since they emulate some other @@ -196,12 +200,14 @@ Sound Blasters SB 1.0 to 2.0 SB Pro SB 16 - SB32/AWE - Configure SB32/AWE just like SB16. See lowlevel/README.awe + SB32/64/AWE + Configure SB32/64/AWE just like SB16. See lowlevel/README.awe for information about using the wave table synth. + NOTE! AWE63/Gold and 16/32/AWE "PnP" cards need to be activated + using isapnptools before they work with OSS/Free. SB16 compatible cards by other manufacturers than Creative. You have been fooled since there are _no_ SB16 compatible - cards on the market (Feb 96). It's likely that your card + cards on the market (May 97). It's likely that your card is compatible just with SB Pro but there is also a non-SB- compatible 16 bit mode. Usually it's MSS/WSS but it could also be a proprietary one like MV Jazz16 or ESS ES688. OPTi @@ -237,7 +243,7 @@ Gravis Ultrasound (GUS) GUS + the 16 bit option GUS MAX GUS ACE (No MIDI port and audio recording) - GUS PnP (in GUS MAX compatible mode) + GUS PnP (with RAM) MPU-401 and compatibles The driver works both with the full (intelligent mode) MPU-401 @@ -267,10 +273,6 @@ Windows Sound System (MSS/WSS) cause a conflict. So check if your card is listed in this file before enabling the MSS support. -6850 UART MIDI - This UART chip is used in the MIDI interface of some (rare) - soundcards. It's supported by the driver in case you need it. - Yamaha FM synthesizers (OPL2, OPL3 (not OPL3-SA) and OPL4) Most soundcards have a FM synthesizer chip. The OPL2 is a 2 operator chip used in the original AdLib card. Currently it's used @@ -321,7 +323,9 @@ Ensoniq SoundScape and compatibles Several companies (including Ensoniq, Reveal and Spea) are selling cards based on this architecture. - NOTE! The new PnP SoundScape is not supported yet. + NOTE! The SoundScape PnP is not supported by OSS/Free. Ensoniq VIVO and + VIVO90 cards are not compatible with Soundscapes so the Soundscape driver + will not work with them. You may want to use OSS/Linux with these cards. MAD16 and Mozart based cards The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929), @@ -332,20 +336,32 @@ MAD16 and Mozart based cards interface chip performs address decoding for the other chips. NOTE! Tropez Plus is not MAD16 but CS4232 based. NOTE! MAD16 PnP cards (82C924, 82C925, 82C931) are not MAD16 compatible - in the PnP mode. You will have to use them in MAD16 mode after having - initialized them using isapnptools or DOS. + in the PnP mode. You will have to use them in MSS mode after having + initialized them using isapnptools or DOS. 82C931 probably requires + initialization using DOS/Windows (running isapnptools is not enough). + It's possible to use 82C931 with OSS/Free by jumpering it to non-PnP + mode (provided that the card has a jumper for this). In non-PnP mode + 82C931 is compatible with 82C930 and should work with the MAD16 driver + (without need to use isapnptools or DOS to initialize it). All OPTi + chips are supported by OSS/Linux (both in PnP and non-PnP modes). Audio Excel DSP16 Support for this card was written by Riccardo Faccetti (riccardo@cdc8g5.cdc.polimi.it). The AEDSP16 driver included in the lowlevel/ directory. To use it you should use the "new" config script and to enable the "Additional low level drivers" option. -Crystal CS4232 and 4236 based cards such as AcerMagic S23, TB Tropez _Plus_ and + +Crystal CS4232 and CS4236 based cards such as AcerMagic S23, TB Tropez _Plus_ and many PC motherboards (Compaq, HP, Intel, ...) CS4232 is a PnP multimedia chip which contains a CS3231A codec, SB and MPU401 emulations. There is support for OPL3 too. Unfortunately the MPU401 mode doesn't work (I don't know how to - initialize it). CS4236 is an enhanced (compatible) version of 4232. + initialize it). CS4236 is an enhanced (compatible) version of CS4232. + NOTE! Don't ever try to use isapnptools with CS4232 since this just + freezes your machine (due to chip bugs). If you have problems in getting + CS4232 working you could try initializing it with DOS (CS4232C.EXE) and + then booting Linux using loadlin. CS4232C.EXE loads a secret firmware + patch which is not documented by Crystal. Turtle Beach Maui and Tropez "classic" This driver version supports sample, patch and program loading commands @@ -354,9 +370,13 @@ Turtle Beach Maui and Tropez "classic" the Tropez is based on the MAD16 chip (see above). NOTE! You will have to use the "old" config script when configuring Maui or Tropez. + NOTE! Tropez Plus is different card than Tropez "classic" and will not + work fully in Linux. You can get audio features working by configuring + the card as a CS4232 based card (above). + Jumpers and software configuration ----------------------------------- +================================== Some of the earliest soundcards were jumper configurable. You have to configure the driver use I/O, IRQ and DMA settings @@ -388,8 +408,9 @@ how the card must be initialized. It cannot initialize unknown cards even if they are otherwise compatible with some other cards (like SB, MPU401 or Windows Sound System). + What if your card was not listed above? ---------------------------------------- +======================================= The first thing to do is to look at the major IC chips on the card. Many of the latest soundcards are based on some standard chips. If you @@ -518,8 +539,19 @@ select some options automatically as well. that doesn't really have a MPU401 could cause some trouble. If your card was in the list of supported cards (above), please look at the card specific instructions later in this file. + + In MOST cases this MPU401 driver should only be used with "true" + MIDI-only MPU401 professional cards. In most other cases there + is another way to get the MPU401 compatible interface of a + soundcard to work. + Support for the MPU401 compatible MIDI port of SB16, ESS1688 + and MV Jazz16 cards is included in the SB driver. Use it instead + of this separate MPU401 driver with these cards. As well + Soundscape, PSS and Maui drivers include their own MPU401 + options. + It's safe to answer 'y' if you have a true MPU401 MIDI interface - card. + card. "6850 UART Midi support", - It's safe to answer 'n' to this question in all cases. The 6850 UART interface is so rarely used. diff --git a/drivers/sound/Readme.linux b/drivers/sound/Readme.linux index 053880e849e8..b1121ebbe15a 100644 --- a/drivers/sound/Readme.linux +++ b/drivers/sound/Readme.linux @@ -72,171 +72,14 @@ Please check http://www.4front-tech.com/osslite for more info. Hannu Savolainen hannu@voxware.pp.fi -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -NOTE! - -Running the script enclosed below is usually not required. All known Linux -distributions build them automaticly during installation. You need to run -this script only if "ls /dev/sndstat" displays "No such file or directory". -In case of any other error message you should start looking for the reason -from somewhere else (see above). -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ----------------- cut here ------------------------------ -#!/bin/sh -# ***************************************** -# * NOTICE! -# * -# * For security reasons read access to /dev/dsp* and /dev/audio* has been -# * disabled from other than root. Otherwise any user may be able to spy -# * what is being talked about near the microphone. -# * This effectively disables audio recording by other than root. In case -# * this capability is required, you should change AUDIOPERMS (below) to 666 -# * before executing this script. -# ***************************************** -AUDIOPERMS=622 -# -# -# -# -# Create the devices -# -# Mixer devices -# -if [ -e /dev/mixer ]; then - rm -f /dev/mixer -fi - -if [ -e /dev/mixer0 ]; then - rm -f /dev/mixer0 -fi - -mknod -m 666 /dev/mixer0 c 14 0 -ln -sf /dev/mixer0 /dev/mixer - -if [ -e /dev/mixer1 ]; then - rm -f /dev/mixer1 -fi -mknod -m 666 /dev/mixer1 c 14 16 - - -# Sequencer (14, 1) -# -if [ -e /dev/sequencer ]; then - rm -f /dev/sequencer -fi -mknod -m 666 /dev/sequencer c 14 1 - -if [ -e /dev/patmgr0 ]; then - rm -f /dev/patmgr0 -fi -mknod -m 666 /dev/patmgr0 c 14 17 -if [ -e /dev/patmgr1 ]; then - rm -f /dev/patmgr1 -fi -mknod -m 666 /dev/patmgr1 c 14 33 - - # music (14, 8) - # - if [ -e /dev/music ]; then - rm -f /dev/music - fi - - mknod -m 666 /dev/music c 14 8 - if [ -e /dev/sequencer2 ]; then - rm -f /dev/sequencer2 - fi - ln -s /dev/music /dev/sequencer2 - -# Midi devices -# -if [ -e /dev/midi ]; then - rm -f /dev/midi # Old name. Don't use it -fi - if [ -e /dev/midi00 ]; then - rm -f /dev/midi00 - fi - mknod -m 666 /dev/midi00 c 14 2 - ln -sf /dev/midi00 /dev/midi - - if [ -e /dev/midi01 ]; then - rm -f /dev/midi01 - fi - mknod -m 666 /dev/midi01 c 14 18 - - if [ -e /dev/midi02 ]; then - rm -f /dev/midi02 - fi - mknod -m 666 /dev/midi02 c 14 34 - - if [ -e /dev/midi03 ]; then - rm -f /dev/midi03 - fi - mknod -m 666 /dev/midi03 c 14 50 -# -# DSP (14, 3) -# -if [ -e /dev/dsp ]; then - rm -f /dev/dsp -fi -if [ -e /dev/dsp0 ]; then - rm -f /dev/dsp0 -fi -mknod -m $AUDIOPERMS /dev/dsp0 c 14 3 -ln -s /dev/dsp0 /dev/dsp - -# -# DSPW (14, 5) -# -if [ -e /dev/dspW ]; then - rm -f /dev/dspW -fi -if [ -e /dev/dspW0 ]; then - rm -f /dev/dspW0 -fi -mknod -m $AUDIOPERMS /dev/dspW0 c 14 5 -ln -s /dev/dspW0 /dev/dspW - -if [ -e /dev/dspW1 ]; then - rm -f /dev/dspW1 -fi -mknod -m $AUDIOPERMS /dev/dspW1 c 14 37 - -# -# SPARC compatible /dev/audio (14, 4) -# -if [ -e /dev/audio ]; then - rm -f /dev/audio -fi -if [ -e /dev/audio0 ]; then - rm -f /dev/audio0 -fi -mknod -m $AUDIOPERMS /dev/audio0 c 14 4 -ln -s /dev/audio0 /dev/audio - -# -# DSP1 (14, 19) /dev/dsp for the second soundcard. -# Also the SB emulation part of the -# PAS16 card. -# -if [ -e /dev/dsp1 ]; then - rm -f /dev/dsp1 -fi -mknod -m $AUDIOPERMS /dev/dsp1 c 14 19 -# -# SPARC audio1 (14, 20) -# /dev/audio for the second soundcard. -# Also the SB emulation part of the -# PAS16 card. -# -if [ -e /dev/audio1 ]; then - rm -f /dev/audio1 -fi -mknod -m $AUDIOPERMS /dev/audio1 c 14 20 -# -# /dev/sndstat (14,6) For debugging purposes -# -if [ -e /dev/sndstat ]; then - rm -f /dev/sndstat -fi -mknod -m 666 /dev/sndstat c 14 6 -exit 0 +SURPRISE SURPRISE!!! + +The device file creation script that used to be here earlier is +obviously not here any more. + +Why? + +Because you do not need it. All Linux distributions have the +device files properly created (yes they are) so you should not +try to run any scripts which create them. diff --git a/drivers/sound/Readme.v30 b/drivers/sound/Readme.v30 deleted file mode 100644 index 2b48ee002d43..000000000000 --- a/drivers/sound/Readme.v30 +++ /dev/null @@ -1,140 +0,0 @@ -Sound driver version v3.0 (and later) -------------------------------------- - -All features of v2.90-2 should work as earlier. There could be some -omissions but they are unintentional. I started this version thread -after v2.3 so all features implemented before it are there. - -New features -============ - -There are now two new device interfaces. The /dev/midi## is a raw -tty like interface to MIDI ports. There is a device file for each MIDI -port on your system. They are named (/dev/midi00 to /dev/midiNN). -The second addition is the /dev/music which is higher level interface -than the old /dev/sequencer. It's intended for writing device independent -applications like sequencers. - -/dev/midi## ------------ - -This interface should be useful for applications like MIDI sysex librarians. -There are (currently) no timing features so making music could be impossible. - -There are as many /dev/midi## devices as there are MIDI ports in the system. -The /dev/midi00 is connected to the first one, /dev/midi01 to the second etc. - -These devices work like tty devices in raw mode. Everything written to them is -sent out to the MIDI port. There is currently an extra delay of at most -1/100th of sec but it will be removed later. - -The reading algorithm is little bit more complicated. There are two different -cases: - -1) There is at least one byte in the input buffer. - -The read returns as many bytes as it can without waiting for more bytes. -For example when a process reads 100 bytes and there are 10 bytes in the -buffer, the read returns just 10 bytes. - -2) The input buffer is empty when the process calls read. - -The read waits for the first byte and then continues as in case 1. By -default it waits infinitely but there is an ioctl for setting a timeout -for this. The ioctl(fd, SNDCTL_MIDI_PRETIME, &time) changes the timeout. -The time is given in 1/10th of seconds (10 means one second). - -Other ioctl calls: - -ioctl(fd, SNDCTL_MIDI_MPUMODE, &mode) is available for full MPU-401 -compatible devices such as MPU-IPC-T, MQ PC Midi Card or MQX-32. -It's not available for the so called MPU UART ports of some soundcards -(PAS16, SB16 etc). By default the MIDI port is in UART mode after open. -If this ioctl is called with mode=1, the interface is put to the intelligent -(coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called. -It could have some strange effects if not called immediately after open. This -call returns EINVAL if the midi port doesn't support the MPU-401 intelligent -mode. - -ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port -is put to the coprocessor mode using ioctl(SNDCTL_MIDI_MPUMODE). It's used to -send commands to a MPU-401 compatible MIDI cards. Please refer to the -MPU-401 Technical Reference Manual (or Music Quest Technical Reference -Manual) for descriptions of the commands. - -The argument of SNDCTL_MIDI_MPUCOMMAND is of type mpu_command_rec. It -has the following fields: - -typedef struct { - unsigned char cmd; - - char nr_args, nr_returns; - unsigned char data[30]; - } mpu_command_rec; - -where: - cmd Contains the command number. - nr_args Number of arguments of the command. - MUST BE INITIALIZED BEFORE CALL - nr_returns Number of bytes returned by the command. - MUST BE INITIALIZED BEFORE CALL - data Buffer for the command arguments and returned - data. - -Be extremely careful with the nr_args and nr_returns fields. They -must match the command. An incorrect value will put the card and -the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further -details. - - - -/dev/music (/dev/sequencer2) ----------------------------- - -This device file works much like the /dev/sequencer which has been present -since the beginning. The main differences are the following: - -- /dev/sequencer makes the MIDI ports to look like the synth devices. In fact -the result is somewhere between the MIDI specification and the synth devices of -/dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE() -like macros. The voice number parameters of the API macros have been redefined -to denote MIDI channels. This means that the driver allocates voices for -the channels automatically (this is a responsibility/right of an application -with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has -similar effects for a synth channel than on a MIDI port. This kind of -solution provides better device independence than the /dev/sequencer. The -drawback is that the new interface doesn't permit so low level access to the -device as the /dev/sequencer does. An application developer must choose between -these two interfaces. I think the old /dev/sequencer is better for applications -like module players while the new one is better for making generic sequencer -programs. - -- There are no separate MIDI devices with the /dev/sequencer2. The -ioctl(SNDCTL_SEQ_NRMIDIS) returns always zero. Instead the MIDI ports are -shown as synth devices. ioctl(SNDCTL_SEQ_NRSYNTHS) on /dev/sequencer2 will -return sum of internal synthesizers (GUS, OPL3) and MIDI ports in the systems. - -- The new interface is used much like the ordinary /dev/sequencer. The -event format is new so you have to use the API macros defined in the -sys/soundcard.h. The interface is will probably change before the final 3.0 -release but using the API macros should ensure compatibility in source level. -The new event format is not recognized by version 2.X so don't try to -distribute binaries compiled with soundcard.h of v3.X. - -- The basic API usage is similar to the current one. There are some new -macros but the older ones should work as earlier. The most important -incompatibility is that the /dev/sequencer2 driver allocates voices itself. -The other one is that the application must send SEQ_START_TIMER() as its -first event. Otherwise the timer is not started and the application waits -infinitely. - - -There are several new features but I don't document them here. There are -some info in the soundcard.h (near the end). I have also included some -sample code in the directory v30. Full documentation will -appear in the Hacker's Guide later. - -Don't hesitate to contact me in case you have questions or comments. - -Hannu Savolainen -hannu@voxware.pp.fi diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 92a71fcdf76d..82ec86f037c0 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -71,6 +71,7 @@ typedef struct int irq_ok; mixer_ents *mix_devices; int mixer_output_port; + int c930_password_port; } ad1848_info; @@ -107,7 +108,7 @@ static int ad_format_mask[8 /*devc->model */ ] = AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM }; -static ad1848_info dev_info[MAX_AUDIO_DEV]; +static ad1848_info adev_info[MAX_AUDIO_DEV]; #define io_Index_Addr(d) ((d)->base) #define io_Indexed_Data(d) ((d)->base+1) @@ -200,7 +201,6 @@ wait_for_calibration (ad1848_info * devc) if (ad_read (devc, 11) & 0x20) if (devc->model != MD_1845) printk ("ad1848: Auto calibration timed out(3).\n"); - ad_write (devc, 9, ad_read (devc, 9) & ~0x18); /* Disable autocalibration */ } static void @@ -215,7 +215,6 @@ ad_mute (ad1848_info * devc) for (i = 6; i < 8; i++) { prev = devc->saved_regs[i] = ad_read (devc, i); - ad_write (devc, i, prev | 0x80); } } @@ -223,21 +222,6 @@ ad_mute (ad1848_info * devc) static void ad_unmute (ad1848_info * devc) { - int i, dummy; - -/* - * Let's have some delay - */ - for (i = 0; i < 1000; i++) - dummy = inb (devc->base); - - /* - * Restore back old volume registers (unmute) - */ - for (i = 6; i < 8; i++) - { - ad_write (devc, i, devc->saved_regs[i] & ~0x80); - } } static void @@ -296,7 +280,6 @@ ad_leave_MCE (ad1848_info * devc) restore_flags (flags); } - static int ad1848_set_recmask (ad1848_info * devc, int mask) { @@ -381,16 +364,32 @@ change_bits (ad1848_info * devc, unsigned char *regval, int dev, int chn, int ne { unsigned char mask; int shift; + int mute; + int mutemask; + int set_mute_bit; + + set_mute_bit = (newval == 0); if (devc->mix_devices[dev][chn].polarity == 1) /* Reverse */ newval = 100 - newval; mask = (1 << devc->mix_devices[dev][chn].nbits) - 1; shift = devc->mix_devices[dev][chn].bitpos; - newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ - *regval &= ~(mask << shift); /* Clear bits */ - *regval |= (newval & mask) << shift; /* Set new value */ + if (devc->mix_devices[dev][chn].mutepos == 8) + { /* if there is no mute bit */ + mute = 0; /* No mute bit; do nothing special */ + mutemask = ~0; /* No mute bit; do nothing special */ + } + else + { + mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); + mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); + } + + newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ + *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ + *regval |= ((newval & mask) << shift) | mute; /* Set new value */ } static int @@ -969,13 +968,12 @@ ad1848_start_input (int dev, unsigned long buf, int count, int intrflag) save_flags (flags); cli (); - if (devc->model == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */ + if (devc->model == MD_1848) { ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); } else - /* Dual DMA channel mode */ { ad_write (devc, 31, (unsigned char) (cnt & 0xff)); ad_write (devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); @@ -1007,6 +1005,8 @@ ad1848_prepare_for_output (int dev, int bsize, int bcount) if (portc->channels > 1) fs |= 0x10; + ad_enter_MCE (devc); /* Enables changes to the format select reg */ + if (devc->model == MD_1845) /* Use alternate speed select registers */ { fs &= 0xf0; /* Mask off the rate select bits */ @@ -1017,14 +1017,15 @@ ad1848_prepare_for_output (int dev, int bsize, int bcount) old_fs = ad_read (devc, 8); - ad_enter_MCE (devc); /* Enables changes to the format select reg */ - if (devc->model == MD_4232) { tmp = ad_read (devc, 16); ad_write (devc, 16, tmp | 0x30); } + if (devc->model == MD_IWAVE) + ad_write (devc, 17, 0xc2); /* Disable variable frequency select */ + ad_write (devc, 8, fs); /* * Write to I8 starts resynchronization. Wait until it completes. @@ -1075,6 +1076,8 @@ ad1848_prepare_for_input (int dev, int bsize, int bcount) if (portc->channels > 1) fs |= 0x10; + ad_enter_MCE (devc); /* Enables changes to the format select reg */ + if (devc->model == MD_1845) /* Use alternate speed select registers */ { fs &= 0xf0; /* Mask off the rate select bits */ @@ -1083,32 +1086,21 @@ ad1848_prepare_for_input (int dev, int bsize, int bcount) ad_write (devc, 23, portc->speed & 0xff); /* Speed LSB */ } - old_fs = ad_read (devc, 8); - - ad_enter_MCE (devc); /* Enables changes to the format select reg */ - if (devc->model == MD_4232) { tmp = ad_read (devc, 16); ad_write (devc, 16, tmp | 0x30); } - ad_write (devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb (devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb (devc->base) == 0x80) - timeout++; + if (devc->model == MD_IWAVE) + ad_write (devc, 17, 0xc2); /* Disable variable frequency select */ /* - * If mode >= 2 (CS4231), set I28 also. It's the capture format register. + * If mode >= 2 (CS4231), set I28. It's the capture format register. */ if (devc->model != MD_1848) { + old_fs = ad_read (devc, 28); ad_write (devc, 28, fs); /* @@ -1121,6 +1113,43 @@ ad1848_prepare_for_input (int dev, int bsize, int bcount) timeout = 0; while (timeout < 10000 && inb (devc->base) == 0x80) timeout++; + + if (devc->model != MD_1848 && devc->model != MD_1845) + { + /* + * CS4231 compatible devices don't have separate sampling rate selection + * register for recording an playback. The I8 register is shared so we have to + * set the speed encoding bits of it too. + */ + unsigned char tmp = portc->speed_bits | (ad_read (devc, 8) & 0xf0); + + ad_write (devc, 8, tmp); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb (devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb (devc->base) == 0x80) + timeout++; + } + } + else + { /* For AD1848 set I8. */ + + old_fs = ad_read (devc, 8); + ad_write (devc, 8, fs); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb (devc->base) != 0x80) + timeout++; + timeout = 0; + while (timeout < 10000 && inb (devc->base) == 0x80) + timeout++; } if (devc->model == MD_4232) @@ -1176,14 +1205,14 @@ ad1848_halt_input (int dev) { int tmout; - disable_dma (audio_devs[dev]->dmap_out->dma); + disable_dma (audio_devs[dev]->dmap_in->dma); for (tmout = 0; tmout < 100000; tmout++) if (ad_read (devc, 11) & 0x10) break; ad_write (devc, 9, ad_read (devc, 9) & ~0x02); /* Stop capture */ - enable_dma (audio_devs[dev]->dmap_out->dma); + enable_dma (audio_devs[dev]->dmap_in->dma); devc->audio_mode &= ~PCM_ENABLE_INPUT; } @@ -1306,6 +1335,9 @@ ad1848_init_hw (ad1848_info * devc) for (i = 16; i < 32; i++) ad_write (devc, i, init_values[i]); + if (devc->model == MD_IWAVE) + ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */ + } if (devc->model > MD_1848) @@ -1321,6 +1353,7 @@ ad1848_init_hw (ad1848_info * devc) if (devc->model == MD_IWAVE) { /* Some magic Interwave specific initialization */ ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + ad_write (devc, 16, 0x30); /* Playback and capture counters enabled */ ad_write (devc, 17, 0xc2); /* Alternate feature enable */ } } @@ -1347,11 +1380,12 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) { unsigned char tmp; - ad1848_info *devc = &dev_info[nr_ad1848_devs]; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; unsigned char tmp1 = 0xff, tmp2 = 0xff; int optiC930 = 0; /* OPTi 82C930 flag */ int interwave = 0; int ad1847_flag = 0; + int cs4248_flag = 0; int i; @@ -1364,16 +1398,22 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) interwave = 1; *ad_flags = 0; } + + if (*ad_flags == 0x12345677) + { + cs4248_flag = 1; + *ad_flags = 0; + } } if (nr_ad1848_devs >= MAX_AUDIO_DEV) { - DDB (printk ("ad1848 detect error - step 0\n")); + printk ("ad1848 - Too many audio devices\n"); return 0; } if (check_region (io_base, 4)) { - printk ("\n\nad1848.c: Port %x not free.\n\n", io_base); + printk ("ad1848.c: Port %x not free.\n", io_base); return 0; } @@ -1386,6 +1426,7 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) devc->chip_name = "AD1848"; devc->model = MD_1848; /* AD1848 or CS4248 */ devc->levels = NULL; + devc->c930_password_port = 0; devc->debug_flag = 0; /* @@ -1413,6 +1454,9 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) DDB (printk ("ad1848_detect() - step A\n")); + if (inb (devc->base) == 0x80) /* Not ready. Let's wait */ + ad_leave_MCE (devc); + if ((inb (devc->base) & 0x80) != 0x00) /* Not a AD1848 */ { DDB (printk ("ad1848 detect error - step A (%02x)\n", @@ -1420,11 +1464,6 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) return 0; } - DDB (printk ("ad1848: regs: ")); - for (i = 0; i < 32; i++) - DDB (printk ("%02x ", ad_read (devc, i))); - DDB (printk ("\n")); - /* * Test if it's possible to change contents of the indirect registers. * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only @@ -1480,6 +1519,8 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) /* * The original AD1848/CS4248 has just 15 indirect registers. This means * that I0 and I16 should return the same value (etc.). + * However this doesn't work with CS4248. Actually it seems to be impossible + * to detect if the chip is a CS4231 or CS4248. * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails * with CS4231. */ @@ -1513,6 +1554,7 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) else ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ + if (ad_flags) *ad_flags = 0; @@ -1630,6 +1672,15 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) devc->chip_name = "AD1845"; devc->model = MD_1845; } + else if (cs4248_flag) + { + if (ad_flags) + *ad_flags |= AD_F_CS4248; + + devc->chip_name = "CS4248"; + devc->model = MD_1848; + ad_write (devc, 12, ad_read (devc, 12) & ~0x40); /* Mode2 off */ + } ad_write (devc, 23, tmp); /* Restore */ } @@ -1686,7 +1737,7 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture int my_dev; char dev_name[100]; - ad1848_info *devc = &dev_info[nr_ad1848_devs]; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; ad1848_port_info *portc = NULL; @@ -1749,7 +1800,7 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture if (irq > 0) { irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler (devc->irq, ad1848_interrupt, + if (snd_set_irq_handler (devc->irq, adintr, "SoundPort", NULL) < 0) { @@ -1819,7 +1870,7 @@ ad1848_control (int cmd, int arg) if (nr_ad1848_devs < 1) return; - devc = &dev_info[nr_ad1848_devs - 1]; + devc = &adev_info[nr_ad1848_devs - 1]; switch (cmd) { @@ -1871,9 +1922,9 @@ ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int shar ad1848_info *devc = NULL; for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) - if (dev_info[i].base == io_base) + if (adev_info[i].base == io_base) { - devc = &dev_info[i]; + devc = &adev_info[i]; dev = devc->dev_no; } @@ -1898,7 +1949,7 @@ ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int shar } void -ad1848_interrupt (int irq, void *dev_id, struct pt_regs *dummy) +adintr (int irq, void *dev_id, struct pt_regs *dummy) { unsigned char status; ad1848_info *devc; @@ -1937,7 +1988,7 @@ interrupt_again: /* Jump back here if int status doesn't reset */ status = inb (io_Status (devc)); if (status == 0x80) - printk ("ad1848_interrupt: Why?\n"); + printk ("adintr: Why?\n"); if (devc->model == MD_1848) outb ((0), io_Status (devc)); /* Clear interrupt status */ @@ -1952,6 +2003,8 @@ interrupt_again: /* Jump back here if int status doesn't reset */ alt_stat = 0; + if (devc->c930_password_port) + outb ((0xe4), devc->c930_password_port); /* Password */ outb ((11), 0xe0e); c930_stat = inb (0xe0f); @@ -1972,6 +2025,8 @@ interrupt_again: /* Jump back here if int status doesn't reset */ save_flags (flags); cli (); + if (devc->c930_password_port) + outb ((0xe4), devc->c930_password_port); /* Password */ outb ((11), 0xe0e); outb ((~c930_stat), 0xe0f); restore_flags (flags); @@ -2319,7 +2374,6 @@ attach_ms_sound (struct address_info *hw_config) -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 }; char bits, dma2_bit = 0; - int ad_flags = 0; static char dma_bits[4] = { @@ -2347,7 +2401,10 @@ attach_ms_sound (struct address_info *hw_config) bits = interrupt_bits[hw_config->irq]; if (bits == -1) - return; + { + printk ("MSS: Bad IRQ %d\n", hw_config->irq); + return; + } outb ((bits | 0x40), config_port); if ((inb (version_port) & 0x40) == 0) @@ -2357,7 +2414,7 @@ attach_ms_sound (struct address_info *hw_config) * Handle the capture DMA channel */ - if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) + if (dma2 != -1 && dma2 != dma) { if (!((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || @@ -2382,7 +2439,12 @@ attach_ms_sound (struct address_info *hw_config) } } else - dma2 = dma; + { + dma2 = dma; + } + + hw_config->dma = dma; + hw_config->dma2 = dma2; outb ((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */ diff --git a/drivers/sound/ad1848_mixer.h b/drivers/sound/ad1848_mixer.h index 8267aed08ca0..f6ea1c006ca3 100644 --- a/drivers/sound/ad1848_mixer.h +++ b/drivers/sound/ad1848_mixer.h @@ -48,10 +48,11 @@ SOUND_MASK_IGAIN | SOUND_MASK_PCM) struct mixer_def { - unsigned int regno: 7; + unsigned int regno: 5; unsigned int polarity:1; /* 0=normal, 1=reversed */ - unsigned int bitpos:4; - unsigned int nbits:4; + unsigned int bitpos:3; + unsigned int nbits:3; + unsigned int mutepos:4; }; static char mix_cvt[101] = { @@ -75,47 +76,47 @@ typedef mixer_ent mixer_ents[2]; * The current version doesn't try to compensate this. */ -#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \ - {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}} +#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r, mute_bit) \ + {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r, mute_bit}} static mixer_ents ad1848_mix_devices[32] = { -MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4), -MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), -MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), -MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5), -MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5), -MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), -MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5), -MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5), -MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) +MIX_ENT(SOUND_MIXER_VOLUME, 27, 1, 0, 4, 29, 1, 0, 4, 8), +MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), +MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) }; static mixer_ents iwave_mix_devices[32] = { -MIX_ENT(SOUND_MIXER_VOLUME, 25, 1, 0, 5, 27, 1, 0, 5), -MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), -MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), -MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5), -MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5), -MIX_ENT(SOUND_MIXER_IMIX, 16, 1, 0, 5, 17, 1, 0, 5), -MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), -MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5), -MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5), -MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) +MIX_ENT(SOUND_MIXER_VOLUME, 25, 1, 0, 5, 27, 1, 0, 5, 8), +MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), +MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1, 8), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_IMIX, 16, 1, 0, 5, 17, 1, 0, 5, 8), +MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5, 7) }; /* OPTi 82C930 has somewhat different port addresses. @@ -124,23 +125,23 @@ MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) * MIC is level of mic monitoring direct to output. Same for CD, LINE, etc. */ static mixer_ents c930_mix_devices[32] = { -MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 0, 5, 23, 1, 0, 5), -MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), -MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), -MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 0, 5, 23, 1, 0, 5), -MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4), -MIX_ENT(SOUND_MIXER_MIC, 20, 1, 0, 4, 21, 1, 0, 4), -MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4), -MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), -MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), -MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4), -MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4), -MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4) +MIX_ENT(SOUND_MIXER_VOLUME, 22, 1, 0, 5, 23, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5, 7), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6, 7), +MIX_ENT(SOUND_MIXER_SPEAKER, 22, 1, 0, 5, 23, 1, 0, 5, 8), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 1, 4, 19, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_MIC, 20, 1, 0, 4, 21, 1, 0, 4, 8), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 1, 4, 3, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4, 8), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0, 8), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 1, 4, 3, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 1, 4, 5, 1, 1, 4, 7), +MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 1, 4, 19, 1, 1, 4, 7) }; static int default_mixer_levels[32] = @@ -155,12 +156,12 @@ static int default_mixer_levels[32] = 0x1010, /* Mic */ 0x4b4b, /* CD */ 0x0000, /* Recording monitor */ - 0x4b4b, /* SB PCM */ + 0x4b4b, /* Second PCM */ 0x4b4b, /* Recording level */ 0x4b4b, /* Input gain */ 0x4b4b, /* Output gain */ - 0x4040, /* Line1 */ - 0x4040, /* Line2 */ + 0x2020, /* Line1 */ + 0x2020, /* Line2 */ 0x1515 /* Line3 (usually line in)*/ }; diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index 0ce7c0a9ddf1..d1ba581b1574 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -21,9 +21,6 @@ #include "ulaw.h" #include "coproc.h" -#define ON 1 -#define OFF 0 - #define NEUTRAL8 0x80 #define NEUTRAL16 0x00 @@ -31,11 +28,12 @@ static int audio_mode[MAX_AUDIO_DEV]; static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */ #define AM_NONE 0 -#define AM_WRITE 1 -#define AM_READ 2 +#define AM_WRITE OPEN_WRITE +#define AM_READ OPEN_READ +static int dma_ioctl (int dev, unsigned int cmd, caddr_t arg); -static int audio_format[MAX_AUDIO_DEV]; +static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV]; static int local_conversion[MAX_AUDIO_DEV]; #define CNV_MU_LAW 0x00000001 @@ -44,7 +42,6 @@ set_format (int dev, int fmt) { if (fmt != AFMT_QUERY) { - local_conversion[dev] = 0; if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ @@ -57,10 +54,10 @@ set_format (int dev, int fmt) fmt = AFMT_U8; /* This is always supported */ audio_format[dev] = audio_devs[dev]->d->set_bits (dev, fmt); + local_format[dev] = fmt; } - - if (local_conversion[dev]) /* This shadows the HW format */ - return local_conversion[dev]; + else + return local_format[dev]; return audio_format[dev]; } @@ -98,7 +95,6 @@ audio_open (int dev, struct fileinfo *file) local_conversion[dev] = 0; - if (dev_type == SND_DEV_AUDIO) { set_format (dev, AFMT_MU_LAW); @@ -127,19 +123,12 @@ sync_output (int dev) /* Align the write pointer with fragment boundaries */ if ((l = dmap->user_counter % dmap->fragment_size) > 0) { - char *ptr; - int err, dummylen, len = dmap->fragment_size - l; + int len; + unsigned long offs = dmap->user_counter % dmap->bytes_in_use; - if ((err = DMAbuf_getwrbuffer (dev, &ptr, &dummylen, 1)) >= 0) - if (dummylen >= len && ((long) ptr % dmap->fragment_size) == l) - { - if ((ptr + len) > (dmap->raw_buf + audio_devs[dev]->buffsize)) - printk ("audio: Buffer error 1\n"); - if (ptr < dmap->raw_buf) - printk ("audio: Buffer error 11\n"); - memset (ptr, dmap->neutral_byte, len); - DMAbuf_move_wrpointer (dev, len); - } + len = dmap->fragment_size - l; + memset (dmap->raw_buf + offs, dmap->neutral_byte, len); + DMAbuf_move_wrpointer (dev, len); } /* @@ -153,7 +142,7 @@ sync_output (int dev) { p = (p + 1) % dmap->nbufs; if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > - (dmap->raw_buf + audio_devs[dev]->buffsize)) + (dmap->raw_buf + dmap->buffsize)) printk ("audio: Buffer error 2\n"); memset (dmap->raw_buf + p * dmap->fragment_size, @@ -241,7 +230,7 @@ audio_write (int dev, struct fileinfo *file, const char *buf, int count) while (c) { - if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev]) < 0)) + if ((err = DMAbuf_getwrbuffer (dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) { /* Handle nonblocking mode */ if (dev_nblock[dev] && err == -EAGAIN) @@ -250,17 +239,18 @@ audio_write (int dev, struct fileinfo *file, const char *buf, int count) } l = c; + if (l > buf_size) l = buf_size; if (!audio_devs[dev]->d->copy_user) { if ((dma_buf + l) > - (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->buffsize)) + (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) printk ("audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, - (int) audio_devs[dev]->buffsize); + (int) audio_devs[dev]->dmap_out->buffsize); if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) printk ("audio: Buffer error 13\n"); copy_from_user (dma_buf, &(buf)[p], l); @@ -541,46 +531,10 @@ void audio_init_devices (void) { /* - * NOTE! This routine could be called several times during boot. + * NOTE! This routine could be called several times during boot. */ } -int -audio_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) -{ - dev = dev >> 4; - - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - if (audio_mode[dev] & AM_WRITE && !(audio_devs[dev]->flags & DMA_DUPLEX)) - { - return 0; /* Not recording */ - } - - return DMAbuf_select (dev, file, sel_type, wait); - break; - - case SEL_OUT: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - if (audio_mode[dev] & AM_READ && !(audio_devs[dev]->flags & DMA_DUPLEX)) - { - return 0; /* Wrong direction */ - } - - return DMAbuf_select (dev, file, sel_type, wait); - break; - - case SEL_EX: - return 0; - } - - return 0; -} - #endif @@ -632,11 +586,11 @@ reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) * of sound (using the current speed, sample size and #channels). */ - bsz = dsp_dev->buffsize; + bsz = dmap->buffsize; while (bsz > sz) bsz /= 2; - if (bsz == dsp_dev->buffsize) + if (bsz == dmap->buffsize) bsz /= 2; /* Needs at least 2 buffers */ /* @@ -668,17 +622,23 @@ reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or * the buffer size computation has already been done. */ - if (dmap->fragment_size > (audio_devs[dev]->buffsize / 2)) - dmap->fragment_size = (audio_devs[dev]->buffsize / 2); + if (dmap->fragment_size > (dmap->buffsize / 2)) + dmap->fragment_size = (dmap->buffsize / 2); bsz = dmap->fragment_size; } - bsz &= ~0x03; /* Force size which is multiple of 4 bytes */ + if (audio_devs[dev]->min_fragment) + if (bsz < (1 << audio_devs[dev]->min_fragment)) + bsz = 1 << audio_devs[dev]->min_fragment; + if (audio_devs[dev]->max_fragment) + if (bsz > (1 << audio_devs[dev]->max_fragment)) + bsz = 1 << audio_devs[dev]->max_fragment; + bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ #ifdef OS_DMA_ALIGN_CHECK OS_DMA_ALIGN_CHECK (bsz); #endif - n = dsp_dev->buffsize / bsz; + n = dmap->buffsize / bsz; if (n > MAX_SUB_BUFFERS) n = MAX_SUB_BUFFERS; if (n > dmap->max_fragments) @@ -693,6 +653,8 @@ reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) dmap->nbufs = n; dmap->bytes_in_use = n * bsz; dmap->fragment_size = bsz; + dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + + dmap->bytes_in_use; /* Approximately one hour */ if (dmap->raw_buf) { @@ -751,6 +713,8 @@ dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) if (count == 0) count = MAX_SUB_BUFFERS; + else if (count < MAX_SUB_BUFFERS) + count++; if (bytes < 4 || bytes > 17) /* <16 || > 512k */ return -EINVAL; @@ -762,6 +726,10 @@ dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) if (bytes < audio_devs[dev]->min_fragment) bytes = audio_devs[dev]->min_fragment; + if (audio_devs[dev]->max_fragment > 0) + if (bytes > audio_devs[dev]->max_fragment) + bytes = audio_devs[dev]->max_fragment; + #ifdef OS_DMA_MINBITS if (bytes < OS_DMA_MINBITS) bytes = OS_DMA_MINBITS; @@ -770,16 +738,16 @@ dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact) dmap->fragment_size = (1 << bytes); dmap->max_fragments = count; - if (dmap->fragment_size > audio_devs[dev]->buffsize) - dmap->fragment_size = audio_devs[dev]->buffsize; + if (dmap->fragment_size > dmap->buffsize) + dmap->fragment_size = dmap->buffsize; - if (dmap->fragment_size == audio_devs[dev]->buffsize && + if (dmap->fragment_size == dmap->buffsize && audio_devs[dev]->flags & DMA_AUTOMODE) dmap->fragment_size /= 2; /* Needs at least 2 buffers */ dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ if (arg) - return (*(int *) arg = bytes | (count << 16)); + return (*(int *) arg = bytes | ((count - 1) << 16)); else return 0; } @@ -797,16 +765,18 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) case SNDCTL_DSP_SUBDIVIDE: { int fact; - int ret; + int ret = 0; fact = *(int *) arg; - ret = dma_subdivide (dev, dmap_out, arg, fact); + if (audio_devs[dev]->open_mode & OPEN_WRITE) + ret = dma_subdivide (dev, dmap_out, arg, fact); if (ret < 0) return ret; - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ) + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) ret = dma_subdivide (dev, dmap_in, arg, fact); return ret; @@ -824,6 +794,10 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) !(audio_devs[dev]->open_mode & OPEN_READ)) return -EINVAL; + if (cmd == SNDCTL_DSP_GETOSPACE && + !(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) dmap = dmap_in; @@ -843,14 +817,14 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) info->fragments = 0; else { - info->fragments = dmap->nbufs - dmap->qlen; + info->fragments = DMAbuf_space_in_queue (dev); if (audio_devs[dev]->d->local_qlen) { int tmp = audio_devs[dev]->d->local_qlen (dev); if (tmp && info->fragments) tmp--; /* - * This buffer has been counted twice + * This buffer has been counted twice */ info->fragments -= tmp; } @@ -904,6 +878,7 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) dmap_in->fragment_size, dmap_in->nbufs)) < 0) return -err; + dmap_in->dma_mode = DMODE_INPUT; audio_devs[dev]->enable_bits = bits; DMAbuf_activate_recording (dev, dmap_in); } @@ -919,7 +894,9 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) reorganize_buffers (dev, dmap_out, 0); } + dmap_out->dma_mode = DMODE_OUTPUT; ; + audio_devs[dev]->enable_bits = bits; dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; DMAbuf_launch_output (dev, dmap_out); ; @@ -950,20 +927,24 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) { count_info info; unsigned long flags; + struct dma_buffparms *dmap = dmap_in; if (!(audio_devs[dev]->open_mode & OPEN_READ)) return -EINVAL; save_flags (flags); cli (); - info.bytes = audio_devs[dev]->dmap_in->byte_counter; - info.ptr = DMAbuf_get_buffer_pointer (dev, audio_devs[dev]->dmap_in) & ~3; - info.blocks = audio_devs[dev]->dmap_in->qlen; + info.bytes = dmap->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_INPUT) & ~3; + if (info.ptr < dmap->fragment_size && dmap->qtail != 0) + info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + + info.blocks = dmap->qlen; info.bytes += info.ptr; memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - audio_devs[dev]->dmap_in->qlen = 0; /* Reset interrupt counter */ + if (dmap->mapping_flags & DMA_MAP_MAPPED) + dmap->qlen = 0; /* Reset interrupt counter */ restore_flags (flags); return 0; } @@ -973,20 +954,23 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) { count_info info; unsigned long flags; + struct dma_buffparms *dmap = dmap_out; if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) return -EINVAL; save_flags (flags); cli (); - info.bytes = audio_devs[dev]->dmap_out->byte_counter; - info.ptr = DMAbuf_get_buffer_pointer (dev, audio_devs[dev]->dmap_out) & ~3; - info.blocks = audio_devs[dev]->dmap_out->qlen; + info.bytes = dmap->byte_counter; + info.ptr = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT) & ~3; + if (info.ptr < dmap->fragment_size && dmap->qhead != 0) + info.bytes += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + info.blocks = dmap->qlen; info.bytes += info.ptr; memcpy ((&((char *) arg)[0]), (char *) &info, sizeof (info)); - if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) - audio_devs[dev]->dmap_out->qlen = 0; /* Reset interrupt counter */ + if (dmap->mapping_flags & DMA_MAP_MAPPED) + dmap->qlen = 0; /* Reset interrupt counter */ restore_flags (flags); return 0; @@ -1004,18 +988,23 @@ dma_ioctl (int dev, unsigned int cmd, caddr_t arg) break; case SNDCTL_DSP_GETBLKSIZE: - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - { - if (audio_devs[dev]->open_mode & OPEN_WRITE) - reorganize_buffers (dev, dmap_out, - (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ) - reorganize_buffers (dev, dmap_in, - (audio_devs[dev]->open_mode == OPEN_READ)); - } + { + int fragment_size; + struct dma_buffparms *dmap = dmap_out; - return (*(int *) arg = dmap_out->fragment_size); + if (audio_devs[dev]->open_mode & OPEN_WRITE) + reorganize_buffers (dev, dmap_out, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + reorganize_buffers (dev, dmap_in, + (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode == OPEN_READ) + dmap = dmap_in; + fragment_size = dmap->fragment_size; + return (*(int *) arg = fragment_size); + } break; case SNDCTL_DSP_SETFRAGMENT: diff --git a/drivers/sound/configure.c b/drivers/sound/configure.c index f5d2a834437e..ee6830b2ad1d 100644 --- a/drivers/sound/configure.c +++ b/drivers/sound/configure.c @@ -145,7 +145,7 @@ hw_entry hw_table[] = char *questions[] = { "ProAudioSpectrum 16 support", - "_TRUE_ Sound Blaster (SB, SBPro, SB16/32/64, ESS, Jazz16) support", + "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support", "Generic OPL2/OPL3 FM synthesizer support", "Gravis Ultrasound support", "MPU-401 support (NOT for SB16)", diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 7f24da62aa17..10daa50ad352 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -15,6 +15,7 @@ #define _DEV_TABLE_C_ #include "sound_config.h" +int sb_be_quiet = 0; int sound_started = 0; @@ -43,20 +44,15 @@ start_services (void) #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { - DMAbuf_init (); + int dev; + + for (dev = 0; dev < num_audiodevs; dev++) + { + } audio_init_devices (); } #endif -#ifdef CONFIG_MIDI - if (num_midis) - MIDIbuf_init (); -#endif - -#ifdef CONFIG_SEQUENCER - if (num_midis + num_synths) - sequencer_init (); -#endif return; } @@ -493,17 +489,11 @@ sound_install_audiodrv (int vers, /* * Hardcoded defaults */ - op->buffsize = DSP_BUFFSIZE; - audio_devs[num_audiodevs] = op; num = num_audiodevs++; - DMAbuf_init (); - - op->dmap_out->dma = dma1; - op->dmap_in->dma = dma2; + DMAbuf_init (num, dma1, dma2); - DMAbuf_init (); audio_init_devices (); return num; #else diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index cef6dc113f25..7013c3c8df3d 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -70,6 +70,7 @@ struct dma_buffparms { char *raw_buf; unsigned long raw_buf_phys; + int buffsize; /* * Device state tables @@ -85,6 +86,8 @@ struct dma_buffparms { #define DMA_SYNCING 0x00000040 #define DMA_DIRTY 0x00000080 #define DMA_POST 0x00000100 +#define DMA_NODMA 0x00000200 +#define DMA_NOTIMEOUT 0x00000400 int open_mode; @@ -109,6 +112,7 @@ struct dma_buffparms { int underrun_count; unsigned long byte_counter; unsigned long user_counter; + unsigned long max_byte_counter; int data_rate; /* Bytes/second */ int mapping_flags; @@ -120,6 +124,9 @@ struct dma_buffparms { OS_DMA_PARMS #endif int applic_profile; /* Application profile (APF_*) */ + int buf_flags[MAX_SUB_BUFFERS]; +#define BUFF_EOF 0x00000001 /* Increment eof count */ +#define BUFF_DIRTY 0x00000002 /* Buffer written */ }; /* @@ -156,6 +163,8 @@ struct audio_driver { int (*set_speed)(int dev, int speed); unsigned int (*set_bits)(int dev, unsigned int bits); short (*set_channels)(int dev, short channels); + void (*postprocess_write)(int dev); /* Device spesific postprocessing for written data */ + void (*preprocess_read)(int dev); /* Device spesific preprocessing for read data */ }; struct audio_operations { @@ -167,13 +176,12 @@ struct audio_operations { #define DMA_DUPLEX 0x04 #define DMA_PSEUDO_AUTOMODE 0x08 #define DMA_HARDSTOP 0x10 -#define DMA_NODMA 0x20 #define DMA_EXACT 0x40 +#define DMA_NORESET 0x80 int format_mask; /* Bitmask for supported audio formats */ void *devc; /* Driver specific info */ struct audio_driver *d; void *portc; /* Driver spesific info */ - long buffsize; struct dma_buffparms *dmap_in, *dmap_out; struct coproc_operations *coproc; int mixer_dev; @@ -181,6 +189,7 @@ struct audio_operations { int open_mode; int go; int min_fragment; /* 0 == unlimited */ + int max_fragment; /* 0 == unlimited */ int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ }; @@ -292,7 +301,7 @@ struct sound_timer_operations { struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) && !defined(VMIDI) extern struct sound_timer_operations default_sound_timer; struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {&default_sound_timer, NULL}; @@ -313,6 +322,15 @@ struct sound_timer_operations { {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif + +#ifdef CONFIG_GUS16 + {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, +#endif +#ifdef CONFIG_GUSHW + {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, + {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, +#endif + #ifdef CONFIG_MSS {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* Compaq Deskpro XL */ @@ -358,15 +376,6 @@ struct sound_timer_operations { # endif #endif - - -#ifdef CONFIG_GUS16 - {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, -#endif -#ifdef CONFIG_GUSHW - {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, - {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, -#endif #ifdef CONFIG_SSCAPEHW {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, @@ -377,6 +386,10 @@ struct sound_timer_operations { {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif + + + + {NULL, 0, 0, "*?*", NULL, NULL, NULL} }; @@ -439,6 +452,10 @@ struct sound_timer_operations { #ifdef CONFIG_MSS +# ifndef MSS_DMA2 +# define MSS_DMA2 -1 +# endif + # ifdef DESKPROXL {SNDCARD_DESKPROXL, {MSS_BASE, MSS_IRQ, MSS_DMA, MSS_DMA2}, SND_DEFAULT_ENABLE}, # else diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 6be1cfe643a8..38b7af597502 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -12,7 +12,7 @@ */ #include -#undef BE_CONSERVATIVE +#define BE_CONSERVATIVE #include "sound_config.h" @@ -44,18 +44,11 @@ static int local_start_dma (int dev, unsigned long physaddr, int count, int static void dma_init_buffers (int dev, struct dma_buffparms *dmap) { - if (dmap == audio_devs[dev]->dmap_out) - { - out_sleep_flag[dev].opts = WK_NONE; - } - else - { - in_sleep_flag[dev].opts = WK_NONE; - } dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; dmap->byte_counter = 0; - dmap->bytes_in_use = audio_devs[dev]->buffsize; + dmap->max_byte_counter = 8000 * 60 * 60; + dmap->bytes_in_use = dmap->buffsize; dmap->dma_mode = DMODE_NONE; dmap->mapping_flags = 0; @@ -92,16 +85,25 @@ open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) return -EBUSY; } + dma_init_buffers (dev, dmap); dmap->open_mode = mode; dmap->subdivision = dmap->underrun_count = 0; dmap->fragment_size = 0; dmap->max_fragments = 65536; /* Just a large value */ dmap->byte_counter = 0; + dmap->max_byte_counter = 8000 * 60 * 60; dmap->applic_profile = APF_NORMAL; dmap->needs_reorg = 1; - dma_init_buffers (dev, dmap); + if (dmap->dma_mode & DMODE_OUTPUT) + { + out_sleep_flag[dev].opts = WK_NONE; + } + else + { + in_sleep_flag[dev].opts = WK_NONE; + } return 0; } @@ -224,6 +226,13 @@ DMAbuf_open (int dev, int mode) audio_devs[dev]->d->set_channels (dev, 1); audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + { + memset (audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + } + return 0; } @@ -335,7 +344,12 @@ dma_reset_input (int dev) void DMAbuf_launch_output (int dev, struct dma_buffparms *dmap) { - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE)) + if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) + return; /* Don't start DMA yet */ + + dmap->dma_mode = DMODE_OUTPUT; + + if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { if (!(dmap->flags & DMA_STARTED)) { @@ -345,12 +359,17 @@ DMAbuf_launch_output (int dev, struct dma_buffparms *dmap) dmap->fragment_size, dmap->nbufs)) return; - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_WRITE); + if (!(dmap->flags & DMA_NODMA)) + { + local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, + DMA_MODE_WRITE); + } + dmap->flags |= DMA_STARTED; } if (dmap->counts[dmap->qhead] == 0) dmap->counts[dmap->qhead] = dmap->fragment_size; + dmap->dma_mode = DMODE_OUTPUT; audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, dmap->counts[dmap->qhead], 1); @@ -560,7 +579,7 @@ int DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { unsigned long flags; - int err = EIO; + int err = 0, n = 0; struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; if (!(audio_devs[dev]->open_mode & OPEN_READ)) @@ -575,77 +594,82 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) printk ("Sound: Can't read from mmapped device (1)\n"); return -EINVAL; } - else if (!dmap->qlen) - { - int tmout; + else + while (dmap->qlen <= 0 && n++ < 10) + { + int tmout; - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || - !audio_devs[dev]->go) - { - restore_flags (flags); - return -EAGAIN; - } + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || + !audio_devs[dev]->go) + { + restore_flags (flags); + return -EAGAIN; + } - if ((err = DMAbuf_activate_recording (dev, dmap)) < 0) - { - restore_flags (flags); - return err; - } + if ((err = DMAbuf_activate_recording (dev, dmap)) < 0) + { + restore_flags (flags); + return err; + } - /* Wait for the next block */ + /* Wait for the next block */ - if (dontblock) - { - restore_flags (flags); - return -EAGAIN; - } + if (dontblock) + { + restore_flags (flags); + return -EAGAIN; + } - if (!audio_devs[dev]->go) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; + if (!audio_devs[dev]->go) + tmout = 0; + else + { + tmout = + (dmap->fragment_size * HZ) / dmap->data_rate; - tmout += HZ / 10; /* Some safety distance */ + tmout += HZ / 10; /* Some safety distance */ - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + } - { - unsigned long tlimit; + { + unsigned long tlimit; - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) + if (tmout) + current->timeout = tlimit = jiffies + (tmout); + else + tlimit = (unsigned long) -1; + in_sleep_flag[dev].opts = WK_SLEEP; + interruptible_sleep_on (&in_sleeper[dev]); + if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + in_sleep_flag[dev].opts |= WK_TIMEOUT; + } + in_sleep_flag[dev].opts &= ~WK_SLEEP; + }; + if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; + err = -EIO; + printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); + dma_reset_input (dev); + ; } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) - { - printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - err = EIO; - dma_reset_input (dev); - ; - } - else - err = EINTR; - } + else + err = -EINTR; + } restore_flags (flags); - if (!dmap->qlen) - return -err; + if (dmap->qlen <= 0) + { + if (err == 0) + err = -EINTR; + return err; + } *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; @@ -660,17 +684,16 @@ DMAbuf_rmchars (int dev, int buff_no, int c) int p = dmap->counts[dmap->qhead] + c; - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) + if (dmap->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't read from mmapped device (2)\n"); return -EINVAL; } + else if (dmap->qlen <= 0) + return -EIO; else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ dmap->counts[dmap->qhead] = 0; - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) - printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); dmap->qlen--; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; } @@ -681,7 +704,7 @@ DMAbuf_rmchars (int dev, int buff_no, int c) } int -DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap) +DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction) { /* * Try to approximate the active byte position of the DMA pointer within the @@ -689,7 +712,6 @@ DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap) */ int pos; unsigned long flags; - int chan = dmap->dma; save_flags (flags); cli (); @@ -697,26 +719,31 @@ DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap) pos = 0; else { + int chan = dmap->dma; + clear_dma_ff (chan); disable_dma (dmap->dma); pos = get_dma_residue (chan); pos = dmap->bytes_in_use - pos; - if (dmap->flags & DMODE_OUTPUT) - { - if (dmap->qhead == 0) - pos %= dmap->bytes_in_use; - } - else - { - if (dmap->qtail == 0) - pos %= dmap->bytes_in_use; - } + if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) + if (direction == DMODE_OUTPUT) + { + if (dmap->qhead == 0) + if (pos > dmap->fragment_size) + pos = 0; + } + else + { + if (dmap->qtail == 0) + if (pos > dmap->fragment_size) + pos = 0; + } if (pos < 0) pos = 0; - if (pos > dmap->bytes_in_use) - pos = dmap->bytes_in_use; + if (pos >= dmap->bytes_in_use) + pos = 0; enable_dma (dmap->dma); } restore_flags (flags); @@ -760,8 +787,8 @@ DMAbuf_space_in_queue (int dev) int len, max, tmp; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - /* Don't allow touching pages too close to the playing ones */ - int lim = dmap->nbufs - 1; + int lim = dmap->nbufs; + if (lim < 2) lim = 2; @@ -789,7 +816,7 @@ DMAbuf_space_in_queue (int dev) if (len >= max) return 0; - return 1; + return max - len; } static int @@ -812,7 +839,7 @@ output_sleep (int dev, int dontblock) /* * Wait for free space */ - if (!audio_devs[dev]->go) + if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) tmout = 0; else { @@ -850,13 +877,12 @@ output_sleep (int dev, int dontblock) if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) { printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - err = EIO; ; dma_reset_output (dev); } else if ((current->signal & ~current->blocked)) { - err = EINTR; + err = -EINTR; } return err; @@ -869,19 +895,24 @@ find_output_space (int dev, char **buf, int *size) unsigned long flags; unsigned long offs, active_offs; long len; + int maxfrags; - if (!DMAbuf_space_in_queue (dev)) - return 0; + if (!(maxfrags = DMAbuf_space_in_queue (dev))) + { + return 0; + } save_flags (flags); cli (); #ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + (dmap->qhead + 1) * dmap->fragment_size; + active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; #else - active_offs = ((dmap->byte_counter + DMAbuf_get_buffer_pointer (dev, dmap))); - /* / dmap->fragment_size) * dmap->fragment_size; */ - + active_offs = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); + /* Check for pointer wrapping situation */ + if (active_offs < 0 || active_offs >= dmap->bytes_in_use) + active_offs = 0; + active_offs += dmap->byte_counter; #endif offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; @@ -898,13 +929,12 @@ find_output_space (int dev, char **buf, int *size) return 0; } - if ((offs + len) > dmap->bytes_in_use) - len = dmap->bytes_in_use - offs; + if (len > maxfrags * dmap->fragment_size) + len = maxfrags * dmap->fragment_size; *size = len & ~3; restore_flags (flags); - return (len > 0); } @@ -912,7 +942,7 @@ int DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { unsigned long flags; - int err = EIO; + int err = -EIO; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; if (dmap->needs_reorg) @@ -944,14 +974,8 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) } } - if (!find_output_space (dev, buf, size)) - { - restore_flags (flags); - return -EIO; /* Caught a signal ? */ - } restore_flags (flags); - dmap->flags |= DMA_DIRTY; return 0; } @@ -962,7 +986,7 @@ DMAbuf_move_wrpointer (int dev, int l) unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - unsigned long end_ptr, p, prev_count; + unsigned long end_ptr, p; int post = (dmap->flags & DMA_POST); ; @@ -971,12 +995,16 @@ DMAbuf_move_wrpointer (int dev, int l) dmap->cfrag = -1; - prev_count = dmap->user_counter; dmap->user_counter += l; + dmap->flags |= DMA_DIRTY; + + if (dmap->user_counter >= dmap->max_byte_counter) + { /* Wrap the byte counters */ + long decr = dmap->user_counter; - if (dmap->user_counter < prev_count) /* Wrap? */ - { /* Wrap the device counter too */ - dmap->byte_counter %= dmap->bytes_in_use; + dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->user_counter; + dmap->byte_counter -= decr; } end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; @@ -995,6 +1023,13 @@ DMAbuf_move_wrpointer (int dev, int l) dmap->counts[dmap->qtail] = dmap->user_counter - ptr; +/* + * Let the low level driver to perform some postprocessing to + * the written data. + */ + if (audio_devs[dev]->d->postprocess_write) + audio_devs[dev]->d->postprocess_write (dev); + if (!(dmap->flags & DMA_ACTIVE)) if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) @@ -1034,11 +1069,6 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) if (chan < 0) return 0; - /* - * The count must be one less than the actual size. This is handled by - * set_dma_addr() - */ - sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0); return count; @@ -1069,14 +1099,14 @@ local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) return 0; } + if (dmap->flags & DMA_NODMA) + { + return 1; + } + if (chan < 0) return 0; - /* - * The count must be one less than the actual size. This is handled by - * set_dma_addr() - */ - sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); dmap->flags |= DMA_STARTED; @@ -1100,19 +1130,9 @@ finish_output_interrupt (int dev, struct dma_buffparms *dmap) restore_flags (flags); } -void -DMAbuf_outputintr (int dev, int event_type) +static void +do_outputintr (int dev, int dummy) { - /* - * Event types: - * 0 = DMA transfer done. Device still has more data in the local - * buffer. - * 1 = DMA transfer done. Device doesn't have local buffer or it's - * empty now. - * 2 = No DMA transfer but the device has now more space in it's local - * buffer. - */ - unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; int this_fragment; @@ -1128,18 +1148,20 @@ DMAbuf_outputintr (int dev, int event_type) return; } - if (dmap->mapping_flags & DMA_MAP_MAPPED) + if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ { - unsigned long prev_counter = dmap->byte_counter; - /* mmapped access */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; if (dmap->qhead == 0) /* Wrapped */ { dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter < prev_counter) /* Overflow */ + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ { - dmap->user_counter %= dmap->bytes_in_use; + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; } } @@ -1153,21 +1175,6 @@ DMAbuf_outputintr (int dev, int event_type) return; } - if (event_type == 2) - { - finish_output_interrupt (dev, dmap); - return; - } - - if (dmap->qlen > dmap->nbufs) - dmap->qlen = dmap->nbufs; - - if (dmap->qlen <= 0) - { - finish_output_interrupt (dev, dmap); - return; - } - save_flags (flags); cli (); @@ -1177,32 +1184,34 @@ DMAbuf_outputintr (int dev, int event_type) if (dmap->qhead == 0) /* Wrapped */ { - unsigned long prev_counter = dmap->byte_counter; - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter < prev_counter) /* Overflow */ + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ { - dmap->user_counter %= dmap->bytes_in_use; + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; } } if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; - if (event_type == 1 && dmap->qlen < 1) + while (dmap->qlen < 0) { dmap->underrun_count++; - dmap->qlen = 0; + dmap->qlen++; if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) { dmap->flags &= ~DMA_DIRTY; memset (audio_devs[dev]->dmap_out->raw_buf, audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); + audio_devs[dev]->dmap_out->buffsize); } dmap->user_counter += dmap->fragment_size; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } if (dmap->qlen > 0) @@ -1213,10 +1222,43 @@ DMAbuf_outputintr (int dev, int event_type) } void -DMAbuf_inputintr (int dev) +DMAbuf_outputintr (int dev, int notify_only) { unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + save_flags (flags); + cli (); + + if (!(dmap->flags & DMA_NODMA)) + { + int chan = dmap->dma, pos, n; + + clear_dma_ff (chan); + disable_dma (dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue (chan); + enable_dma (dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qhead != pos && n++ < dmap->nbufs) + { + do_outputintr (dev, notify_only); + } + } + else + do_outputintr (dev, notify_only); + restore_flags (flags); +} + +static void +do_inputintr (int dev) +{ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; #ifdef OS_DMA_INTR if (audio_devs[dev]->dmap_in->dma >= 0) @@ -1234,12 +1276,14 @@ DMAbuf_inputintr (int dev) dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; if (dmap->qtail == 0) /* Wrapped */ { - unsigned long prev_counter = dmap->byte_counter; - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter < prev_counter) /* Overflow */ + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ { - dmap->user_counter %= dmap->bytes_in_use; + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; } } dmap->qlen++; @@ -1267,30 +1311,28 @@ DMAbuf_inputintr (int dev) /* Just throw away the oldest fragment but keep the engine running */ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; } - else + else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) { dmap->qlen++; - if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) - printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n", - dev, dmap->qlen, dmap->nbufs); dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; if (dmap->qtail == 0) /* Wrapped */ { - unsigned long prev_counter = dmap->byte_counter; - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter < prev_counter) /* Overflow */ + if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ { - dmap->user_counter %= dmap->bytes_in_use; + long decr = dmap->byte_counter; + + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; } } } - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + @@ -1305,13 +1347,47 @@ DMAbuf_inputintr (int dev) save_flags (flags); cli (); - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { + if (dmap->qlen > 0) + if ((in_sleep_flag[dev].opts & WK_SLEEP)) { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&in_sleeper[dev]); - }; + { + in_sleep_flag[dev].opts = WK_WAKEUP; + wake_up (&in_sleeper[dev]); + }; + } + restore_flags (flags); +} + +void +DMAbuf_inputintr (int dev) +{ + struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + unsigned long flags; + + save_flags (flags); + cli (); + + if (!(dmap->flags & DMA_NODMA)) + { + int chan = dmap->dma, pos, n; + + clear_dma_ff (chan); + disable_dma (dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue (chan); + enable_dma (dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qtail != pos && ++n < dmap->nbufs) + { + do_inputintr (dev); + } } + else + do_inputintr (dev); restore_flags (flags); } @@ -1330,8 +1406,9 @@ DMAbuf_open_dma (int dev) return -EBUSY; } dma_init_buffers (dev, audio_devs[dev]->dmap_out); + out_sleep_flag[dev].opts = WK_NONE; audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize; + audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; if (chan >= 0) { @@ -1339,7 +1416,7 @@ DMAbuf_open_dma (int dev) save_flags (flags); cli (); - disable_dma (chan); + disable_dma (audio_devs[dev]->dmap_out->dma); clear_dma_ff (chan); restore_flags (flags); } @@ -1354,37 +1431,39 @@ DMAbuf_close_dma (int dev) } void -DMAbuf_init (void) +DMAbuf_init (int dev, int dma1, int dma2) { - int dev; - /* * NOTE! This routine could be called several times. */ - for (dev = 0; dev < num_audiodevs; dev++) - if (audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) - panic ("OSS: audio_devs[%d]->d == NULL\n", dev); - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; - - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } - else - { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; + if (audio_devs[dev]->dmap_out == NULL) + { + if (audio_devs[dev]->d == NULL) + panic ("OSS: audio_devs[%d]->d == NULL\n", dev); + + if (audio_devs[dev]->parent_dev) + { /* Use DMA map of the parent dev */ + int parent = audio_devs[dev]->parent_dev - 1; - if (audio_devs[dev]->flags & DMA_DUPLEX) + audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; + audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; + } + else + { + audio_devs[dev]->dmap_out = + audio_devs[dev]->dmap_in = + &dmaps[ndmaps++]; + audio_devs[dev]->dmap_out->dma = dma1; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; - } - } + audio_devs[dev]->dmap_in->dma = dma2; + } + } + } } int @@ -1396,7 +1475,7 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) switch (sel_type) { case SEL_IN: - if (!(audio_devs[dev]->open_mode)) + if (!(audio_devs[dev]->open_mode & OPEN_READ)) return 0; dmap = audio_devs[dev]->dmap_in; @@ -1448,6 +1527,9 @@ DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) case SEL_OUT: dmap = audio_devs[dev]->dmap_out; + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + if (dmap->mapping_flags & DMA_MAP_MAPPED) { if (dmap->qlen) diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c new file mode 100644 index 000000000000..b7da7932a673 --- /dev/null +++ b/drivers/sound/dmasound.c @@ -0,0 +1,3435 @@ + +/* linux/drivers/sound/dmasound.c */ + +/* + +OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k + +(c) 1995 by Michael Schlueter & Michael Marte + +Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS +interface and the u-law to signed byte conversion. + +Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue, +/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like +to thank: +Michael Schlueter for initial ideas and documentation on the MFP and +the DMA sound hardware. +Therapy? for their CD 'Troublegum' which really made me rock. + +/dev/sndstat is based on code by Hannu Savolainen, the author of the +VoxWare family of drivers. + +This file is subject to the terms and conditions of the GNU General Public +License. See the file COPYING in the main directory of this archive +for more details. + +History: +1995/8/25 first release + +1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming + and several race conditions + +1995/9/14 ++roman: After some discussion with Michael Schlueter, revised + the interrupt disabling + Slightly speeded up U8->S8 translation by using long + operations where possible + Added 4:3 interpolation for /dev/audio + +1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio + converting to play at 12517Hz instead of 6258Hz. + +1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program + the DMA for another frame while there's still one + running. This allows the IRQ response to be + arbitrarily delayed and playing will still continue. + +1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for + Falcon audio (the Falcon doesn't raise an IRQ at the + end of a frame, but at the beginning instead!). uses + 'if (codec_dma)' in lots of places to simply switch + between Falcon and TT code. + +1995/11/06 ++TeSche: started introducing a hardware abstraction scheme + (may perhaps also serve for Amigas?), can now play + samples at almost all frequencies by means of a more + generalized expand routine, takes a good deal of care + to cut data only at sample sizes, buffer size is now + a kernel runtime option, implemented fsync() & several + minor improvements + ++Guenther: useful hints and bug fixes, cross-checked it for + Falcons + +1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. + Unification to drivers/sound/dmasound.c. + +1996/4/6 ++Martin Mitchell: updated to 1.3 kernel. + +1996/6/13 ++topi: fixed things that were broken (mainly the amiga + 14-bit routines), /dev/sndstat shows now the real + hardware frequency, the lowpass filter is disabled + by default now. + +1996/9/25 ++geert: modularization + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATARI +#include +#include +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA +#include +#include +#endif /* CONFIG_AMIGA */ + +#include "dmasound.h" +#include + + +#ifdef MODULE +static int chrdev_registered = 0; +static int irq_installed = 0; +#endif /* MODULE */ +static char **sound_buffers = NULL; + + +#ifdef CONFIG_ATARI +extern void atari_microwire_cmd(int cmd); +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA + /* + * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * (Imported from arch/m68k/amiga/amisound.c) + */ + +extern volatile u_short amiga_audio_min_period; + + + /* + * amiga_mksound() should be able to restore the period after beeping + * (Imported from arch/m68k/amiga/amisound.c) + */ + +extern u_short amiga_audio_period; + + + /* + * Audio DMA masks + */ + +#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3) +#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1) +#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3) + +#endif /* CONFIG_AMIGA */ + + +/*** Some declarations *******************************************************/ + + +#define DMASND_TT 1 +#define DMASND_FALCON 2 +#define DMASND_AMIGA 3 + +#define MAX_CATCH_RADIUS 10 +#define MIN_BUFFERS 4 +#define MIN_BUFSIZE 4 +#define MAX_BUFSIZE 128 /* Limit for Amiga */ + +static int catchRadius = 0, numBufs = 4, bufSize = 32; + + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff)) +#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff)) + +#define IOCTL_IN(arg, ret) \ + do { int error = get_user(ret, (int *)(arg)); \ + if (error) return error; \ + } while (0) +#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret) + + +/*** Some low level helpers **************************************************/ + + +/* 8 bit mu-law */ + +static char ulaw2dma8[] = { + -126, -122, -118, -114, -110, -106, -102, -98, + -94, -90, -86, -82, -78, -74, -70, -66, + -63, -61, -59, -57, -55, -53, -51, -49, + -47, -45, -43, -41, -39, -37, -35, -33, + -31, -30, -29, -28, -27, -26, -25, -24, + -23, -22, -21, -20, -19, -18, -17, -16, + -16, -15, -15, -14, -14, -13, -13, -12, + -12, -11, -11, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -7, -6, -6, + -6, -6, -5, -5, -5, -5, -4, -4, + -4, -4, -4, -4, -3, -3, -3, -3, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 0, + 125, 121, 117, 113, 109, 105, 101, 97, + 93, 89, 85, 81, 77, 73, 69, 65, + 62, 60, 58, 56, 54, 52, 50, 48, + 46, 44, 42, 40, 38, 36, 34, 32, + 30, 29, 28, 27, 26, 25, 24, 23, + 22, 21, 20, 19, 18, 17, 16, 15, + 15, 14, 14, 13, 13, 12, 12, 11, + 11, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 6, 6, 6, 6, 5, 5, + 5, 5, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* 8 bit A-law */ + +static char alaw2dma8[] = { + -22, -21, -24, -23, -18, -17, -20, -19, + -30, -29, -32, -31, -26, -25, -28, -27, + -11, -11, -12, -12, -9, -9, -10, -10, + -15, -15, -16, -16, -13, -13, -14, -14, + -86, -82, -94, -90, -70, -66, -78, -74, + -118, -114, -126, -122, -102, -98, -110, -106, + -43, -41, -47, -45, -35, -33, -39, -37, + -59, -57, -63, -61, -51, -49, -55, -53, + -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -6, -6, -6, -6, -5, -5, -5, -5, + -8, -8, -8, -8, -7, -7, -7, -7, + -3, -3, -3, -3, -3, -3, -3, -3, + -4, -4, -4, -4, -4, -4, -4, -4, + 21, 20, 23, 22, 17, 16, 19, 18, + 29, 28, 31, 30, 25, 24, 27, 26, + 10, 10, 11, 11, 8, 8, 9, 9, + 14, 14, 15, 15, 12, 12, 13, 13, + 86, 82, 94, 90, 70, 66, 78, 74, + 118, 114, 126, 122, 102, 98, 110, 106, + 43, 41, 47, 45, 35, 33, 39, 37, + 59, 57, 63, 61, 51, 49, 55, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 4, 4, 4, 4, + 7, 7, 7, 7, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 +}; + + +#ifdef HAS_16BIT_TABLES + +/* 16 bit mu-law */ + +static char ulaw2dma16[] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0, +}; + +/* 16 bit A-law */ + +static char alaw2dma16[] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848, +}; +#endif /* HAS_16BIT_TABLES */ + + +#ifdef HAS_14BIT_TABLES + +/* 14 bit mu-law (LSB) */ + +static char alaw2dma14l[] = { + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 49, 17, 49, 17, 49, 17, 49, 17, + 49, 17, 49, 17, 49, 17, 49, 17, + 41, 57, 9, 25, 41, 57, 9, 25, + 41, 57, 9, 25, 41, 57, 9, 25, + 37, 45, 53, 61, 5, 13, 21, 29, + 37, 45, 53, 61, 5, 13, 21, 29, + 35, 39, 43, 47, 51, 55, 59, 63, + 3, 7, 11, 15, 19, 23, 27, 31, + 34, 36, 38, 40, 42, 44, 46, 48, + 50, 52, 54, 56, 58, 60, 62, 0, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, + 15, 47, 15, 47, 15, 47, 15, 47, + 15, 47, 15, 47, 15, 47, 15, 47, + 23, 7, 55, 39, 23, 7, 55, 39, + 23, 7, 55, 39, 23, 7, 55, 39, + 27, 19, 11, 3, 59, 51, 43, 35, + 27, 19, 11, 3, 59, 51, 43, 35, + 29, 25, 21, 17, 13, 9, 5, 1, + 61, 57, 53, 49, 45, 41, 37, 33, + 30, 28, 26, 24, 22, 20, 18, 16, + 14, 12, 10, 8, 6, 4, 2, 0 +}; + +/* 14 bit A-law (LSB) */ + +static char alaw2dma14l[] = { + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 16, 48, 16, 48, 16, 48, 16, 48, + 16, 48, 16, 48, 16, 48, 16, 48, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 42, 46, 34, 38, 58, 62, 50, 54, + 10, 14, 2, 6, 26, 30, 18, 22, + 40, 56, 8, 24, 40, 56, 8, 24, + 40, 56, 8, 24, 40, 56, 8, 24, + 20, 28, 4, 12, 52, 60, 36, 44, + 20, 28, 4, 12, 52, 60, 36, 44, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 48, 16, 48, 16, 48, 16, 48, 16, + 48, 16, 48, 16, 48, 16, 48, 16, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 22, 18, 30, 26, 6, 2, 14, 10, + 54, 50, 62, 58, 38, 34, 46, 42, + 24, 8, 56, 40, 24, 8, 56, 40, + 24, 8, 56, 40, 24, 8, 56, 40, + 44, 36, 60, 52, 12, 4, 28, 20, + 44, 36, 60, 52, 12, 4, 28, 20 +}; +#endif /* HAS_14BIT_TABLES */ + + +/*** Translations ************************************************************/ + + +#ifdef CONFIG_ATARI +static long ata_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static long ami_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft); +#endif /* CONFIG_AMIGA */ + + +/*** Machine definitions *****************************************************/ + + +typedef struct { + int type; + void *(*dma_alloc)(unsigned int, int); + void (*dma_free)(void *, unsigned int); + int (*irqinit)(void); +#ifdef MODULE + void (*irqcleanup)(void); +#endif /* MODULE */ + void (*init)(void); + void (*silence)(void); + int (*setFormat)(int); + int (*setVolume)(int); + int (*setBass)(int); + int (*setTreble)(int); + void (*play)(void); +} MACHINE; + + +/*** Low level stuff *********************************************************/ + + +typedef struct { + int format; /* AFMT_* */ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit*/ + int speed; /* speed */ +} SETTINGS; + +typedef struct { + long (*ct_ulaw)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_alaw)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s8)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u8)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16be)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16be)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_s16le)(const u_char *, unsigned long, u_char *, long *, long); + long (*ct_u16le)(const u_char *, unsigned long, u_char *, long *, long); +} TRANS; + +struct sound_settings { + MACHINE mach; /* machine dependent things */ + SETTINGS hard; /* hardware settings */ + SETTINGS soft; /* software settings */ + SETTINGS dsp; /* /dev/dsp default settings */ + TRANS *trans; /* supported translations */ + int volume_left; /* volume (range is machine dependent) */ + int volume_right; + int bass; /* tone (range is machine dependent) */ + int treble; + int minDev; /* minor device number currently open */ +#ifdef CONFIG_ATARI + int bal; /* balance factor for expanding (not volume!) */ + u_long data; /* data for expanding */ +#endif /* CONFIG_ATARI */ +}; + +static struct sound_settings sound; + + +#ifdef CONFIG_ATARI +static void *AtaAlloc(unsigned int size, int flags); +static void AtaFree(void *, unsigned int size); +static int AtaIrqInit(void); +#ifdef MODULE +static void AtaIrqCleanUp(void); +#endif /* MODULE */ +static int AtaSetBass(int bass); +static int AtaSetTreble(int treble); +static void TTSilence(void); +static void TTInit(void); +static int TTSetFormat(int format); +static int TTSetVolume(int volume); +static void FalconSilence(void); +static void FalconInit(void); +static int FalconSetFormat(int format); +static int FalconSetVolume(int volume); +static void ata_sq_play_next_frame(int index); +static void AtaPlay(void); +static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static void *AmiAlloc(unsigned int size, int flags); +static void AmiFree(void *, unsigned int); +static int AmiIrqInit(void); +#ifdef MODULE +static void AmiIrqCleanUp(void); +#endif /* MODULE */ +static void AmiSilence(void); +static void AmiInit(void); +static int AmiSetFormat(int format); +static int AmiSetVolume(int volume); +static int AmiSetTreble(int treble); +static void ami_sq_play_next_frame(int index); +static void AmiPlay(void); +static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); +#endif /* CONFIG_AMIGA */ + + +/*** Mid level stuff *********************************************************/ + + +static void sound_silence(void); +static void sound_init(void); +static int sound_set_format(int format); +static int sound_set_speed(int speed); +static int sound_set_stereo(int stereo); +static int sound_set_volume(int volume); +#ifdef CONFIG_ATARI +static int sound_set_bass(int bass); +#endif /* CONFIG_ATARI */ +static int sound_set_treble(int treble); +static long sound_copy_translate(const u_char *userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft); + + +/* + * /dev/mixer abstraction + */ + +struct sound_mixer { + int busy; +}; + +static struct sound_mixer mixer; + +static void mixer_init(void); +static int mixer_open(int open_mode); +static int mixer_release(void); +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); + + +/* + * Sound queue stuff, the heart of the driver + */ + +struct sound_queue { + int max_count, block_size; + char **buffers; + + /* it shouldn't be necessary to declare any of these volatile */ + int front, rear, count; + int rear_size; + /* + * The use of the playing field depends on the hardware + * + * Atari: The number of frames that are loaded/playing + * + * Amiga: Bit 0 is set: a frame is loaded + * Bit 1 is set: a frame is playing + */ + int playing; + struct wait_queue *write_queue, *open_queue, *sync_queue; + int open_mode; + int busy, syncing; +#ifdef CONFIG_ATARI + int ignore_int; /* ++TeSche: used for Falcon */ +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + int block_size_half, block_size_quarter; +#endif /* CONFIG_AMIGA */ +}; + +static struct sound_queue sq; + +#define sq_block_address(i) (sq.buffers[i]) +#define SIGNAL_RECEIVED (current->signal & ~current->blocked) +#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK) +#define ONE_SECOND HZ /* in jiffies (100ths of a second) */ +#define NO_TIME_LIMIT 0xffffffff +#define SLEEP(queue, time_limit) \ + current->timeout = jiffies+(time_limit); \ + interruptible_sleep_on(&queue); +#define WAKE_UP(queue) (wake_up_interruptible(&queue)) + +static void sq_init(int numBufs, int bufSize, char **buffers); +static void sq_play(void); +static long sq_write(const char *src, unsigned long uLeft); +static int sq_open(int open_mode); +static void sq_reset(void); +static int sq_sync(void); +static int sq_release(void); + + +/* + * /dev/sndstat + */ + +struct sound_state { + int busy; + char buf[512]; + int len, ptr; +}; + +static struct sound_state state; + +static void state_init(void); +static int state_open(int open_mode); +static int state_release(void); +static long state_read(char *dest, unsigned long count); + + +/*** High level stuff ********************************************************/ + + +static int sound_open(struct inode *inode, struct file *file); +static int sound_fsync(struct inode *inode, struct file *filp); +static void sound_release(struct inode *inode, struct file *file); +static long long sound_lseek(struct inode *inode, struct file *file, + long long offset, int orig); +static long sound_read(struct inode *inode, struct file *file, char *buf, + unsigned long count); +static long sound_write(struct inode *inode, struct file *file, + const char *buf, unsigned long count); +static inline int ioctl_return(int *addr, int value) +{ + if (value < 0) + return(value); + + return put_user(value, addr); +} +static int unknown_minor_dev(char *fname, int dev); +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg); + + +/*** Config & Setup **********************************************************/ + + +void soundcard_init(void); +void dmasound_setup(char *str, int *ints); +void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ + + +/*** Translations ************************************************************/ + + +/* ++TeSche: radically changed for new expanding purposes... + * + * These two routines now deal with copying/expanding/translating the samples + * from user space into our buffer at the right frequency. They take care about + * how much data there's actually to read, how much buffer space there is and + * to convert samples into the right frequency/encoding. They will only work on + * complete samples so it may happen they leave some bytes in the input stream + * if the user didn't write a multiple of the current sample size. They both + * return the number of bytes they've used from both streams so you may detect + * such a situation. Luckily all programs should be able to cope with that. + * + * I think I've optimized anything as far as one can do in plain C, all + * variables should fit in registers and the loops are really short. There's + * one loop for every possible situation. Writing a more generalized and thus + * parameterized loop would only produce slower code. Feel free to optimize + * this in assembler if you like. :) + * + * I think these routines belong here because they're not yet really hardware + * independent, especially the fact that the Falcon can play 16bit samples + * only in stereo is hardcoded in both of them! + * + * ++geert: split in even more functions (one per format) + */ + +#ifdef CONFIG_ATARI +static long ata_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + u_char *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + *frameUsed += used; + return(used); +} + + +static long ata_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + void *p = &frame[*frameUsed]; + + count = min(userCount, frameLeft); + if (sound.soft.stereo) + count &= ~1; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + return(used); +} + + +static long ata_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft); + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + u_short data; + get_user(data, ((u_short *)userPtr)++); + *p++ = data ^ 0x8080; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ata_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + void *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft) & ~3; + used = count; + copy_from_user(p, userPtr, count); + *frameUsed += used; + } + return(used); +} + + +static long ata_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count*4; + while (count > 0) { + get_user(data, ((u_int *)userPtr)++); + *p++ = data ^ 0x80008000; + count--; + } + *frameUsed += used; + } + return(used); +} + + +static long ata_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *p++ = data; + *p++ = data; + count--; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count*4; + while (count > 0) { + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data); + *p++ = data; + count--; + } + *frameUsed += used; + } + return(used); +} + + +static long ata_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + count = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *p++ = data; + *p++ = data; + } + *frameUsed += used*2; + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + count = min(userCount, frameLeft)>>2; + used = count; + while (count > 0) { + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + *p++ = data; + count--; + } + *frameUsed += used; + } + return(used); +} + + +static long ata_ctx_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + u_char c; + if (bal < 0) { + if (!userCount) + break; + get_user(c, userPtr++); + data = table[c]; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + u_char c; + if (bal < 0) { + if (userCount < 2) + break; + get_user(c, userPtr++); + data = table[c] << 8; + get_user(c, userPtr++); + data |= table[c]; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + get_user(data, userPtr++); + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + while (frameLeft) { + if (bal < 0) { + if (!userCount) + break; + get_user(data, userPtr++); + data ^= 0x80; + userCount--; + bal += hSpeed; + } + *p++ = data; + frameLeft--; + bal -= sSpeed; + } + } else { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 2) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8080; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 2; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + data ^= 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data); + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} + + +static long ata_ctx_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + /* this should help gcc to stuff everything into registers */ + u_long data = sound.data; + long bal = sound.bal; + long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed; + long used, usedf; + + used = userCount; + usedf = frameLeft; + if (!sound.soft.stereo) { + u_short *p = (u_short *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 2) + break; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + userCount -= 2; + bal += hSpeed; + } + *p++ = data; + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } else { + u_long *p = (u_long *)&frame[*frameUsed]; + while (frameLeft >= 4) { + if (bal < 0) { + if (userCount < 4) + break; + get_user(data, ((u_int *)userPtr)++); + data = le2be16dbl(data) ^ 0x80008000; + userCount -= 4; + bal += hSpeed; + } + *p++ = data; + frameLeft -= 4; + bal -= sSpeed; + } + } + sound.bal = bal; + sound.data = data; + used -= userCount; + *frameUsed += usedf-frameLeft; + return(used); +} +#endif /* CONFIG_ATARI */ + + +#ifdef CONFIG_AMIGA +static long ami_ct_law(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8; + long count, used; + + if (!sound.soft.stereo) { + u_char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = table[data]; + count--; + } + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *left++ = table[data]; + get_user(data, userPtr++); + *right++ = table[data]; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_s8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + + if (!sound.soft.stereo) { + void *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + copy_from_user(p, userPtr, count); + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(*left++, userPtr++); + get_user(*right++, userPtr++); + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_u8(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + + if (!sound.soft.stereo) { + char *p = &frame[*frameUsed]; + count = min(userCount, frameLeft) & ~1; + used = count; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *p++ = data ^ 0x80; + count--; + } + } else { + u_char *left = &frame[*frameUsed>>1]; + u_char *right = left+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + u_char data; + get_user(data, userPtr++); + *left++ = data ^ 0x80; + get_user(data, userPtr++); + *right++ = data ^ 0x80; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_s16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_u16be(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + data ^= 0x8000; + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_s16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data); + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} + + +static long ami_ct_u16le(const u_char *userPtr, unsigned long userCount, + u_char frame[], long *frameUsed, long frameLeft) +{ + long count, used; + u_long data; + + if (!sound.soft.stereo) { + u_char *high = &frame[*frameUsed>>1]; + u_char *low = high+sq.block_size_half; + count = min(userCount, frameLeft)>>1 & ~1; + used = count*2; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *high++ = data>>8; + *low++ = (data>>2) & 0x3f; + count--; + } + } else { + u_char *lefth = &frame[*frameUsed>>2]; + u_char *leftl = lefth+sq.block_size_quarter; + u_char *righth = lefth+sq.block_size_half; + u_char *rightl = righth+sq.block_size_quarter; + count = min(userCount, frameLeft)>>2 & ~1; + used = count*4; + while (count > 0) { + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *lefth++ = data>>8; + *leftl++ = (data>>2) & 0x3f; + get_user(data, ((u_short *)userPtr)++); + data = le2be16(data) ^ 0x8000; + *righth++ = data>>8; + *rightl++ = (data>>2) & 0x3f; + count--; + } + } + *frameUsed += used; + return(used); +} +#endif /* CONFIG_AMIGA */ + + +#ifdef CONFIG_ATARI +static TRANS transTTNormal = { + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL +}; + +static TRANS transTTExpanding = { + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL +}; + +static TRANS transFalconNormal = { + ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, ata_ct_s16be, ata_ct_u16be, + ata_ct_s16le, ata_ct_u16le +}; + +static TRANS transFalconExpanding = { + ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, ata_ctx_s16be, + ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le +}; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static TRANS transAmiga = { + ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8, ami_ct_s16be, ami_ct_u16be, + ami_ct_s16le, ami_ct_u16le +}; +#endif /* CONFIG_AMIGA */ + + +/*** Low level stuff *********************************************************/ + + +#ifdef CONFIG_ATARI + +/* + * Atari (TT/Falcon) + */ + +static void *AtaAlloc(unsigned int size, int flags) +{ + int order; + unsigned int a_size; + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) { + order++; + a_size <<= 1; + } + return (void *) __get_dma_pages(flags, order); +} + +static void AtaFree(void *obj, unsigned int size) +{ + int order; + unsigned int a_size; + order = 0; + a_size = PAGE_SIZE; + while (a_size < size) { + order++; + a_size <<= 1; + } + free_pages ((unsigned long) obj, order); +} + +static int AtaIrqInit(void) +{ + /* Set up timer A. Timer A + will receive a signal upon end of playing from the sound + hardware. Furthermore Timer A is able to count events + and will cause an interrupt after a programmed number + of events. So all we need to keep the music playing is + to provide the sound hardware with new data upon + an interrupt from timer A. */ + mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */ + mfp.tim_dt_a = 1; /* Cause interrupt after first event. */ + mfp.tim_ct_a = 8; /* Turn on event counting. */ + /* Register interrupt handler. */ + request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW, + "DMA sound", ata_sq_interrupt); + mfp.int_en_a |= 0x20; /* Turn interrupt on. */ + mfp.int_mk_a |= 0x20; + return(1); +} + +#ifdef MODULE +static void AtaIrqCleanUp(void) +{ + mfp.tim_ct_a = 0; /* stop timer */ + mfp.int_en_a &= ~0x20; /* turn interrupt off */ + free_irq(IRQ_MFP_TIMA, ata_sq_interrupt); +} +#endif /* MODULE */ + + +#define TONE_VOXWARE_TO_DB(v) \ + (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25) +#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50) + + +static int AtaSetBass(int bass) +{ + sound.bass = TONE_VOXWARE_TO_DB(bass); + atari_microwire_cmd(MW_LM1992_BASS(sound.bass)); + return(TONE_DB_TO_VOXWARE(sound.bass)); +} + + +static int AtaSetTreble(int treble) +{ + sound.treble = TONE_VOXWARE_TO_DB(treble); + atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble)); + return(TONE_DB_TO_VOXWARE(sound.treble)); +} + + + +/* + * TT + */ + + +static void TTSilence(void) +{ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */ +} + + +static void TTInit(void) +{ + int mode, i, idx; + const int freq[4] = {50066, 25033, 12517, 6258}; + + /* search a frequency that fits into the allowed error range */ + + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* this isn't as much useful for a TT than for a Falcon, but + * then it doesn't hurt very much to implement it for a TT too. + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) { + sound.soft.speed = freq[idx]; + sound.trans = &transTTNormal; + } else + sound.trans = &transTTExpanding; + + TTSilence(); + sound.hard = sound.soft; + + if (sound.hard.speed > 50066) { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + sound.trans = &transTTNormal; + } else if (sound.hard.speed > 25033) { + sound.hard.speed = 50066; + mode = DMASND_MODE_50KHZ; + } else if (sound.hard.speed > 12517) { + sound.hard.speed = 25033; + mode = DMASND_MODE_25KHZ; + } else if (sound.hard.speed > 6258) { + sound.hard.speed = 12517; + mode = DMASND_MODE_12KHZ; + } else { + sound.hard.speed = 6258; + mode = DMASND_MODE_6KHZ; + } + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + DMASND_MODE_8BIT | mode; + + sound.bal = -sound.soft.speed; +} + + +static int TTSetFormat(int format) +{ + /* TT sound DMA supports only 8bit modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_S8: + case AFMT_U8: + break; + default: + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = 8; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = 8; + } + TTInit(); + + return(format); +} + + +#define VOLUME_VOXWARE_TO_DB(v) \ + (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40) +#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2) + + +static int TTSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff); + atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left)); + sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8); + atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right)); + return(VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8)); +} + + + +/* + * Falcon + */ + + +static void FalconSilence(void) +{ + /* stop playback, set sample rate 50kHz for PSG sound */ + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT; + tt_dmasnd.int_div = 0; /* STE compatible divider */ + tt_dmasnd.int_ctrl = 0x0; + tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */ + tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */ + tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */ + tt_dmasnd.adc_src = 3; /* ADC Input = PSG */ +} + + +static void FalconInit(void) +{ + int divider, i, idx; + const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195}; + + /* search a frequency that fits into the allowed error range */ + + idx = -1; + for (i = 0; i < arraysize(freq); i++) + /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would + * be playable without expanding, but that now a kernel runtime + * option + */ + if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius) + idx = i; + if (idx > -1) { + sound.soft.speed = freq[idx]; + sound.trans = &transFalconNormal; + } else + sound.trans = &transFalconExpanding; + + FalconSilence(); + sound.hard = sound.soft; + + if (sound.hard.size == 16) { + /* the Falcon can play 16bit samples only in stereo */ + sound.hard.stereo = 1; + } + + if (sound.hard.speed > 49170) { + /* we would need to squeeze the sound, but we won't do that */ + sound.hard.speed = 49170; + divider = 1; + sound.trans = &transFalconNormal; + } else if (sound.hard.speed > 32780) { + sound.hard.speed = 49170; + divider = 1; + } else if (sound.hard.speed > 24585) { + sound.hard.speed = 32780; + divider = 2; + } else if (sound.hard.speed > 19668) { + sound.hard.speed = 24585; + divider = 3; + } else if (sound.hard.speed > 16390) { + sound.hard.speed = 19668; + divider = 4; + } else if (sound.hard.speed > 12292) { + sound.hard.speed = 16390; + divider = 5; + } else if (sound.hard.speed > 9834) { + sound.hard.speed = 12292; + divider = 7; + } else if (sound.hard.speed > 8195) { + sound.hard.speed = 9834; + divider = 9; + } else { + sound.hard.speed = 8195; + divider = 11; + } + tt_dmasnd.int_div = divider; + + /* Setup Falcon sound DMA for playback */ + tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */ + tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */ + tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */ + tt_dmasnd.cbar_dst = 0x0000; + tt_dmasnd.rec_track_select = 0; + tt_dmasnd.dac_src = 2; /* connect matrix to DAC */ + tt_dmasnd.adc_src = 0; /* ADC Input = Mic */ + + tt_dmasnd.mode = (sound.hard.stereo ? + DMASND_MODE_STEREO : DMASND_MODE_MONO) | + ((sound.hard.size == 8) ? + DMASND_MODE_8BIT : DMASND_MODE_16BIT) | + DMASND_MODE_6KHZ; + + sound.bal = -sound.soft.speed; +} + + +static int FalconSetFormat(int format) +{ + int size; + /* Falcon sound DMA supports 8bit and 16bit modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + + FalconInit(); + + return(format); +} + + +/* This is for the Falcon output *attenuation* in 1.5dB steps, + * i.e. output level from 0 to -22.5dB in -1.5dB steps. + */ +#define VOLUME_VOXWARE_TO_ATT(v) \ + ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20) +#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3) + + +static int FalconSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff); + sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8); + tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4; + return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8); +} + + +static void ata_sq_play_next_frame(int index) +{ + char *start, *end; + + /* used by AtaPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + end = start+((sq.count == index) ? sq.rear_size : sq.block_size); + /* end might not be a legal virtual address. */ + DMASNDSetEnd(VTOP(end - 1) + 1); + DMASNDSetBase(VTOP(start)); + /* Since only an even number of samples per frame can + be played, we might lose one byte here. (TO DO) */ + sq.front = (sq.front+1) % sq.max_count; + sq.playing++; + tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT; +} + + +static void AtaPlay(void) +{ + /* ++TeSche: Note that sq.playing is no longer just a flag but holds + * the number of frames the DMA is currently programmed for instead, + * may be 0, 1 (currently being played) or 2 (pre-programmed). + * + * Changes done to sq.count and sq.playing are a bit more subtle again + * so now I must admit I also prefer disabling the irq here rather + * than considering all possible situations. But the point is that + * disabling the irq doesn't have any bad influence on this version of + * the driver as we benefit from having pre-programmed the DMA + * wherever possible: There's no need to reload the DMA at the exact + * time of an interrupt but only at some time while the pre-programmed + * frame is playing! + */ + atari_disable_irq(IRQ_MFP_TIMA); + + if (sq.playing == 2 || /* DMA is 'full' */ + sq.count <= 0) { /* nothing to do */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + + if (sq.playing == 0) { + /* looks like there's nothing 'in' the DMA yet, so try + * to put two frames into it (at least one is available). + */ + if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(1); + if (sq.count == 1) { + /* no more frames */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, there were two frames, but the second + * one is not yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } else { + /* there's already a frame being played so we may only stuff + * one new into the DMA, but even if this may be the last + * frame existing the previous one is still on sq.count. + */ + if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + atari_enable_irq(IRQ_MFP_TIMA); + return; + } + ata_sq_play_next_frame(2); + } + atari_enable_irq(IRQ_MFP_TIMA); +} + + +static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ +#if 0 + /* ++TeSche: if you should want to test this... */ + static int cnt = 0; + if (sq.playing == 2) + if (++cnt == 10) { + /* simulate losing an interrupt */ + cnt = 0; + return; + } +#endif + + if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) { + /* ++TeSche: Falcon only: ignore first irq because it comes + * immediately after starting a frame. after that, irqs come + * (almost) like on the TT. + */ + sq.ignore_int = 0; + return; + } + + if (!sq.playing) { + /* playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + + /* Probably ;) one frame is finished. Well, in fact it may be that a + * pre-programmed one is also finished because there has been a long + * delay in interrupt delivery and we've completely lost one, but + * there's no way to detect such a situation. In such a case the last + * frame will be played more than once and the situation will recover + * as soon as the irq gets through. + */ + sq.count--; + sq.playing--; + + if (!sq.playing) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; + sq.ignore_int = 1; + } + + WAKE_UP(sq.write_queue); + /* At least one block of the queue is free now + so wake up a writing process blocked because + of a full queue. */ + + if ((sq.playing != 1) || (sq.count != 1)) + /* We must be a bit carefully here: sq.count indicates the + * number of buffers used and not the number of frames to + * be played. If sq.count==1 and sq.playing==1 that means + * the only remaining frame was already programmed earlier + * (and is currently running) so we mustn't call AtaPlay() + * here, otherwise we'll play one frame too much. + */ + AtaPlay(); + + if (!sq.playing) WAKE_UP(sq.sync_queue); + /* We are not playing after AtaPlay(), so there + is nothing to play any more. Wake up a process + waiting for audio output to drain. */ +} +#endif /* CONFIG_ATARI */ + + +#ifdef CONFIG_AMIGA + +/* + * Amiga + */ + + +static void *AmiAlloc(unsigned int size, int flags) +{ + return(amiga_chip_alloc((long)size)); +} + +static void AmiFree(void *obj, unsigned int size) +{ + amiga_chip_free (obj); +} + +static int AmiIrqInit(void) +{ + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; + + /* Register interrupt handler. */ + if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0, + "DMA sound", ami_sq_interrupt)) + return(0); + return(1); +} + +#ifdef MODULE +static void AmiIrqCleanUp(void) +{ + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; + /* release the interrupt */ + free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt); +} +#endif /* MODULE */ + +static void AmiSilence(void) +{ + /* turn off DMA for audio channels */ + custom.dmacon = AMI_AUDIO_OFF; +} + + +static void AmiInit(void) +{ + int period, i; + + AmiSilence(); + + if (sound.soft.speed) + period = amiga_colorclock/sound.soft.speed-1; + else + period = amiga_audio_min_period; + sound.hard = sound.soft; + sound.trans = &transAmiga; + + if (period < amiga_audio_min_period) { + /* we would need to squeeze the sound, but we won't do that */ + period = amiga_audio_min_period; + } else if (period > 65535) { + period = 65535; + } + sound.hard.speed = amiga_colorclock/(period+1); + + for (i = 0; i < 4; i++) + custom.aud[i].audper = period; + amiga_audio_period = period; + + AmiSetTreble(50); /* recommended for newer amiga models */ +} + + +static int AmiSetFormat(int format) +{ + int size; + + /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */ + + switch (format) { + case AFMT_QUERY: + return(sound.soft.format); + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + size = 8; + break; + case AFMT_S16_BE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_U16_LE: + size = 16; + break; + default: /* :-) */ + size = 8; + format = AFMT_S8; + } + + sound.soft.format = format; + sound.soft.size = size; + if (sound.minDev == SND_DEV_DSP) { + sound.dsp.format = format; + sound.dsp.size = sound.soft.size; + } + AmiInit(); + + return(format); +} + + +#define VOLUME_VOXWARE_TO_AMI(v) \ + (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100) +#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64) + +static int AmiSetVolume(int volume) +{ + sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff); + custom.aud[0].audvol = sound.volume_left; + sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8); + custom.aud[1].audvol = sound.volume_right; + return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); +} + +static int AmiSetTreble(int treble) +{ + sound.treble = treble; + if (treble < 50) + ciaa.pra &= ~0x02; + else + ciaa.pra |= 0x02; + return(treble); +} + + +#define AMI_PLAY_LOADED 1 +#define AMI_PLAY_PLAYING 2 +#define AMI_PLAY_MASK 3 + + +static void ami_sq_play_next_frame(int index) +{ + u_char *start, *ch0, *ch1, *ch2, *ch3; + u_long size; + + /* used by AmiPlay() if all doubts whether there really is something + * to be played are already wiped out. + */ + start = sq_block_address(sq.front); + size = (sq.count == index ? sq.rear_size : sq.block_size)>>1; + + if (sound.hard.stereo) { + ch0 = start; + ch1 = start+sq.block_size_half; + size >>= 1; + } else { + ch0 = start; + ch1 = start; + } + if (sound.hard.size == 8) { + custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + custom.dmacon = AMI_AUDIO_8; + } else { + size >>= 1; + custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0); + custom.aud[0].audlen = size; + custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1); + custom.aud[1].audlen = size; + if (sound.volume_left == 64 && sound.volume_right == 64) { + /* We can play pseudo 14-bit only with the maximum volume */ + ch3 = ch0+sq.block_size_quarter; + ch2 = ch1+sq.block_size_quarter; + custom.aud[2].audvol = 1; /* we are being affected by the beeps */ + custom.aud[3].audvol = 1; /* restoring volume here helps a bit */ + custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2); + custom.aud[2].audlen = size; + custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3); + custom.aud[3].audlen = size; + custom.dmacon = AMI_AUDIO_14; + } else + custom.dmacon = AMI_AUDIO_8; + } + sq.front = (sq.front+1) % sq.max_count; + sq.playing |= AMI_PLAY_LOADED; +} + + +static void AmiPlay(void) +{ + int minframes = 1; + + custom.intena = IF_AUD0; + + if (sq.playing & AMI_PLAY_LOADED) { + /* There's already a frame loaded */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + if (sq.playing & AMI_PLAY_PLAYING) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + if (sq.count < minframes) { + /* Nothing to do */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) { + /* hmmm, the only existing frame is not + * yet filled and we're not syncing? + */ + custom.intena = IF_SETCLR | IF_AUD0; + return; + } + + ami_sq_play_next_frame(minframes); + + custom.intena = IF_SETCLR | IF_AUD0; +} + + +static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + int minframes = 1; + + if (!sq.playing) { + /* Playing was interrupted and sq_reset() has already cleared + * the sq variables, so better don't do anything here. + */ + WAKE_UP(sq.sync_queue); + return; + } + + if (sq.playing & AMI_PLAY_PLAYING) { + /* We've just finished a frame */ + sq.count--; + WAKE_UP(sq.write_queue); + } + + if (sq.playing & AMI_PLAY_LOADED) + /* Increase threshold: frame 1 is already being played */ + minframes = 2; + + /* Shift the flags */ + sq.playing = (sq.playing<<1) & AMI_PLAY_MASK; + + if (!sq.playing) + /* No frame is playing, disable audio DMA */ + custom.dmacon = AMI_AUDIO_OFF; + + if (sq.count >= minframes) + /* Try to play the next frame */ + AmiPlay(); + + if (!sq.playing) + /* Nothing to play anymore. + Wake up a process waiting for audio output to drain. */ + WAKE_UP(sq.sync_queue); +} +#endif /* CONFIG_AMIGA */ + + +/*** Machine definitions *****************************************************/ + + +#ifdef CONFIG_ATARI +static MACHINE machTT = { + DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit, +#ifdef MODULE + AtaIrqCleanUp, +#endif /* MODULE */ + TTInit, TTSilence, TTSetFormat, TTSetVolume, AtaSetBass, AtaSetTreble, + AtaPlay +}; + +static MACHINE machFalcon = { + DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit, +#ifdef MODULE + AtaIrqCleanUp, +#endif /* MODULE */ + FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume, AtaSetBass, + AtaSetTreble, AtaPlay +}; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA +static MACHINE machAmiga = { + DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit, +#ifdef MODULE + AmiIrqCleanUp, +#endif /* MODULE */ + AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume, NULL, AmiSetTreble, + AmiPlay +}; +#endif /* CONFIG_AMIGA */ + + +/*** Mid level stuff *********************************************************/ + + +static void sound_silence(void) +{ + /* update hardware settings one more */ + (*sound.mach.init)(); + + (*sound.mach.silence)(); +} + + +static void sound_init(void) +{ + (*sound.mach.init)(); +} + + +static int sound_set_format(int format) +{ + return(*sound.mach.setFormat)(format); +} + + +static int sound_set_speed(int speed) +{ + if (speed < 0) + return(sound.soft.speed); + + sound.soft.speed = speed; + (*sound.mach.init)(); + if (sound.minDev == SND_DEV_DSP) + sound.dsp.speed = sound.soft.speed; + + return(sound.soft.speed); +} + + +static int sound_set_stereo(int stereo) +{ + if (stereo < 0) + return(sound.soft.stereo); + + stereo = !!stereo; /* should be 0 or 1 now */ + + sound.soft.stereo = stereo; + if (sound.minDev == SND_DEV_DSP) + sound.dsp.stereo = stereo; + (*sound.mach.init)(); + + return(stereo); +} + + +static int sound_set_volume(int volume) +{ + return(*sound.mach.setVolume)(volume); +} + + +#ifdef CONFIG_ATARI +static int sound_set_bass(int bass) +{ + return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50); +} +#endif /* CONFIG_ATARI */ + + +static int sound_set_treble(int treble) +{ + return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50); +} + + +static long sound_copy_translate(const u_char *userPtr, + unsigned long userCount, + u_char frame[], long *frameUsed, + long frameLeft) +{ + long (*ct_func)(const u_char *, unsigned long, u_char *, long *, long) = NULL; + + switch (sound.soft.format) { + case AFMT_MU_LAW: + ct_func = sound.trans->ct_ulaw; + break; + case AFMT_A_LAW: + ct_func = sound.trans->ct_alaw; + break; + case AFMT_S8: + ct_func = sound.trans->ct_s8; + break; + case AFMT_U8: + ct_func = sound.trans->ct_u8; + break; + case AFMT_S16_BE: + ct_func = sound.trans->ct_s16be; + break; + case AFMT_U16_BE: + ct_func = sound.trans->ct_u16be; + break; + case AFMT_S16_LE: + ct_func = sound.trans->ct_s16le; + break; + case AFMT_U16_LE: + ct_func = sound.trans->ct_u16le; + break; + } + if (ct_func) + return(ct_func(userPtr, userCount, frame, frameUsed, frameLeft)); + else + return(0); +} + + +/* + * /dev/mixer abstraction + */ + + +#define RECLEVEL_VOXWARE_TO_GAIN(v) \ + ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20) +#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3) + + +static void mixer_init(void) +{ + mixer.busy = 0; + sound.treble = 0; + sound.bass = 0; + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + atari_microwire_cmd(MW_LM1992_VOLUME(0)); + sound.volume_left = 0; + atari_microwire_cmd(MW_LM1992_BALLEFT(0)); + sound.volume_right = 0; + atari_microwire_cmd(MW_LM1992_BALRIGHT(0)); + atari_microwire_cmd(MW_LM1992_TREBLE(0)); + atari_microwire_cmd(MW_LM1992_BASS(0)); + break; + case DMASND_FALCON: + sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8; + sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4; + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + sound.volume_left = 64; + sound.volume_right = 64; + custom.aud[0].audvol = sound.volume_left; + custom.aud[3].audvol = 1; /* For pseudo 14bit */ + custom.aud[1].audvol = sound.volume_right; + custom.aud[2].audvol = 1; /* For pseudo 14bit */ + sound.treble = 50; + break; +#endif /* CONFIG_AMIGA */ + } +} + + +static int mixer_open(int open_mode) +{ + if (mixer.busy) + return(-EBUSY); + mixer.busy = 1; + return(0); +} + + +static int mixer_release(void) +{ + mixer.busy = 0; + return(0); +} + + +static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + int data; + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_FALCON: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, SOUND_MASK_MIC)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC)); + case SOUND_MIXER_READ_CAPS: + return(IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_ATT_TO_VOXWARE(sound.volume_left) | + VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_MIC: + IOCTL_IN(arg, data); + tt_dmasnd.input_gain = + RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 | + RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff); + /* fall thru, return set value */ + case SOUND_MIXER_READ_MIC: + return(IOCTL_OUT(arg, + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) | + RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8)); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_SPEAKER: + { + int porta; + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } + } + break; + + case DMASND_TT: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, + SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS | + ((atari_mch_cookie >> 16) == ATARI_MCH_TT ? + SOUND_MASK_SPEAKER : 0))); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_DB_TO_VOXWARE(sound.volume_left) | + (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8))); + case SOUND_MIXER_READ_BASS: + return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass))); + case SOUND_MIXER_READ_TREBLE: + return(IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble))); + case SOUND_MIXER_READ_SPEAKER: + { + int porta; + if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) { + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = sound_ym.rd_data_reg_sel; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return(-EINVAL); + } + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_WRITE_BASS: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_bass(data))); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_treble(data))); + case SOUND_MIXER_WRITE_SPEAKER: + if ((atari_mch_cookie >> 16) == ATARI_MCH_TT) { + int porta; + IOCTL_IN(arg, data); + cli(); + sound_ym.rd_data_reg_sel = 14; + porta = (sound_ym.rd_data_reg_sel & ~0x40) | + (data < 50 ? 0x40 : 0); + sound_ym.wd_data = porta; + sti(); + return(IOCTL_OUT(arg, porta & 0x40 ? 0 : 100)); + } else + return(-EINVAL); + } + break; +#endif /* CONFIG_ATARI */ + +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + switch (cmd) { + case SOUND_MIXER_READ_DEVMASK: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE)); + case SOUND_MIXER_READ_RECMASK: + return(IOCTL_OUT(arg, 0)); + case SOUND_MIXER_READ_STEREODEVS: + return(IOCTL_OUT(arg, SOUND_MASK_VOLUME)); + case SOUND_MIXER_READ_VOLUME: + return(IOCTL_OUT(arg, + VOLUME_AMI_TO_VOXWARE(sound.volume_left) | + VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8)); + case SOUND_MIXER_WRITE_VOLUME: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_volume(data))); + case SOUND_MIXER_READ_TREBLE: + return(IOCTL_OUT(arg, sound.treble)); + case SOUND_MIXER_WRITE_TREBLE: + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_treble(data))); + } + break; +#endif /* CONFIG_AMIGA */ + } + + return(-EINVAL); +} + + + +/* + * Sound queue stuff, the heart of the driver + */ + + +static void sq_init(int numBufs, int bufSize, char **buffers) +{ + sq.max_count = numBufs; + sq.block_size = bufSize; + sq.buffers = buffers; + + sq.front = sq.count = 0; + sq.rear = -1; + sq.write_queue = sq.open_queue = sq.sync_queue = 0; + sq.busy = 0; + sq.syncing = 0; + + sq.playing = 0; + +#ifdef CONFIG_ATARI + sq.ignore_int = 0; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + sq.block_size_half = sq.block_size>>1; + sq.block_size_quarter = sq.block_size_half>>1; +#endif /* CONFIG_AMIGA */ + + sound_silence(); + + /* whatever you like as startup mode for /dev/dsp, + * (/dev/audio hasn't got a startup mode). note that + * once changed a new open() will *not* restore these! + */ + sound.dsp.format = AFMT_S8; + sound.dsp.stereo = 0; + sound.dsp.size = 8; + + /* set minimum rate possible without expanding */ + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + sound.dsp.speed = 6258; + break; + case DMASND_FALCON: + sound.dsp.speed = 8195; + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + sound.dsp.speed = 8000; + break; +#endif /* CONFIG_AMIGA */ + } + + /* before the first open to /dev/dsp this wouldn't be set */ + sound.soft = sound.dsp; + sound.hard = sound.dsp; +} + + +static void sq_play(void) +{ + (*sound.mach.play)(); +} + + +/* ++TeSche: radically changed this one too */ + +static long sq_write(const char *src, unsigned long uLeft) +{ + long uWritten = 0; + u_char *dest; + long uUsed, bUsed, bLeft; + + /* ++TeSche: Is something like this necessary? + * Hey, that's an honest question! Or does any other part of the + * filesystem already checks this situation? I really don't know. + */ + if (uLeft == 0) + return(0); + + /* The interrupt doesn't start to play the last, incomplete frame. + * Thus we can append to it without disabling the interrupts! (Note + * also that sq.rear isn't affected by the interrupt.) + */ + + if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) { + dest = sq_block_address(sq.rear); + bUsed = sq.rear_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + sq.rear_size = bUsed; + } + + do { + while (sq.count == sq.max_count) { + sq_play(); + if (NON_BLOCKING(sq.open_mode)) + return(uWritten > 0 ? uWritten : -EAGAIN); + SLEEP(sq.write_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return(uWritten > 0 ? uWritten : -EINTR); + } + + /* Here, we can avoid disabling the interrupt by first + * copying and translating the data, and then updating + * the sq variables. Until this is done, the interrupt + * won't see the new frame and we can work on it + * undisturbed. + */ + + dest = sq_block_address((sq.rear+1) % sq.max_count); + bUsed = 0; + bLeft = sq.block_size; + uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft); + src += uUsed; + uWritten += uUsed; + uLeft -= uUsed; + if (bUsed) { + sq.rear = (sq.rear+1) % sq.max_count; + sq.rear_size = bUsed; + sq.count++; + } + } while (bUsed); /* uUsed may have been 0 */ + + sq_play(); + + return(uWritten); +} + + +static int sq_open(int open_mode) +{ + if (sq.busy) { + if (NON_BLOCKING(open_mode)) + return(-EBUSY); + while (sq.busy) { + SLEEP(sq.open_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) + return(-EINTR); + } + } + sq.open_mode = open_mode; + sq.busy = 1; +#ifdef CONFIG_ATARI + sq.ignore_int = 1; +#endif /* CONFIG_ATARI */ + return(0); +} + + +static void sq_reset(void) +{ + sound_silence(); + sq.playing = 0; + sq.count = 0; + sq.front = (sq.rear+1) % sq.max_count; +} + + +static int sq_sync(void) +{ + int rc = 0; + + sq.syncing = 1; + sq_play(); /* there may be an incomplete frame waiting */ + + while (sq.playing) { + SLEEP(sq.sync_queue, ONE_SECOND); + if (SIGNAL_RECEIVED) { + /* While waiting for audio output to drain, an interrupt occurred. + Stop audio output immediately and clear the queue. */ + sq_reset(); + rc = -EINTR; + break; + } + } + + sq.syncing = 0; + return(rc); +} + + +static int sq_release(void) +{ + int rc = 0; + if (sq.busy) { + rc = sq_sync(); + sq.busy = 0; + WAKE_UP(sq.open_queue); + /* Wake up a process waiting for the queue being released. + Note: There may be several processes waiting for a call to open() + returning. */ + } + return(rc); +} + + + +/* + * /dev/sndstat + */ + + +static void state_init(void) +{ + state.busy = 0; +} + + +/* state.buf should not overflow! */ + +static int state_open(int open_mode) +{ + char *buffer = state.buf, *mach = ""; + int len = 0; + + if (state.busy) + return(-EBUSY); + + state.ptr = 0; + state.busy = 1; + + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + case DMASND_FALCON: + mach = "Atari "; + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + mach = "Amiga "; + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); + + len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); + switch (sound.soft.format) { + case AFMT_MU_LAW: + len += sprintf(buffer+len, " (mu-law)"); + break; + case AFMT_A_LAW: + len += sprintf(buffer+len, " (A-law)"); + break; + case AFMT_U8: + len += sprintf(buffer+len, " (unsigned 8 bit)"); + break; + case AFMT_S8: + len += sprintf(buffer+len, " (signed 8 bit)"); + break; + case AFMT_S16_BE: + len += sprintf(buffer+len, " (signed 16 bit big)"); + break; + case AFMT_U16_BE: + len += sprintf(buffer+len, " (unsigned 16 bit big)"); + break; + case AFMT_S16_LE: + len += sprintf(buffer+len, " (signed 16 bit little)"); + break; + case AFMT_U16_LE: + len += sprintf(buffer+len, " (unsigned 16 bit little)"); + break; + } + len += sprintf(buffer+len, "\n"); + len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", + sound.soft.speed, sound.hard.speed); + len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", + sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono"); + switch (sound.mach.type) { +#ifdef CONFIG_ATARI + case DMASND_TT: + len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n", + sound.volume_right); + len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n", + sound.bass); + len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n", + sound.treble); + break; + case DMASND_FALCON: + len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n", + sound.volume_right); + break; +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case DMASND_AMIGA: + len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n", + sound.volume_left); + len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", + sound.volume_right); + break; +#endif /* CONFIG_AMIGA */ + } + len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d\n", + sq.block_size, sq.max_count); + len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count, + sq.rear_size); + len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n", + sq.playing, sq.syncing); + state.len = len; + return(0); +} + + +static int state_release(void) +{ + state.busy = 0; + return(0); +} + + +static long state_read(char *dest, unsigned long count) +{ + int n = state.len-state.ptr; + if (n > count) + n = count; + if (n <= 0) + return(0); + copy_to_user(dest, &state.buf[state.ptr], n); + state.ptr += n; + return(n); +} + + + +/*** High level stuff ********************************************************/ + + +static int sound_open(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev) & 0x0f; + int rc = 0; + + switch (dev) { + case SND_DEV_STATUS: + rc = state_open(file->f_flags); + break; + case SND_DEV_CTL: + rc = mixer_open(file->f_flags); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + rc = sq_open(file->f_flags); + if (rc == 0) { + sound.minDev = dev; + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_init(); + if (dev == SND_DEV_AUDIO) { + sound_set_speed(8000); + sound_set_stereo(0); + sound_set_format(AFMT_MU_LAW); + } + } + break; + default: + rc = -ENXIO; + } +#ifdef MODULE + if (rc >= 0) + MOD_INC_USE_COUNT; +#endif + return(rc); +} + + +static int sound_fsync(struct inode *inode, struct file *filp) +{ + int dev = MINOR(inode->i_rdev) & 0x0f; + + switch (dev) { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return(0); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(sq_sync()); + default: + return(unknown_minor_dev("sound_fsync", dev)); + } +} + + +static void sound_release(struct inode *inode, struct file *file) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + state_release(); + break; + case SND_DEV_CTL: + mixer_release(); + break; + case SND_DEV_DSP: + case SND_DEV_AUDIO: + sq_release(); + sound.soft = sound.dsp; + sound.hard = sound.dsp; + sound_silence(); + break; + default: + unknown_minor_dev("sound_release", dev); + return; + } +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + + +static long long sound_lseek(struct inode *inode, struct file *file, + long long offset, int orig) +{ + return -ESPIPE; +} + + +static long sound_read(struct inode *inode, struct file *file, char *buf, + unsigned long count) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + return(state_read(buf, count)); + case SND_DEV_CTL: + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(-EPERM); + default: + return(unknown_minor_dev("sound_read", dev)); + } +} + + +static long sound_write(struct inode *inode, struct file *file, + const char *buf, unsigned long count) +{ + int dev = MINOR(inode->i_rdev); + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + case SND_DEV_CTL: + return(-EPERM); + case SND_DEV_DSP: + case SND_DEV_AUDIO: + return(sq_write(buf, count)); + default: + return(unknown_minor_dev("sound_write", dev)); + } +} + + +static int unknown_minor_dev(char *fname, int dev) +{ + /* printk("%s: Unknown minor device %d\n", fname, dev); */ + return(-ENXIO); +} + + +static int sound_ioctl(struct inode *inode, struct file *file, u_int cmd, + u_long arg) +{ + int dev = MINOR(inode->i_rdev); + u_long fmt; + int data; + + switch (dev & 0x0f) { + case SND_DEV_STATUS: + return(-EPERM); + case SND_DEV_CTL: + return(mixer_ioctl(inode, file, cmd, arg)); + case SND_DEV_AUDIO: + case SND_DEV_DSP: + switch (cmd) { + case SNDCTL_DSP_RESET: + sq_reset(); + return(0); + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: + return(sound_fsync(inode, file)); + + /* ++TeSche: before changing any of these it's probably wise to + * wait until sound playing has settled down + */ + case SNDCTL_DSP_SPEED: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_speed(data))); + case SNDCTL_DSP_STEREO: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_stereo(data))); + case SOUND_PCM_WRITE_CHANNELS: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_stereo(data-1)+1)); + case SNDCTL_DSP_SETFMT: + sound_fsync(inode, file); + IOCTL_IN(arg, data); + return(IOCTL_OUT(arg, sound_set_format(data))); + case SNDCTL_DSP_GETFMTS: + fmt = 0; + if (sound.trans) { + if (sound.trans->ct_ulaw) + fmt |= AFMT_MU_LAW; + if (sound.trans->ct_alaw) + fmt |= AFMT_A_LAW; + if (sound.trans->ct_s8) + fmt |= AFMT_S8; + if (sound.trans->ct_u8) + fmt |= AFMT_U8; + if (sound.trans->ct_s16be) + fmt |= AFMT_S16_BE; + if (sound.trans->ct_u16be) + fmt |= AFMT_U16_BE; + if (sound.trans->ct_s16le) + fmt |= AFMT_S16_LE; + if (sound.trans->ct_u16le) + fmt |= AFMT_U16_LE; + } + return(IOCTL_OUT(arg, fmt)); + case SNDCTL_DSP_GETBLKSIZE: + return(IOCTL_OUT(arg, 10240)); + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + break; + + default: + return(mixer_ioctl(inode, file, cmd, arg)); + } + break; + + default: + return(unknown_minor_dev("sound_ioctl", dev)); + } + return(-EINVAL); +} + + +static struct file_operations sound_fops = +{ + sound_lseek, + sound_read, + sound_write, + NULL, + NULL, /* select */ + sound_ioctl, + NULL, + sound_open, + sound_release, + sound_fsync +}; + + + +/*** Config & Setup **********************************************************/ + + +void soundcard_init(void) +{ + int has_sound = 0; + int i; + + switch (m68k_machtype) { +#ifdef CONFIG_ATARI + case MACH_ATARI: + if (ATARIHW_PRESENT(PCM_8BIT)) { + if (ATARIHW_PRESENT(CODEC)) + sound.mach = machFalcon; + else if (ATARIHW_PRESENT(MICROWIRE)) + sound.mach = machTT; + else + break; + if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0) + has_sound = 1; + else + printk("DMA sound driver: Timer A interrupt already in use\n"); + } + break; + +#endif /* CONFIG_ATARI */ +#ifdef CONFIG_AMIGA + case MACH_AMIGA: + if (AMIGAHW_PRESENT(AMI_AUDIO)) { + sound.mach = machAmiga; + has_sound = 1; + } + break; +#endif /* CONFIG_AMIGA */ + } + if (!has_sound) + return; + + /* Set up sound queue, /dev/audio and /dev/dsp. */ + sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL); + if (!sound_buffers) { +out_of_memory: + printk("DMA sound driver: Not enough buffer memory, driver disabled!\n"); + return; + } + for (i = 0; i < numBufs; i++) { + sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL); + if (!sound_buffers[i]) { + while (i--) + sound.mach.dma_free (sound_buffers[i], bufSize << 10); + kfree (sound_buffers); + sound_buffers = 0; + goto out_of_memory; + } + } + +#ifndef MODULE + /* Register driver with the VFS. */ + register_chrdev(SOUND_MAJOR, "sound", &sound_fops); +#endif + + sq_init(numBufs, bufSize << 10, sound_buffers); + + /* Set up /dev/sndstat. */ + state_init(); + + /* Set up /dev/mixer. */ + mixer_init(); + + if (!sound.mach.irqinit()) { + printk("DMA sound driver: Interrupt initialization failed\n"); + return; + } +#ifdef MODULE + irq_installed = 1; +#endif + + printk("DMA sound driver installed, using %d buffers of %dk.\n", numBufs, + bufSize); + + return; +} + +void sound_setup(char *str, int *ints) +{ + /* ++Martin: stub, could possibly be merged with soundcard.c et al later */ +} + + +#define MAXARGS 8 /* Should be sufficient for now */ + +void dmasound_setup(char *str, int *ints) +{ + /* check the bootstrap parameter for "dmasound=" */ + + switch (ints[0]) { + case 3: + if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) + printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius); + else + catchRadius = ints[3]; + /* fall through */ + case 2: + if (ints[1] < MIN_BUFFERS) + printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs); + else + numBufs = ints[1]; + if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE) + printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize); + else + bufSize = ints[2]; + break; + case 0: + break; + default: + printk("dmasound_setup: illegal number of arguments\n"); + } +} + + +#ifdef MODULE + +static int dmasound[MAXARGS] = { 0 }; + +int init_module(void) +{ + int err, i = 0; + int ints[MAXARGS+1]; + + while (i < MAXARGS && dmasound[i]) + ints[i + 1] = dmasound[i++]; + ints[0] = i; + + if (i) + dmasound_setup("dmasound=", ints); + + err = register_chrdev(SOUND_MAJOR, "sound", &sound_fops); + if (err) { + printk("dmasound: driver already loaded/included in kernel\n"); + return err; + } + chrdev_registered = 1; + soundcard_init(); + + return 0; +} + + +void cleanup_module(void) +{ + int i; + + if (MOD_IN_USE) + return; + + if (chrdev_registered) + unregister_chrdev(SOUND_MAJOR, "sound"); + + if (irq_installed) { + sound_silence(); + sound.mach.irqcleanup(); + } + + if (sound_buffers) { + for (i = 0; i < numBufs; i++) + sound.mach.dma_free(sound_buffers[i], bufSize << 10); + kfree(sound_buffers); + } +} + +#endif /* MODULE */ diff --git a/drivers/sound/dmasound.h b/drivers/sound/dmasound.h new file mode 100644 index 000000000000..fec3ad84eba3 --- /dev/null +++ b/drivers/sound/dmasound.h @@ -0,0 +1,36 @@ + +/* linux/drivers/sound/dmasound.h */ + +/* + * Minor numbers for the sound driver. + * + * Unfortunately Creative called the codec chip of SB as a DSP. For this + * reason the /dev/dsp is reserved for digitized audio use. There is a + * device for true DSP processors but it will be called something else. + * In v3.0 it's /dev/sndproc but this could be a temporary solution. + */ + +#define SND_NDEVS 256 /* Number of supported devices */ +#define SND_DEV_CTL 0 /* Control port /dev/mixer */ +#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM + synthesizer and MIDI output) */ +#define SND_DEV_MIDIN 2 /* Raw midi access */ +#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ +#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ +#define SND_DEV_STATUS 6 /* /dev/sndstat */ +/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ +#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ +#define SND_DEV_PSS SND_DEV_SNDPROC + +#define DSP_DEFAULT_SPEED 8000 + +#define ON 1 +#define OFF 0 + +#define MAX_AUDIO_DEV 5 +#define MAX_MIXER_DEV 2 +#define MAX_SYNTH_DEV 3 +#define MAX_MIDI_DEV 6 +#define MAX_TIMER_DEV 3 diff --git a/drivers/sound/gus_card.c b/drivers/sound/gus_card.c index b844e43639e7..1c8881684ca2 100644 --- a/drivers/sound/gus_card.c +++ b/drivers/sound/gus_card.c @@ -123,7 +123,7 @@ gusintr (int irq, void *dev_id, struct pt_regs *dummy) #ifdef CONFIG_GUSMAX if (have_gus_max) - ad1848_interrupt (irq, NULL, NULL); + adintr (irq, NULL, NULL); #endif while (1) diff --git a/drivers/sound/gus_midi.c b/drivers/sound/gus_midi.c index 61c6440075c9..9fc38fc88010 100644 --- a/drivers/sound/gus_midi.c +++ b/drivers/sound/gus_midi.c @@ -248,6 +248,7 @@ gus_midi_init (void) std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &gus_midi_operations; + sequencer_init (); return; } diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 5c579b8468be..8c1523750d7b 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -21,7 +21,7 @@ #if defined(CONFIG_GUSHW) -#define GUS_BANK_SIZE (256*1024) +#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) #define MAX_SAMPLE 150 #define MAX_PATCH 256 @@ -73,6 +73,7 @@ extern int gus_pnp_flag; static int gus_dma2 = -1; static int dual_dma_mode = 0; static long gus_mem_size = 0; +static long gus_rom_size = 0; static long free_mem_ptr = 0; static int gus_busy = 0; static int gus_no_dma = 0; @@ -84,6 +85,7 @@ static int recording_active = 0; static int only_read_access = 0; static int only_8_bits = 0; +int iw_mode = 0; int gus_wave_volume = 60; int gus_pcm_volume = 80; int have_gus_max = 0; @@ -105,6 +107,8 @@ static int active_device = 0; static int gus_audio_speed; static int gus_audio_channels; static int gus_audio_bits; +static int gus_audio_bsize; +static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ static struct wait_queue *dram_sleeper = NULL; static volatile struct snd_wait dram_sleep_flag = @@ -113,7 +117,7 @@ static volatile struct snd_wait dram_sleep_flag = /* * Variables and buffers for PCM output */ -#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* Don't change */ +#define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */ static int pcm_bsize, pcm_nblk, pcm_banksize; static int pcm_datasize[MAX_PCM_BUFFERS]; @@ -356,14 +360,22 @@ gus_write_addr (int reg, unsigned long address, int frac, int is16bit) cli (); if (is16bit) { - /* - * Special processing required for 16 bit patches - */ + if (iw_mode) + { + /* Interwave spesific address translations */ + address >>= 1; + } + else + { + /* + * Special processing required for 16 bit patches + */ - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } } gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); @@ -389,6 +401,8 @@ gus_select_voice (int voice) static void gus_select_max_voices (int nvoices) { + if (iw_mode) + nvoices = 32; if (nvoices < 14) nvoices = 14; if (nvoices > 32) @@ -430,7 +444,11 @@ gus_voice_freq (unsigned long freq) unsigned long divisor = freq_div_table[nr_voices - 14]; unsigned short fc; - fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); + /* Interwave plays at 44100 Hz with any number of voices */ + if (iw_mode) + fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100); + else + fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); fc = fc << 1; gus_write16 (0x01, fc); @@ -851,6 +869,8 @@ gus_initialize (void) gus_read8 (0x0f); /* Clear pending IRQs */ + if (iw_mode) + gus_write8 (0x19, gus_read8 (0x19) | 0x01); restore_flags (flags); } @@ -1022,10 +1042,10 @@ pnp_mem_init (void) */ gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits); -/* - * Return the chip back to GUS compatible mode. - */ - gus_write8 (0x19, gus_read8 (0x19) & ~0x01); +/* Leave the chip into enhanced mode. Disable LFO */ + gus_mem_size = total; + iw_mode = 1; + gus_write8 (0x19, (gus_read8 (0x19) | 0x01) & ~0x02); } int @@ -1065,6 +1085,8 @@ gus_wave_detect (int baseaddr) if (gus_pnp_flag) pnp_mem_init (); + if (iw_mode) + return 1; /* See if there is first block there.... */ gus_poke (0L, 0xaa); @@ -1479,6 +1501,9 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume) voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; + if (iw_mode) + gus_write8 (0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ + if (voices[voice].mode & WAVE_ENVELOPES) { int i; @@ -1897,7 +1922,7 @@ guswave_load_patch (int dev, int format, const char *addr, for (i = 0; i < blk_sz; i++) { - get_user (data, (unsigned char *) &((addr)[sizeof_patch + i])); + get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); if (patch.mode & WAVE_UNSIGNED) if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) data ^= 0x80; /* Convert to signed */ @@ -1934,17 +1959,37 @@ guswave_load_patch (int dev, int format, const char *addr, * Set the DRAM address for the wave data */ - address = target; - - if (audio_devs[gus_devnum]->dmap_out->dma > 3) + if (iw_mode) { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); + /* Different address translation in enhanced mode */ + + unsigned char hi; + + if (gus_dma > 4) + address = target >> 1; /* Convert to 16 bit word address */ + else + address = target; + + hi = (unsigned char) ((address >> 16) & 0xf0); + hi += (unsigned char) (address & 0x0f); + + gus_write16 (0x42, (address >> 4) & 0xffff); /* DMA address (low) */ + gus_write8 (0x50, hi); } + else + { + address = target; + + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + } /* * Start the DMA transfer @@ -2280,6 +2325,7 @@ gus_audio_reset (int dev) } } +static int saved_iw_mode; /* A hack hack hack */ static int gus_audio_open (int dev, int mode) @@ -2300,6 +2346,13 @@ gus_audio_open (int dev, int mode) gus_reset (); reset_sample_memory (); gus_select_max_voices (14); + saved_iw_mode = iw_mode; + if (iw_mode) + { + /* There are some problems with audio in enhanced mode so disable it */ + gus_write8 (0x19, gus_read8 (0x19) & ~0x01); /* Disable enhanced mode */ + iw_mode = 0; + } pcm_active = 0; dma_active = 0; @@ -2322,6 +2375,7 @@ gus_audio_open (int dev, int mode) static void gus_audio_close (int dev) { + iw_mode = saved_iw_mode; gus_reset (); gus_busy = 0; pcm_opened = 0; @@ -2428,7 +2482,7 @@ play_next_pcm_block (void) gus_voice_volume (1530 + (25 * gus_pcm_volume)); gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - gus_write_addr (0x0a, dram_loc, 0, is16bits); /* Starting position */ + gus_write_addr (0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ gus_write_addr (0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ if (chn != 0) @@ -2437,30 +2491,11 @@ play_next_pcm_block (void) } if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, + gus_write_addr (0x04, dram_loc + pcm_bsize - 1, 0, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ - if (pcm_datasize[this_one] != pcm_bsize) - { - /* - * Incompletely filled block. Possibly the last one. - */ - if (chn == 0) - { - mode[chn] &= ~0x08; /* Disable looping */ - mode[chn] |= 0x20; /* Enable IRQ at the end */ - voices[0].loop_irq_mode = LMODE_PCM_STOP; - ramp_mode[chn] = 0x03; /* No rollover bit */ - } - else - { - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], - 0, is16bits); /* Loop end location */ - mode[chn] &= ~0x08; /* Disable looping */ - } - } restore_flags (flags); } @@ -2471,6 +2506,8 @@ play_next_pcm_block (void) cli (); gus_select_voice (chn); gus_write8 (0x0d, ramp_mode[chn]); + if (iw_mode) + gus_write8 (0x15, 0x00); /* Reset voice deactivate bit of SMSI */ gus_voice_on (mode[chn]); restore_flags (flags); } @@ -2549,7 +2586,7 @@ gus_transfer_output_block (int dev, unsigned long buf, */ dma_active = 1; /* DMA started. There is a unacknowledged buffer */ active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize)) + if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) { play_next_pcm_block (); } @@ -2566,14 +2603,59 @@ gus_transfer_output_block (int dev, unsigned long buf, restore_flags (flags); } +static void +gus_uninterleave8 (char *buf, int l) +{ +/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ + int i, p = 0, halfsize = l / 2; + char *buf2 = buf + halfsize, *src = bounce_buf; + + memcpy (bounce_buf, buf, l); + + for (i = 0; i < halfsize; i++) + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } +} + +static void +gus_uninterleave16 (short *buf, int l) +{ +/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ + int i, p = 0, halfsize = l / 2; + short *buf2 = buf + halfsize, *src = (short *) bounce_buf; + + memcpy (bounce_buf, (char *) buf, l * 2); + + for (i = 0; i < halfsize; i++) + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } +} + static void gus_audio_output_block (int dev, unsigned long buf, int total_count, int intrflag) { + struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + + dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT; + pcm_current_buf = buf; pcm_current_count = total_count; pcm_current_intrflag = intrflag; pcm_current_dev = dev; + if (gus_audio_channels == 2) + { + char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); + + if (gus_audio_bits == 8) + gus_uninterleave8 (b, total_count); + else + gus_uninterleave16 ((short *) b, total_count / 2); + } gus_transfer_output_block (dev, buf, total_count, intrflag, 0); } @@ -2587,7 +2669,7 @@ gus_audio_start_input (int dev, unsigned long buf, int count, save_flags (flags); cli (); - /* DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); */ + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); mode = 0xa0; /* DMA IRQ enabled, invert MSB */ @@ -2607,6 +2689,8 @@ gus_audio_prepare_for_input (int dev, int bsize, int bcount) { unsigned int rate; + gus_audio_bsize = bsize; + audio_devs[dev]->dmap_in->flags |= DMA_NODMA; rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ @@ -2627,6 +2711,7 @@ gus_audio_prepare_for_output (int dev, int bsize, int bcount) long mem_ptr, mem_size; + audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; mem_ptr = 0; mem_size = gus_mem_size / gus_audio_channels; @@ -2636,7 +2721,7 @@ gus_audio_prepare_for_output (int dev, int bsize, int bcount) pcm_bsize = bsize / gus_audio_channels; pcm_head = pcm_tail = pcm_qlen = 0; - pcm_nblk = MAX_PCM_BUFFERS; + pcm_nblk = 2; /* MAX_PCM_BUFFERS; */ if ((pcm_bsize * pcm_nblk) > mem_size) pcm_nblk = mem_size / pcm_bsize; @@ -2658,56 +2743,6 @@ gus_local_qlen (int dev) return pcm_qlen; } -static void -gus_copy_from_user (int dev, char *localbuf, int localoffs, - const char *userbuf, int useroffs, int len) -{ - if (gus_audio_channels == 1) - { - copy_from_user (&localbuf[localoffs], &(userbuf)[useroffs], len); - } - else if (gus_audio_bits == 8) - { - int in_left = useroffs; - int in_right = useroffs + 1; - char *out_left, *out_right; - int i; - - len /= 2; - localoffs /= 2; - out_left = localbuf + localoffs; - out_right = out_left + pcm_bsize; - - for (i = 0; i < len; i++) - { - get_user (*out_left++, (unsigned char *) &((userbuf)[in_left])); - in_left += 2; - get_user (*out_right++, (unsigned char *) &((userbuf)[in_right])); - in_right += 2; - } - } - else - { - int in_left = useroffs; - int in_right = useroffs + 2; - short *out_left, *out_right; - int i; - - len /= 4; - localoffs /= 4; - - out_left = ((short *) localbuf) + localoffs; - out_right = out_left + (pcm_bsize / 2); - - for (i = 0; i < len; i++) - { - get_user (*out_left++, (unsigned short *) &((userbuf)[in_left])); - in_left += 4; - get_user (*out_right++, (unsigned short *) &((userbuf)[in_right])); - in_right += 4; - } - } -} static struct audio_driver gus_audio_driver = { @@ -2720,7 +2755,7 @@ static struct audio_driver gus_audio_driver = gus_audio_prepare_for_output, gus_audio_reset, gus_local_qlen, - gus_copy_from_user + NULL }; static void @@ -3218,7 +3253,10 @@ gus_wave_init (struct address_info *hw_config) else { voice_alloc = &guswave_operations.alloc; + if (iw_mode) + guswave_operations.id = "IWAVE"; synth_devs[num_synths++] = &guswave_operations; + sequencer_init (); #ifdef CONFIG_SEQUENCER gus_tmr_install (gus_base + 8); #endif @@ -3237,15 +3275,16 @@ gus_wave_init (struct address_info *hw_config) &gus_audio_driver, sizeof (struct audio_driver), NEEDS_RESTART | - ((dma2 != dma && dma2 != -1) ? - DMA_DUPLEX : 0), + ((!iw_mode && dma2 != dma && dma2 != -1) ? + DMA_DUPLEX : 0), AFMT_U8 | AFMT_S16_LE, NULL, dma, dma2)) < 0) return; - audio_devs[gus_devnum]->min_fragment = 9; + audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ + audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */ audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; } @@ -3347,7 +3386,6 @@ do_loop_irq (int voice) pcm_active = 0; /* Signal to the play_next_pcm_block routine */ case LMODE_PCM: { - int flag; /* 0 or 2 */ pcm_qlen--; pcm_head = (pcm_head + 1) % pcm_nblk; @@ -3367,20 +3405,11 @@ do_loop_irq (int voice) } /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. */ - if (dma_active) - { - if (pcm_qlen == 0) - flag = 1; /* Underflow */ - else - flag = 0; - dma_active = 0; - } - else - flag = 2; /* Just notify the dmabuf.c */ - DMAbuf_outputintr (gus_devnum, flag); + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr (gus_devnum, 0); } break; @@ -3413,9 +3442,9 @@ do_volume_irq (int voice) switch (mode) { - case VMODE_HALT: /* - * Decay phase finished - */ + case VMODE_HALT: /* Decay phase finished */ + if (iw_mode) + gus_write8 (0x15, 0x02); /* Set voice deactivate bit of SMSI */ restore_flags (flags); gus_voice_init (voice); break; @@ -3523,13 +3552,12 @@ guswave_dma_irq (void) gus_write8 (0x41, 0); /* Disable GF1 DMA */ if (pcm_qlen < pcm_nblk) { - int flag = (1 - dma_active) * 2; /* 0 or 2 */ - - if (pcm_qlen == 0) - flag = 1; /* Underrun */ dma_active = 0; if (gus_busy) - DMAbuf_outputintr (gus_devnum, flag); + { + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr (gus_devnum, 0); + } } break; diff --git a/drivers/sound/lowlevel/Config.tmpl b/drivers/sound/lowlevel/Config.tmpl index ff107a819f0f..a3864b96f7fd 100644 --- a/drivers/sound/lowlevel/Config.tmpl +++ b/drivers/sound/lowlevel/Config.tmpl @@ -32,7 +32,7 @@ if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then fi fi - if [ "$CONFIG_MIDI" = "y" ]; then + if [ "$CONFIG_MPU401" = "y" ]; then bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then comment 'Audio Excel DSP 16 [MPU-401]' diff --git a/drivers/sound/lowlevel/aci.c b/drivers/sound/lowlevel/aci.c index 657fa697dbb1..7599d5a6ce38 100644 --- a/drivers/sound/lowlevel/aci.c +++ b/drivers/sound/lowlevel/aci.c @@ -22,9 +22,9 @@ * First version written. * 1995-12-31 Markus Kuhn * Second revision, general code cleanup. - * 1997-05-16 Hannu Savolainen + * 1996-05-16 Hannu Savolainen * Integrated with other parts of the driver. - * 1997-05-28 Markus Kuhn + * 1996-05-28 Markus Kuhn * Initialize CS4231A mixer, make ACI first mixer, * use new private mixer API for solo mode. */ diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index 8c416a632d2f..6fa104905ad6 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -333,7 +333,7 @@ maui_load_patch (int dev, int format, const char *addr, { unsigned char data; - get_user (data, (unsigned char *) &((addr)[hdr_size + i])); + get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); if (i == 0 && !(data & 0x80)) return -EINVAL; diff --git a/drivers/sound/midi_synth.c b/drivers/sound/midi_synth.c index 512fc2bb7336..454fc7471928 100644 --- a/drivers/sound/midi_synth.c +++ b/drivers/sound/midi_synth.c @@ -537,7 +537,7 @@ midi_synth_load_patch (int dev, int format, const char *addr, { unsigned char data; - get_user (data, (unsigned char *) &((addr)[hdr_size + i])); + get_user (*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i])); eox_seen = (i > 0 && data & 0x80); /* End of sysex */ diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index cfe2879d1e4e..c4271e87b102 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -12,6 +12,7 @@ */ #include +#define MIDIBUF_C #include "sound_config.h" diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index 7c611100312a..5a5e90e27b1e 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -1183,6 +1183,7 @@ attach_mpu401 (struct address_info *hw_config) irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; + sequencer_init (); } static int diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index 28ce6da15c1f..5c71dc585ec1 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -112,6 +112,7 @@ opl3_ioctl (int dev, struct sbi_instrument ins; memcpy ((char *) &ins, (&((char *) arg)[0]), sizeof (ins)); + printk("Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n"); if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { @@ -1168,6 +1169,7 @@ opl3_init (int ioaddr, int *osp) opl3_operations.info = &devc->fm_info; synth_devs[num_synths++] = &opl3_operations; + sequencer_init (); devc->v_alloc = &opl3_operations.alloc; devc->chn_info = &opl3_operations.chn_info[0]; diff --git a/drivers/sound/os.h b/drivers/sound/os.h index 4ab565960d6d..4b1abd06e6be 100644 --- a/drivers/sound/os.h +++ b/drivers/sound/os.h @@ -7,6 +7,7 @@ #undef NO_INLINE_ASM #define SHORT_BANNERS #define MANUAL_PNP +#undef DO_TIMINGS #ifdef MODULE #define __NO_VERSION__ @@ -20,6 +21,7 @@ #define LINUX21X #endif +#ifdef __KERNEL__ #include #include #include @@ -37,6 +39,10 @@ #include #include #include +#include +#include +#else +#endif #include diff --git a/drivers/sound/pas2_card.c b/drivers/sound/pas2_card.c index a162ce9932b2..b109b22f1417 100644 --- a/drivers/sound/pas2_card.c +++ b/drivers/sound/pas2_card.c @@ -283,7 +283,7 @@ detect_pas_hw (struct address_info *hw_config) foo = board_id ^ 0xe0; pas_write (foo, 0x0B8B); - foo = inb (0x0B8B); + foo = pas_read (0x0B8B); pas_write (board_id, 0x0B8B); if (board_id != foo) diff --git a/drivers/sound/pas2_midi.c b/drivers/sound/pas2_midi.c index b9dce0b41665..05a509f913bc 100644 --- a/drivers/sound/pas2_midi.c +++ b/drivers/sound/pas2_midi.c @@ -236,6 +236,7 @@ pas_midi_init (void) std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &pas_midi_operations; + sequencer_init (); } void diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index 87446e147c20..e082fc9cce9f 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -55,12 +55,12 @@ pcm_set_speed (int arg) if (pcm_channels & 2) { foo = (596590 + (arg / 2)) / arg; - arg = 596590 / foo; + arg = (596590 + (foo / 2)) / foo; } else { foo = (1193180 + (arg / 2)) / arg; - arg = 1193180 / foo; + arg = (1193180 + (foo / 2)) / foo; } pcm_speed = arg; diff --git a/drivers/sound/pnp.c b/drivers/sound/pnp.c new file mode 100644 index 000000000000..9e07fa3aba46 --- /dev/null +++ b/drivers/sound/pnp.c @@ -0,0 +1,36 @@ +/* + * sound/pnp.c - Temporary kludge for PnP soundcards. + * + * Copyright by Hannu Savolainen 1997. + * + * This file is just a temporary solution to be used with + * PnP soundcards until final kernel PnP support gets ready. + * The code contained in this file is largely untested and + * may cause failures in some systems. In particular it will + * cause troubles with other PnP ISA cards such as network cards. + * This file is also incompatible with (future) PnP support in kernel. + * + * For the above reasons I don't want this file to be widely distributed. + * You have permission to use this file with this particular sound driver + * and only for your own evaluation purposes. Any other use of this file + * or parts of it requires written permission by the author. + */ +extern int pnp_trace; +int pnp_trace_io = 0; + +#define UDELAY(x) udelay(x) + +#ifdef TEST_PNP +#include "pnp.h" +#include +#include +#define printk printf + +#define MALLOC(sz) malloc(sz) + +unsigned char res[10000]; +int rp; + +#else +#include "sound_config.h" +#endif diff --git a/drivers/sound/pnp.h b/drivers/sound/pnp.h new file mode 100644 index 000000000000..eb18c13ebd9d --- /dev/null +++ b/drivers/sound/pnp.h @@ -0,0 +1,112 @@ +#ifndef _PNP_H_ +#define _PNP_H_ + +#define MAX_PNP_CARDS 16 + +#define PNP_DEVID(a, b, c, id) \ + ((a-'@')<<26) | ((b-'@')<<21) | ((c-'@') << 16) | (id&0xffff) + +#define NO_PORT 0 +#define NO_IRQ 0 +#define NO_DMA 4 + +struct pnp_port_resource +{ + short range_min, range_max; + unsigned char align, len; +}; + +struct pnp_func + { + struct pnp_dev *dev; + unsigned long flags; + struct pnp_func *next; + int nports; + struct pnp_port_resource ports[8]; + int nirq; + unsigned short irq[2]; + int ndma; + unsigned char dma[2]; + }; + +struct pnp_dev + { + int key; /* A PnP device id identifying this device */ + char *name; /* ANSI identifier string */ + int devno; /* Logical device number within a card */ + int ncompat; /* Number of compatible device idents */ + int compat_keys[8]; /* List of PnP compatible device idents */ + struct pnp_card *card; /* Link to the card which holds this device */ + struct pnp_dev *next; /* Pointer to next logical device or NULL */ + + int nports, nirq, ndma; + + int nfunc; /* Number of dependent function records */ + struct pnp_func *functions; /* List of dependent functions */ + int driver; /* Driver signature or 0 */ + int preconfig; /* 1 if config has been set manully */ + + }; + +struct pnp_card + { + int key; /* Unique PnP device identifier */ + char *name; /* ANSI identifier string of the card */ + int csn; /* Card select number */ + + char pnp_version; + char vendor_version; + + int driven; /* 0=No driver assigned, */ + /* 1=Drivers assigned to some of logical devices */ + /* 2=Card and all of it's devices have a driver */ + int relocated; /* 0=Card is inactive, 1=card is up and running */ + + int ndevs; /* Number of logical devices on the card */ + struct pnp_dev *devices; /* Pointer to first function entry */ + }; + +typedef struct pnp_card_info { + struct pnp_card card; + char name[64]; +} pnp_card_info; + +extern int pnp_card_count; +extern struct pnp_card *pnp_cards[MAX_PNP_CARDS]; +extern struct pnp_dev *pnp_device_list; + +extern int pnp_trace; + +/* + * Callable functions + */ + +extern void pnp_init(void); /* Called by kernel during boot */ +extern void terminate_pnp(void); + +extern int pnp_connect(char *driver_name); +extern void pnp_disconnect(int driver_signature); + +/* + * pnp_get_descr() returns an ASCII desctription string for a device. + * The parameter is an compressed EISA identifier of the device/card. + */ +extern char *pnp_get_descr (int id); + +extern void pnp_enable_device(struct pnp_dev *dev, int state); +extern void pnp_set_port(struct pnp_dev *dev, int selec, unsigned short base); +extern void pnp_set_irq(struct pnp_dev *dev, int selec, unsigned short val); +extern void pnp_set_dma(struct pnp_dev *dev, int selec, unsigned short val); +extern unsigned short pnp_get_port(struct pnp_dev *dev, int selec); +extern unsigned short pnp_get_irq(struct pnp_dev *dev, int selec); +extern unsigned short pnp_get_dma(struct pnp_dev *dev, int selec); +extern int pnp_allocate_device(int driver_sig, struct pnp_dev *dev, int basemask, int irqmask, + int dmamask, int memmask); +extern void pnp_release_device(int driver_sig, struct pnp_dev *dev); +extern int pnp_asc2devid(char *name); +extern char *pnp_devid2asc(int id); +extern void pnp_dump_resources(void); +extern int pnp_device_status (struct pnp_dev *dev); +struct pnp_dev *pnp_get_next_device(int driver_sig, struct pnp_dev *prev); +unsigned char pnp_readreg (struct pnp_dev *dev, int reg); +#endif diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index b229549bb479..ba2f3be18ec1 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -105,6 +105,7 @@ typedef struct sb_devc { /* MIDI fields */ int my_mididev; int input_opened; + int midi_broken; void (*midi_input_intr) (int dev, unsigned char data); } sb_devc; diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 3faf6b690b04..bd9e05704e61 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -58,10 +58,7 @@ sb_dsp_command (sb_devc * devc, unsigned char val) int i; unsigned long limit; - limit = jiffies + HZ / 10; /* - * The timeout is 0.1 seconds - */ - + limit = jiffies + HZ / 10; /* Timeout */ /* * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes * called while interrupts are disabled. This means that the timer is @@ -173,7 +170,8 @@ sbintr (int irq, void *dev_id, struct pt_regs *dummy) break; default: - printk ("Sound Blaster: Unexpected interrupt\n"); + /* printk ("Sound Blaster: Unexpected interrupt\n"); */ + ; } /* * Acknowledge interrupts @@ -633,6 +631,7 @@ sb_dsp_detect (struct address_info *hw_config) for (i = 0; i < 10000; i++) inb (DSP_DATA_AVAIL); devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ + devc->model = MDL_AZTECH; } } } @@ -666,6 +665,7 @@ sb_dsp_init (struct address_info *hw_config) sb_devc *devc; int n; char name[100]; + extern int sb_be_quiet; /* * Check if we had detected a SB device earlier @@ -776,7 +776,7 @@ sb_dsp_init (struct address_info *hw_config) { devc->model = hw_config->card_subtype = MDL_SBPRO; if (hw_config->name == NULL) - hw_config->name = "Sound Blaster Pro"; + hw_config->name = "Sound Blaster Pro (8 BIT ONLY)"; } break; @@ -809,10 +809,33 @@ sb_dsp_init (struct address_info *hw_config) #endif if (hw_config->name == NULL) - hw_config->name = "Sound Blaster"; + hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)"; sprintf (name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); conf_printf (name, hw_config); + +/* + * Assuming that a soundcard is Sound Blaster (compatible) is the most common + * configuration error and the mother of all problems. Usually soundcards + * emulate SB Pro but in addition they have a 16 bit native mode which should be + * used in Unix. See Readme.cards for more information about configuring OSS/Free + * properly. + */ + if (devc->model <= MDL_SBPRO) + if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1. */ + { + printk ("This soundcard doesn't seem to be fully Sound Blaster Pro compatible.\n"); + printk ("Almost certainly there is another way to configure OSS so that\n"); + printk ("it works properly with OSS (for example in 16 bit mode).\n"); + } + else if (!sb_be_quiet && devc->model == MDL_SBPRO) + { + printk ("SB DSP version is just %d.%d which means that your card is\n", + devc->major, devc->minor); + printk ("several years old (8 bit only device)\n"); + printk ("or alternatively the sound driver is incorrectly configured.\n"); + } + hw_config->card_subtype = devc->model; last_devc = devc; /* For SB MPU detection */ diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 2bdeef1ba7eb..cffaafc7b2d7 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -52,6 +52,7 @@ sb_midi_open (int dev, int mode, restore_flags (flags); devc->irq_mode = IMODE_MIDI; + devc->midi_broken = 0; sb_dsp_reset (devc); @@ -96,9 +97,16 @@ sb_midi_out (int dev, unsigned char midi_byte) sb_devc *devc = midi_devs[dev]->devc; if (devc == NULL) - return -ENXIO; + return 1; + + if (devc->midi_broken) + return 1; - sb_dsp_command (devc, midi_byte); + if (!sb_dsp_command (devc, midi_byte)) + { + devc->midi_broken = 1; + return 1; + } return 1; } @@ -220,6 +228,7 @@ sb_dsp_midi_init (sb_devc * devc) midi_devs[num_midis]->converter->id = "SBMIDI"; num_midis++; + sequencer_init (); } #endif diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 6ffced88e5ba..14d2f24de7b8 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -24,6 +24,9 @@ static int sequencer_ok = 0; static struct sound_timer_operations *tmr; static int tmr_no = -1; /* Currently selected timer */ static int pending_timer = -1; /* For timer change operation */ +extern unsigned long seq_time; + +static int obsolete_api_used = 0; /* * Local counts for number of synth and MIDI devices. These are initialized @@ -56,7 +59,6 @@ static int midi_written[MAX_MIDI_DEV] = unsigned long prev_input_time = 0; int prev_event_time; -unsigned long seq_time = 0; #include "tuning.h" @@ -312,6 +314,9 @@ sequencer_write (int dev, struct fileinfo *file, const char *buf, int count) return -EINVAL; } ev_size = 4; + + if (event_rec[0] != SEQ_MIDIPUTC) + obsolete_api_used = 1; } if (event_rec[0] == SEQ_MIDIPUTC) @@ -498,11 +503,12 @@ alloc_voice (int dev, int chn, int note) static void seq_chn_voice_event (unsigned char *event_rec) { - unsigned char dev = event_rec[1]; - unsigned char cmd = event_rec[2]; - unsigned char chn = event_rec[3]; - unsigned char note = event_rec[4]; - unsigned char parm = event_rec[5]; +#define dev event_rec[1] +#define cmd event_rec[2] +#define chn event_rec[3] +#define note event_rec[4] +#define parm event_rec[5] + int voice = -1; if ((int) dev > max_synthdev) @@ -570,6 +576,11 @@ seq_chn_voice_event (unsigned char *event_rec) default:; } +#undef dev +#undef cmd +#undef chn +#undef note +#undef parm } @@ -1105,6 +1116,7 @@ sequencer_open (int dev, struct fileinfo *file) return -EBUSY; } sequencer_busy = 1; + obsolete_api_used = 0; restore_flags (flags); max_mididev = num_midis; @@ -1322,6 +1334,8 @@ sequencer_release (int dev, struct fileinfo *file) if (seq_mode == SEQ_2) tmr->close (tmr_no); + if (obsolete_api_used) + printk ("/dev/music: Obsolete (4 byte) API was used by this program\n"); sequencer_busy = 0; } @@ -1628,6 +1642,8 @@ sequencer_ioctl (int dev, struct fileinfo *file, break; case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SYNTH_REMOVESAMPLE: + case SNDCTL_SYNTH_CONTROL: { int err; @@ -1870,7 +1886,7 @@ note_to_freq (int note_num) */ int note, octave, note_freq; - int notes[] = + static int notes[] = { 261632, 277189, 293671, 311132, 329632, 349232, 369998, 391998, 415306, 440000, 466162, 493880 @@ -1937,6 +1953,8 @@ compute_finetune (unsigned long base_freq, int bend, int range, } semitones = bend / 100; + if (semitones > 99) + semitones = 99; cents = bend % 100; amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) @@ -1955,6 +1973,10 @@ sequencer_init (void) if (sequencer_ok) return; +#ifdef CONFIG_MIDI + MIDIbuf_init (); +#endif + queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * EV_SZ)); sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * EV_SZ; @@ -1971,7 +1993,7 @@ sequencer_init (void) sound_mem_sizes[sound_nblocks] = SEQ_MAX_QUEUE * IEV_SZ; if (sound_nblocks < 1024) sound_nblocks++;; - if (queue == NULL) + if (iqueue == NULL) { printk ("Sound: Can't allocate memory for sequencer input queue\n"); return; diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h index f5587cc3f9e6..8bb54fa9d337 100644 --- a/drivers/sound/sound_calls.h +++ b/drivers/sound/sound_calls.h @@ -10,7 +10,7 @@ int DMAbuf_rmchars(int dev, int buff_no, int c); int DMAbuf_start_output(int dev, int buff_no, int l); int DMAbuf_move_wrpointer(int dev, int l); /* int DMAbuf_ioctl(int dev, unsigned int cmd, caddr_t arg, int local); */ -void DMAbuf_init(void); +void DMAbuf_init(int dev, int dma1, int dma2); void DMAbuf_deinit(int dev); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); int DMAbuf_open_dma (int dev); @@ -20,7 +20,7 @@ void DMAbuf_outputintr(int dev, int underflow_flag); struct dma_buffparms; int DMAbuf_space_in_queue (int dev); int DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap); -int DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap); +int DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction); void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap); int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); void DMAbuf_start_devices(unsigned int devmask); @@ -52,7 +52,8 @@ int sequencer_open (int dev, struct fileinfo *file); void sequencer_release (int dev, struct fileinfo *file); int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); -int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig); +int sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); + void sequencer_init (void); void sequencer_timer(unsigned long dummy); int note_to_freq(int note_num); @@ -61,8 +62,6 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range, void seq_input_event(unsigned char *event, int len); void seq_copy_to_input (unsigned char *event, int len); -int sequencer_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); - /* * System calls for the /dev/midi */ @@ -73,19 +72,20 @@ int MIDIbuf_open (int dev, struct fileinfo *file); void MIDIbuf_release (int dev, struct fileinfo *file); int MIDIbuf_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); -int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig); +int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); + void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); void MIDIbuf_init(void); -int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait); - /* * * Misc calls from various sources */ /* From soundcard.c */ +#ifndef __bsdi__ void tenmicrosec(int *osp); +#endif void request_sound_timer (int count); void sound_stop_timer(void); int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp); @@ -205,7 +205,7 @@ void ad1848_control(int cmd, int arg); #define AD1848_REROUTE(oldctl, newctl) \ ad1848_control(AD1848_MIXER_REROUTE, ((oldctl)<<8)|(newctl)) -void ad1848_interrupt (int irq, void *dev_id, struct pt_regs * dummy); +void adintr(int irq, void *dev_id, struct pt_regs * dummy); void attach_ms_sound(struct address_info * hw_config); int probe_ms_sound(struct address_info *hw_config); void attach_pnp_ad1848(struct address_info * hw_config); diff --git a/drivers/sound/sound_pnp.c b/drivers/sound/sound_pnp.c new file mode 100644 index 000000000000..ffaa5b644085 --- /dev/null +++ b/drivers/sound/sound_pnp.c @@ -0,0 +1,1513 @@ +/* + * sound/sound_pnp.c + * + * PnP soundcard support (Linux spesific) + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. + */ +#include + +#include "sound_config.h" + +#if defined(CONFIG_SPNP) + + +static struct wait_queue *maui_sleeper = NULL; +static volatile struct snd_wait maui_sleep_flag = +{0}; + +extern unsigned long init_pnp (unsigned long, int *); + +#include "pnp.h" +extern int *sound_osp; + +extern int (*pnp_ioctl) (unsigned int cmd, caddr_t arg); + +extern int sound_pnp_port; +static int disabled_devices[] = +{ + PNP_DEVID ('G', 'R', 'V', 0x0003), /* GUS SB emulation */ + PNP_DEVID ('G', 'R', 'V', 0x0004), /* GUS MPU emulation */ + 0 +}; + +static int special_devices[] = +{ + PNP_DEVID ('C', 'S', 'C', 0x0010), /* CS4232/6 control port */ + PNP_DEVID ('C', 'S', 'C', 0x0002), /* CS4232/6 control port */ + 0 +}; + +static int pnp_sig = 0; + +static void +pnp_delay (long t) +{ + t = (t * HZ) / 1000000; /* Convert to jiffies */ + + + { + unsigned long tlimit; + + if (t) + current->timeout = tlimit = jiffies + (t); + else + tlimit = (unsigned long) -1; + maui_sleep_flag.opts = WK_SLEEP; + interruptible_sleep_on (&maui_sleeper); + if (!(maui_sleep_flag.opts & WK_WAKEUP)) + { + if (jiffies >= tlimit) + maui_sleep_flag.opts |= WK_TIMEOUT; + } + maui_sleep_flag.opts &= ~WK_SLEEP; + }; +} + +void +cs4232_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + int old_num_mixers = num_mixers; + int is_4232 = 0; /* CS4232 (not CS4236 or something better) */ + + int portmask = 0xff; + int irqmask = 0x01, dmamask = 0x03; + int opl3_driver, wss_driver; + + + if (pnp_trace) + printk ("CS4232/6 driver waking up\n"); + + if (dev->card->key == (PNP_DEVID ('C', 'S', 'C', 0x4232))) + is_4232 = 1; + +#ifndef USE_HOT_PNP_INIT + if (is_4232) /* CS4232 may cause lockups */ + if (pnp_get_port (dev, 0) == NO_PORT || + pnp_get_port (dev, 1) == NO_PORT || + pnp_get_irq (dev, 0) == NO_IRQ || + pnp_get_dma (dev, 0) == NO_DMA + ) + { + printk ("Sound: CS4232 in PnP mode requires prior initialization by PnP BIOS\n"); + return; + } +#endif + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "PnP WSS"; + + if ((wss_driver = sndtable_identify_card ("AD1848"))) + portmask |= 0x01; /* MSS */ + else + printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x02; /* OPL3 */ + else + printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); + + /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ + + if (!portmask) /* No drivers available */ + return; + + if (!is_4232) + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + { + printk ("sound_pnp: Failed to find free resources\n"); + return; + } + + { + struct address_info hw_config; + int wss_base, opl3_base; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + wss_base = pnp_get_port (dev, 0); + opl3_base = pnp_get_port (dev, 1); + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + pnp_delay (1000000); + + if (pnp_trace) + { + printk ("I/O0 %03x\n", wss_base); + printk ("I/O1 %03x\n", opl3_base); + printk ("IRQ %d\n", irq); + printk ("DMA0 %d\n", dma1); + printk ("DMA1 %d\n", dma2); + } + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + + } + + if (wss_base && wss_driver) + { + hw_config.io_base = wss_base; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (wss_driver, &hw_config); + + + if (num_mixers > old_num_mixers) + { /* Assume the mixer map is as suggested in the CS4232 spec */ + AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + AD1848_REROUTE (SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM */ + } + } + } +} + +void +opti82C924_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; + int opl3_driver, wss_driver; + + if (pnp_trace) + printk ("OPTi 82C924 driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "PnP WSS"; + + if ((wss_driver = sndtable_identify_card ("AD1848"))) + portmask |= 0x01; /* MSS */ + else + printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x02; /* OPL3 */ + else + printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); + + /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int wss_base, opl3_base; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + wss_base = pnp_get_port (dev, 1); + opl3_base = pnp_get_port (dev, 2); + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + pnp_delay (2000000); + + if (pnp_trace) + { + printk ("I/O0 %03x\n", wss_base); + printk ("I/O1 %03x\n", opl3_base); + printk ("IRQ %d\n", irq); + printk ("DMA0 %d\n", dma1); + printk ("DMA1 %d\n", dma2); + } + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base + 8; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + + } + + if (wss_base && wss_driver) + { + hw_config.io_base = wss_base + 4; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (wss_driver, &hw_config); + + } + } +} + +void +opl3sa2_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; + int opl3_driver, wss_driver, mpu_driver; + + if (pnp_trace) + printk ("OPL3-SA2 driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "PnP WSS"; + + if ((wss_driver = sndtable_identify_card ("AD1848"))) + portmask |= 0x02; /* MSS */ + else + printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x04; /* OPL3 */ + else + printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); + + if ((mpu_driver = sndtable_identify_card ("UART401"))) + portmask |= 0x08; /* OPL3 */ + else + printk ("Sound: PnP UART401 device detected but no driver enabled\n"); + + /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int wss_base, opl3_base, mpu_base; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + wss_base = pnp_get_port (dev, 1); + opl3_base = pnp_get_port (dev, 2); + mpu_base = pnp_get_port (dev, 3); + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + pnp_delay (1000000); + + if (pnp_trace) + { + printk ("I/O0 %03x\n", wss_base); + printk ("I/O1 %03x\n", opl3_base); + printk ("I/O3 %03x\n", mpu_base); + printk ("IRQ %d\n", irq); + printk ("DMA0 %d\n", dma1); + printk ("DMA1 %d\n", dma2); + } + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + + } + + if (wss_base && wss_driver) + { + hw_config.io_base = wss_base + 4; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (wss_driver, &hw_config); + + } + + if (mpu_base && mpu_driver) + { + hw_config.io_base = mpu_base; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (mpu_driver, &hw_config); + + } + } +} + +static unsigned char +C931_read (int base, int reg) +{ + unsigned char data; + unsigned long flags; + + save_flags (flags); + cli (); + outb ((0xE4), base); + outb ((reg), base + 2); + data = inb (base + 3); + restore_flags (flags); + return data; +} + +static void +C931_write (int base, int reg, unsigned char data) +{ + unsigned long flags; + + save_flags (flags); + cli (); + outb ((0xE4), base); + outb ((reg), base + 2); + outb ((data), base + 3); + restore_flags (flags); +} + +void +opti82C931_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; + int opl3_driver, wss_driver; + + if (pnp_trace) + printk ("OPTi 82C931 driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "PnP WSS"; + + if ((wss_driver = sndtable_identify_card ("AD1848"))) + portmask |= 0x01; /* MSS */ + else + printk ("Sound: PnP MSS/WSS device detected but no driver enabled\n"); + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x02; /* OPL3 */ + else + printk ("Sound: PnP OPL3/4 device detected but no driver enabled\n"); + + /* printk ("WSS driver %d, OPL3 driver %d\n", wss_driver, opl3_driver); */ + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int wss_base, opl3_base, master_ctl; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + wss_base = pnp_get_port (dev, 0); + opl3_base = pnp_get_port (dev, 1); + master_ctl = pnp_get_port (dev, 3); + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + if (pnp_trace) + { + int i; + + printk ("I/O0 %03x\n", wss_base); + printk ("I/O1 %03x\n", opl3_base); + printk ("Master control port %x\n", master_ctl); + for (i = 0; i < 4; i++) + printk ("Port %x = %x\n", master_ctl + i, inb (master_ctl + i)); + printk ("IRQ %d\n", irq); + printk ("DMA0 %d\n", dma1); + printk ("DMA1 %d\n", dma2); + } + { + unsigned char tmp; + + tmp = C931_read (master_ctl, 5) | 0x20; /* Enable codec registers I16 to I31 */ + C931_write (master_ctl, 5, tmp); + + tmp = 0x82; /* MPU and WSS enabled, SB disabled */ + C931_write (master_ctl, 6, tmp); + } + + pnp_delay (2000000); + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base + 8; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + + } + + if (wss_base && wss_driver) + { + hw_config.io_base = wss_base; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (wss_driver, &hw_config); + + ad1848_control (AD1848_SET_C930_PWD, master_ctl); + } + } +} + +void +opti82C924mpu_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; + int mpu_driver; + + if (pnp_trace) + printk ("OPTi 82C924/C925/C931 MPU driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "PnP MPU"; + + if ((mpu_driver = sndtable_identify_card ("UART401"))) + portmask |= 0x01; /* MPU401 */ + else + printk ("Sound: PnP MPU device detected but no driver enabled\n"); + + /* printk ("MPU driver %d\n", mpu_driver); */ + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int mpu_base; + int irq; + + if (pnp_trace) + printk ("Device activation OK\n"); + mpu_base = pnp_get_port (dev, 0); + irq = pnp_get_irq (dev, 0); + + pnp_delay (1000000); + + if (pnp_trace) + { + printk ("I/O %03x\n", mpu_base); + printk ("IRQ %d\n", irq); + } + + if (mpu_base && mpu_driver) + { + hw_config.io_base = mpu_base; + hw_config.irq = irq; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (mpu_driver, &hw_config); + + } + } +} + +void +cs4236mpu_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0xff, irqmask = 0x01, dmamask = 0x03; + int mpu_driver; + + if (dev->card->key == (PNP_DEVID ('C', 'S', 'C', 0x4232))) /* CS4232 */ + return; + + if (pnp_trace) + printk ("CS4236 MPU driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "PnP MPU"; + + if ((mpu_driver = sndtable_identify_card ("UART401"))) + portmask |= 0x01; /* MPU401 */ + else + printk ("Sound: CS4236 PnP MPU device detected but no driver enabled\n"); + + /* printk ("MPU driver %d\n", mpu_driver); */ + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int mpu_base; + int irq; + + if (pnp_trace) + printk ("Device activation OK\n"); + mpu_base = pnp_get_port (dev, 0); + irq = pnp_get_irq (dev, 0); + + pnp_delay (1500000); + + if (pnp_trace) + { + printk ("I/O %03x\n", mpu_base); + printk ("IRQ %d\n", irq); + } + + if (mpu_base && mpu_driver) + { + hw_config.io_base = mpu_base; + hw_config.irq = irq; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (mpu_driver, &hw_config); + + } + } +} + +void +soundscape_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0xff, irqmask = 0x03, dmamask = 0x01; + int sscape_driver, wss_driver; + + if (pnp_trace) + printk ("Soundscape PnP driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "SoundScape PnP"; + + if ((sscape_driver = sndtable_identify_card ("SSCAPE"))) + portmask |= 0x01; /* MPU401 */ + else + printk ("Sound: Soundscape PnP device detected but no driver enabled\n"); + + /* printk ("Soundscape driver %d\n", sscape_driver); */ + + if ((wss_driver = sndtable_identify_card ("SSCAPEMSS"))) + portmask |= 0x01; + else + printk ("Sound: Soundscape codec device detected but no driver enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int sscape_base; + int irq, irq2, dma, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + sscape_base = pnp_get_port (dev, 0); + irq = pnp_get_irq (dev, 0); + irq2 = pnp_get_irq (dev, 1); + dma = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + pnp_delay (1000000); + + if (pnp_trace) + { + printk ("I/O %03x\n", sscape_base); + printk ("IRQ %d\n", irq); + printk ("IRQ2 %d\n", irq2); + printk ("DMA %d\n", dma); + printk ("DMA2 %d\n", dma2); + } + + if (sscape_base && sscape_driver) + { + hw_config.io_base = sscape_base; + hw_config.irq = irq; + hw_config.dma = dma; + hw_config.dma2 = dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0x12345678; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (sscape_driver, &hw_config); + } + + if (sscape_base && wss_driver) + { + hw_config.io_base = sscape_base + 8; /* The codec base */ + hw_config.irq = irq2; + hw_config.dma = dma; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (wss_driver, &hw_config); + ad1848_control (AD1848_SET_XTAL, 1); /* 14.3 MHz is used */ + } + } +} + +void +soundscape_vivo (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x07, irqmask = 0x03, dmamask = 0x03; + int mpu_driver, wss_driver, vivo_driver; + int is_vivo_classic = 0; + + if (pnp_trace) + printk ("Soundscape VIVO driver waking up\n"); + + if (dev->card->key == (PNP_DEVID ('E', 'N', 'S', 0x4080))) + is_vivo_classic = 1; + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "SoundScape VIVO"; + + if ((mpu_driver = sndtable_identify_card ("UART401"))) + portmask |= 0x01; /* MPU401 */ + + /* printk ("MPU driver %d\n", mpu_driver); */ + + if ((wss_driver = sndtable_identify_card ("AD1848"))) + portmask |= 0x02; + else + printk ("Sound: Soundscape codec device detected but no driver enabled\n"); + + if ((vivo_driver = sndtable_identify_card ("VIVO"))) + portmask |= 0x07; + else + printk ("Sound: Soundscape VIVO/OTTO device detected but no driver installed\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int mpu_base, mss_base, otto_base; + int irq, irq2, dma, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + mpu_base = pnp_get_port (dev, 0); + mss_base = pnp_get_port (dev, 1); + otto_base = pnp_get_port (dev, 2); + irq = pnp_get_irq (dev, 0); + irq2 = pnp_get_irq (dev, 1); + dma = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + if (dma2 == NO_DMA) + dma2 = dma; + + if (pnp_trace) + { + printk ("I/O %03x\n", mpu_base); + printk ("MSS I/O %03x\n", mss_base); + printk ("OTTO I/O %03x\n", otto_base); + printk ("IRQ %d\n", irq); + printk ("IRQ2 %d\n", irq2); + printk ("DMA %d\n", dma); + printk ("DMA2 %d\n", dma2); + } + + + if (mss_base && wss_driver) + { + hw_config.io_base = mss_base + 4; /* The codec base */ + hw_config.irq = irq; + hw_config.dma = dma; + hw_config.dma2 = dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (wss_driver, &hw_config); + } + + if (otto_base && vivo_driver) + { + hw_config.io_base = otto_base; + hw_config.irq = irq2; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = mpu_base; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (vivo_driver, &hw_config); + + if (is_vivo_classic) + { + /* + * The original VIVO uses XCTL0 pin of AD1845 as a synth (un)mute bit. Turn it + * on _after_ the synth is initialized. Btw, XCTL1 controls 30 dB mic boost + * circuit. + */ + + ad1848_control (AD1848_SET_XCTL0, 1); /* Unmute */ + } + AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH); /* AUX1 is OTTO input */ + AD1848_REROUTE (SOUND_MIXER_LINE3, SOUND_MIXER_LINE); /* Line in */ + + } + } +} + +void +gus_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; + int gus_driver, wss_driver; + + if (pnp_trace) + printk ("GUS PnP driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "Ultrasound PnP"; + + if ((gus_driver = sndtable_identify_card ("GUSPNP"))) + portmask |= 0x07; + else + printk ("Sound: GUS PnP device detected but no driver enabled\n"); + + if ((wss_driver = sndtable_identify_card ("AD1848"))) + portmask |= 0x01; /* MAX */ + else + printk ("Sound: GUS PnP codec device detected but no driver enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int gus_base; + int irq; + int dma1, dma2; + + gus_base = pnp_get_port (dev, 0); + + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + if (pnp_trace) + printk ("Device activation OK (P%x I%d D%d d%d)\n", + gus_base, irq, dma1, dma2); + + if (gus_base && gus_driver) + { + + hw_config.io_base = gus_base; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (gus_driver, &hw_config); + } + } +} + +void +sb_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; + int sb_driver, mpu_driver, opl3_driver; + + if (pnp_trace) + printk ("SB PnP driver waking up\n"); + pnp_delay (1000000); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "SoundBlaster PnP"; + + if ((sb_driver = sndtable_identify_card ("SBPNP"))) + portmask |= 0x01; + else + printk ("Sound: SB PnP device detected but no driver enabled\n"); + + if ((mpu_driver = sndtable_identify_card ("SBMPU"))) + portmask |= 0x02; + else + printk ("Sound: SB PnP device detected but SB MPU driver not enabled\n"); + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x04; + else + printk ("Sound: SB PnP device detected but OPL3 driver not enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int sb_base, mpu_base, opl3_base; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + sb_base = pnp_get_port (dev, 0); + mpu_base = pnp_get_port (dev, 1); + opl3_base = pnp_get_port (dev, 2); + + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + dma2 = pnp_get_dma (dev, 1); + + if (sb_base && sb_driver) + { + hw_config.io_base = sb_base; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (sb_driver, &hw_config); + } + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + + } + + if (mpu_base && mpu_driver) + { + hw_config.io_base = mpu_base; + hw_config.irq = irq; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (mpu_driver, &hw_config); + + } + } +} + +void +als_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; + int sb_driver; + + if (pnp_trace) + printk ("ALS### PnP driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "SB16 clone"; + + if ((sb_driver = sndtable_identify_card ("SBPNP"))) + portmask |= 0x01; + else + printk ("Sound: ALS PnP device detected but no driver enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int sb_base; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + sb_base = pnp_get_port (dev, 0); + + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 1); + dma2 = pnp_get_dma (dev, 0); + + if (sb_base && sb_driver) + { + hw_config.io_base = sb_base; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (sb_driver, &hw_config); + } + } +} + +void +als_pnp_mpu (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; + int mpu_driver; + + if (pnp_trace) + printk ("ALS### PnP MPU driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "SB16 clone"; + + if ((mpu_driver = sndtable_identify_card ("UART401"))) + portmask |= 0x01; + else + printk ("Sound: ALS PnP device detected but no MPU driver enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int mpu_base; + int irq; + + if (pnp_trace) + printk ("Device activation OK\n"); + mpu_base = pnp_get_port (dev, 0); + + irq = pnp_get_irq (dev, 0); + + if (mpu_base && mpu_driver) + { + hw_config.io_base = mpu_base; + hw_config.irq = irq; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (mpu_driver, &hw_config); + } + } +} + +void +als_pnp_opl (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x00, irqmask = 0x01, dmamask = 0x03; + int opl3_driver; + + if (pnp_trace) + printk ("ALS### PnP OPL3 driver waking up\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "SB16 clone"; + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x01; + else + printk ("Sound: ALS PnP device detected but no OPL3 driver enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int opl3_base; + int irq; + + if (pnp_trace) + printk ("Device activation OK\n"); + opl3_base = pnp_get_port (dev, 0); + + irq = pnp_get_irq (dev, 0); + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = sound_osp; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + } + } +} + +void +ess_pnp (void *parm) +{ + struct pnp_dev *dev = (struct pnp_dev *) parm; + char *name; + + int portmask = 0x03, irqmask = 0x01, dmamask = 0x03; + int sb_driver, mpu_driver, opl3_driver; + + if (pnp_trace) + printk ("ESS PnP driver waking up\n"); + + if (pnp_trace) + { + printk ("ESS1868: IRQB,IRQA = %x\n", pnp_readreg (dev, 0x20)); + printk ("ESS1868: IRQD,IRQC = %x\n", pnp_readreg (dev, 0x21)); + printk ("ESS1868: IRQF,IRQE = %x\n", pnp_readreg (dev, 0x22)); + printk ("ESS1868: DRQB,DRQA = %x\n", pnp_readreg (dev, 0x23)); + printk ("ESS1868: DRQD,DRQC = %x\n", pnp_readreg (dev, 0x24)); + printk ("ESS1868: Configuration ROM Header 0 = %x\n", pnp_readreg (dev, 0x25)); + printk ("ESS1868: Configuration ROM Header 1 = %x\n", pnp_readreg (dev, 0x26)); + printk ("ESS1868: HW Volume IRQ = %x\n", pnp_readreg (dev, 0x27)); + printk ("ESS1868: MPU401 IRQ = %x\n", pnp_readreg (dev, 0x28)); + } + + if (pnp_readreg (dev, 0x27) & 0x01) /* MPU401 is at logical device #3 */ + printk ("Nonstandard ESS1868 implementation - contact support@4front-tech.com\n"); + + if (dev->card && dev->card->name) + name = dev->card->name; + else + name = "ESS AudioDrive PnP"; + + if ((sb_driver = sndtable_identify_card ("SBLAST"))) + portmask |= 0x01; + else + printk ("Sound: SB PnP device detected but no driver enabled\n"); + + if ((mpu_driver = sndtable_identify_card ("SBMPU"))) + portmask |= 0x02; + else + printk ("Sound: SB PnP device detected but SB MPU driver not enabled\n"); + + if ((opl3_driver = sndtable_identify_card ("OPL3"))) + portmask |= 0x04; + else + printk ("Sound: SB PnP device detected but OPL3 driver not enabled\n"); + + if (!portmask) /* No drivers available */ + return; + + if (!pnp_allocate_device (pnp_sig, dev, portmask, irqmask, dmamask, 0x00)) + printk ("sound_pnp: Failed to find free resources\n"); + else + { + struct address_info hw_config; + int sb_base, mpu_base, opl3_base; + int irq; + int dma1, dma2; + + if (pnp_trace) + printk ("Device activation OK\n"); + sb_base = pnp_get_port (dev, 0); + opl3_base = pnp_get_port (dev, 1); + mpu_base = pnp_get_port (dev, 2); + + irq = pnp_get_irq (dev, 0); + dma1 = pnp_get_dma (dev, 0); + /* dma2 = pnp_get_dma (dev, 1); */ dma2 = -1; + + if (pnp_trace) + { + printk ("ESS PnP at %x/%x/%x, %d, %d/%d\n", + sb_base, mpu_base, opl3_base, + irq, dma1, dma2); + } + + if (sb_base && sb_driver) + { + hw_config.io_base = sb_base; + hw_config.irq = irq; + hw_config.dma = dma1; + hw_config.dma2 = (dma2 == NO_DMA) ? dma1 : dma2; + hw_config.always_detect = 0; + hw_config.name = name; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = NULL; + hw_config.card_subtype = 0; + + sndtable_start_card (sb_driver, &hw_config); + } + + if (opl3_base && opl3_driver) + { + hw_config.io_base = opl3_base; + hw_config.irq = 0; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = NULL; + hw_config.card_subtype = 0; + + sndtable_start_card (opl3_driver, &hw_config); + + } + + if (mpu_base && mpu_driver) + { + hw_config.io_base = mpu_base; + hw_config.irq = -irq; + hw_config.dma = -1; + hw_config.dma2 = -1; + hw_config.always_detect = 0; + hw_config.name = ""; + hw_config.driver_use_1 = 0; + hw_config.driver_use_2 = 0; + hw_config.osp = NULL; + hw_config.card_subtype = 0; + + sndtable_start_card (mpu_driver, &hw_config); + + } + } +} + +static struct pnp_sounddev pnp_devs[] = +{ + {PNP_DEVID ('C', 'S', 'C', 0x0000), cs4232_pnp, "CS4232"}, + {PNP_DEVID ('C', 'S', 'C', 0x0003), cs4236mpu_pnp, "CS4236MPU"}, + {PNP_DEVID ('G', 'R', 'V', 0x0000), gus_pnp, "GUS"}, + {PNP_DEVID ('R', 'V', 'L', 0x0010), gus_pnp, "WAVXTREME"}, + {PNP_DEVID ('A', 'D', 'V', 0x0010), gus_pnp, "IWAVE"}, + {PNP_DEVID ('D', 'X', 'P', 0x0010), gus_pnp, "IWAVE"}, + {PNP_DEVID ('Y', 'M', 'H', 0x0021), opl3sa2_pnp, "OPL3SA2"}, + {PNP_DEVID ('O', 'P', 'T', 0x0000), opti82C924_pnp, "82C924"}, + {PNP_DEVID ('O', 'P', 'T', 0x9250), opti82C924_pnp, "82C925"}, + {PNP_DEVID ('O', 'P', 'T', 0x9310), opti82C931_pnp, "82C931"}, + {PNP_DEVID ('O', 'P', 'T', 0x0002), opti82C924mpu_pnp, "82C924MPU"}, + {PNP_DEVID ('E', 'N', 'S', 0x0000), soundscape_pnp, "SSCAPE"}, + {PNP_DEVID ('N', 'E', 'C', 0x0000), soundscape_pnp, "NEC"}, + {PNP_DEVID ('E', 'N', 'S', 0x1010), soundscape_vivo, "SSCAPE"}, + {PNP_DEVID ('E', 'N', 'S', 0x1011), soundscape_vivo, "SSCAPE"}, + {PNP_DEVID ('C', 'T', 'L', 0x0031), sb_pnp, "SB"}, + {PNP_DEVID ('C', 'T', 'L', 0x0001), sb_pnp, "SB"}, + {PNP_DEVID ('C', 'T', 'L', 0x0041), sb_pnp, "SB"}, /* SB32 (new revision) */ + {PNP_DEVID ('C', 'T', 'L', 0x0042), sb_pnp, "SB"}, /* SB64 */ + {PNP_DEVID ('C', 'T', 'L', 0x0044), sb_pnp, "SB"}, /* SB64 Gold */ + {PNP_DEVID ('@', '@', '@', 0x0001), als_pnp, "SB"}, + {PNP_DEVID ('@', 'X', '@', 0x0001), als_pnp_mpu, "SB"}, + {PNP_DEVID ('@', 'H', '@', 0x0001), als_pnp_opl, "SB"}, + {PNP_DEVID ('E', 'S', 'S', 0x1868), ess_pnp, "ESS"} +}; + +static int nr_pnpdevs = sizeof (pnp_devs) / sizeof (struct pnp_sounddev); + +static int +pnp_activate (int id, struct pnp_dev *dev) +{ + int i; + + for (i = 0; i < nr_pnpdevs; i++) + if (pnp_devs[i].id == id) + { + + if (pnp_trace) + printk ("PnP dev: %08x, %s\n", id, + pnp_devid2asc (id)); + + pnp_devs[i].setup ((void *) dev); + return 1; + } + + return 0; +} + +void +cs423x_special (struct pnp_dev *dev) +{ +} + +void +sound_pnp_init (int *osp) +{ + + struct pnp_dev *dev; + + if (pnp_sig == 0) + init_pnp (0, osp); + + if (pnp_sig == 0) + if ((pnp_sig = pnp_connect ("sound")) == -1) + { + printk ("Sound: Can't connect to kernel PnP services.\n"); + return; + } + +/* + * First handle some special configuration ports. + */ + dev = NULL; + while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) + { + int i; + + for (i = 0; special_devices[i] != 0; i++) + if (special_devices[i] == dev->key) + switch (i) + { + case 0: + case 1: + cs423x_special (dev); + break; + } + } + +/* + * Next disable some unused sound devices so that they don't consume + * valuable IRQ and DMA resources. + */ + dev = NULL; + while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) + { + int i; + + for (i = 0; disabled_devices[i] != 0; i++) + if (disabled_devices[i] == dev->key) + pnp_enable_device (dev, 0); /* Disable it */ + } + +/* + * Then initialize drivers for known PnP devices. + */ + dev = NULL; + while ((dev = pnp_get_next_device (pnp_sig, dev)) != NULL) + { + if (!pnp_activate (dev->key, dev)) + { + /* Scan all compatible devices */ + + int i; + + for (i = 0; i < dev->ncompat; i++) + if (pnp_activate (dev->compat_keys[i], dev)) + break; + } + } +} + +void +sound_pnp_disconnect (void) +{ + pnp_disconnect (pnp_sig); +} + + +#endif diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index 12282544026d..bacdccb66e53 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -16,6 +16,7 @@ #include "sound_config.h" static int in_use = 0; /* Total # of open devices */ +unsigned long seq_time = 0; /* Time for /dev/sequencer */ /* * Table for configurable mixer volume handling @@ -167,17 +168,22 @@ init_status (void) status_ptr = 0; #ifdef SOUND_UNAME_A - put_status ("Sound Driver:" SOUND_VERSION_STRING + put_status ("OSS/Free" SOUND_VERSION_STRING " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n" SOUND_UNAME_A ")" "\n"); #else - put_status ("Sound Driver:" SOUND_VERSION_STRING + put_status ("OSS/Free:" SOUND_VERSION_STRING " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" "\n"); #endif +#ifdef MODULE + put_status ("Load type: Driver loaded as a module.\n"); +#else + put_status ("Load type: Driver compiled into kernel\n"); +#endif put_status ("Kernel: "); put_status (system_utsname.sysname); put_status (" "); @@ -189,6 +195,9 @@ init_status (void) put_status (" "); put_status (system_utsname.machine); put_status ("\n"); +#ifdef MODULE + put_status ("Driver loaded as a module\n"); +#endif if (!put_status ("Config options: ")) diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index fc6a5a94c72a..088591b9d080 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -139,8 +139,8 @@ sound_release (struct inode *inode, struct file *file) sound_release_sw (dev, &files[dev]); #ifdef MODULE MOD_DEC_USE_COUNT; -#endif return 0; +#endif } static int @@ -156,7 +156,7 @@ sound_ioctl (struct inode *inode, struct file *file, files[dev].flags = file->f_flags; - if (_SIOC_DIR (cmd) != _SIOC_NONE) + if (_SIOC_DIR (cmd) != _SIOC_NONE && _SIOC_DIR (cmd) != 0) { /* * Have to validate the address given by the process. @@ -196,7 +196,7 @@ sound_ioctl (struct inode *inode, struct file *file, if (ptr != NULL && alloced) vfree (ptr); - return err; + return ((err < 0) ? err : 0); } static int @@ -229,7 +229,7 @@ sound_select (struct inode *inode, struct file *file, int sel_type, poll_table * case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return audio_select (dev, &files[dev], sel_type, wait); + return DMAbuf_select (dev >> 4, &files[dev], sel_type, wait); break; #endif @@ -275,20 +275,14 @@ sound_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) return -EINVAL; } - if ((vma->vm_flags & (VM_READ | VM_WRITE)) == (VM_READ | VM_WRITE)) + if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ { - printk ("Sound: Cannot do read/write mmap()\n"); - return -EINVAL; + dmap = audio_devs[dev]->dmap_out; } - - if (vma->vm_flags & VM_READ) + else if (vma->vm_flags & VM_READ) { dmap = audio_devs[dev]->dmap_in; } - else if (vma->vm_flags & VM_WRITE) - { - dmap = audio_devs[dev]->dmap_out; - } else { printk ("Sound: Undefined mmap() access\n"); @@ -379,20 +373,10 @@ soundcard_init (void) #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { - DMAbuf_init (); audio_init_devices (); } #endif -#ifdef CONFIG_MIDI - if (num_midis) - MIDIbuf_init (); -#endif - -#ifdef CONFIG_SEQUENCER - if (num_midis + num_synths) - sequencer_init (); -#endif } @@ -616,9 +600,15 @@ sound_close_dma (int chn) #ifdef CONFIG_SEQUENCER +static void +do_sequencer_timer (unsigned long dummy) +{ + sequencer_timer (0); +} + static struct timer_list seq_timer = -{NULL, NULL, 0, 0, sequencer_timer}; +{NULL, NULL, 0, 0, do_sequencer_timer}; void request_sound_timer (int count) @@ -681,33 +671,31 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) dmap->raw_buf = NULL; - if (debugmem) - printk ("sound: buffsize[%d] = %lu\n", dev, audio_devs[dev]->buffsize); - - audio_devs[dev]->buffsize = dma_buffsize; + dmap->buffsize = dma_buffsize; - if (audio_devs[dev]->buffsize > dma_pagesize) - audio_devs[dev]->buffsize = dma_pagesize; + if (dmap->buffsize > dma_pagesize) + dmap->buffsize = dma_pagesize; start_addr = NULL; /* * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. + * it fails. Don't accept smaller than 8k buffer for performance + * reasons. */ - while (start_addr == NULL && audio_devs[dev]->buffsize > PAGE_SIZE) + while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) { int sz, size; for (sz = 0, size = PAGE_SIZE; - size < audio_devs[dev]->buffsize; + size < dmap->buffsize; sz++, size <<= 1); - audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz); + dmap->buffsize = PAGE_SIZE * (1 << sz); if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL) - audio_devs[dev]->buffsize /= 2; + dmap->buffsize /= 2; } if (start_addr == NULL) @@ -718,7 +706,7 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) else { /* make some checks */ - end_addr = start_addr + audio_devs[dev]->buffsize - 1; + end_addr = start_addr + dmap->buffsize - 1; if (debugmem) printk ("sound: start 0x%lx, end 0x%lx\n", @@ -731,9 +719,9 @@ sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan) || end_addr >= (char *) (MAX_DMA_ADDRESS)) { printk ( - "sound: Got invalid address 0x%lx for %ldb DMA-buffer\n", + "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, - audio_devs[dev]->buffsize); + dmap->buffsize); return -EFAULT; } } @@ -761,11 +749,11 @@ sound_free_dmap (int dev, struct dma_buffparms *dmap, int chan) return; /* Don't free mmapped buffer. Will use it next time */ for (sz = 0, size = PAGE_SIZE; - size < audio_devs[dev]->buffsize; + size < dmap->buffsize; sz++, size <<= 1); start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + audio_devs[dev]->buffsize; + end_addr = start_addr + dmap->buffsize; for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) { @@ -776,6 +764,33 @@ sound_free_dmap (int dev, struct dma_buffparms *dmap, int chan) dmap->raw_buf = NULL; } + +/* Intel version !!!!!!!!! */ +int +sound_start_dma (int dev, struct dma_buffparms *dmap, int chan, + unsigned long physaddr, + int count, int dma_mode, int autoinit) +{ + unsigned long flags; + + /* printk("Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ + if (autoinit) + dma_mode |= DMA_AUTOINIT; + save_flags (flags); + cli (); + disable_dma (chan); + clear_dma_ff (chan); + set_dma_mode (chan, dma_mode); + set_dma_addr (chan, physaddr); + set_dma_count (chan, count); + enable_dma (chan); + restore_flags (flags); + + return 0; +} + +#endif + void conf_printf (char *name, struct address_info *hw_config) { @@ -817,29 +832,3 @@ conf_printf2 (char *name, int base, int irq, int dma, int dma2) printk ("\n"); } - -/* Intel version !!!!!!!!! */ -int -sound_start_dma (int dev, struct dma_buffparms *dmap, int chan, - unsigned long physaddr, - int count, int dma_mode, int autoinit) -{ - unsigned long flags; - -/* printk("Start DMA %d, %d\n", (int)(physaddr-dmap->raw_buf_phys), count); */ - if (autoinit) - dma_mode |= DMA_AUTOINIT; - save_flags (flags); - cli (); - disable_dma (chan); - clear_dma_ff (chan); - set_dma_mode (chan, dma_mode); - set_dma_addr (chan, physaddr); - set_dma_count (chan, count); - enable_dma (chan); - restore_flags (flags); - - return 0; -} - -#endif diff --git a/drivers/sound/soundvers.h b/drivers/sound/soundvers.h index 6bcb5c3b6571..5b9b6a5c6503 100644 --- a/drivers/sound/soundvers.h +++ b/drivers/sound/soundvers.h @@ -1,2 +1,2 @@ -#define SOUND_VERSION_STRING "3.8-beta9-970226" -#define SOUND_INTERNAL_VERSION 0x030803 +#define SOUND_VERSION_STRING "3.8a" +#define SOUND_INTERNAL_VERSION 0x030804 diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index ea8d6b80012e..c5cf7de3fae0 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -59,16 +59,16 @@ #define CMD_GEN_HOST_ACK 0x80 #define CMD_GEN_MPU_ACK 0x81 #define CMD_GET_BOARD_TYPE 0x82 -#define CMD_SET_CONTROL 0x88 -#define CMD_GET_CONTROL 0x89 +#define CMD_SET_CONTROL 0x88 /* Old firmware only */ +#define CMD_GET_CONTROL 0x89 /* Old firmware only */ #define CTL_MASTER_VOL 0 #define CTL_MIC_MODE 2 #define CTL_SYNTH_VOL 4 #define CTL_WAVE_VOL 7 -#define CMD_SET_MT32 0x96 -#define CMD_GET_MT32 0x97 -#define CMD_SET_EXTMIDI 0x9b -#define CMD_GET_EXTMIDI 0x9c +#define CMD_SET_EXTMIDI 0x8a +#define CMD_GET_EXTMIDI 0x8b +#define CMD_SET_MT32 0x8c +#define CMD_GET_MT32 0x8d #define CMD_ACK 0x80 @@ -78,15 +78,16 @@ typedef struct sscape_info int ok; /* Properly detected */ int failed; int dma_allocated; - int my_audiodev; + int codec_audiodev; int opened; int *osp; } - sscape_info; -static struct sscape_info dev_info = + +static struct sscape_info adev_info = {0}; -static struct sscape_info *devc = &dev_info; +static struct sscape_info *devc = &adev_info; +static int sscape_mididev = -1; static struct wait_queue *sscape_sleeper = NULL; static volatile struct snd_wait sscape_sleep_flag = @@ -270,19 +271,7 @@ set_control (struct sscape_info *devc, int ctrl, int value) host_close (devc); } -static int -get_board_type (struct sscape_info *devc) -{ - int tmp; - host_open (devc); - if (!host_command1 (devc, CMD_GET_BOARD_TYPE)) - tmp = -1; - else - tmp = host_read (devc); - host_close (devc); - return tmp; -} @@ -297,11 +286,11 @@ do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, return; } - audio_devs[devc->my_audiodev]->flags &= ~DMA_AUTOMODE; - DMAbuf_start_dma (devc->my_audiodev, + audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; + DMAbuf_start_dma (devc->codec_audiodev, buf, blk_size, mode); - audio_devs[devc->my_audiodev]->flags |= DMA_AUTOMODE; + audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; temp = devc->dma << 4; /* Setup DMA channel select bits */ if (devc->dma <= 3) @@ -384,7 +373,7 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, { unsigned long flags; unsigned char temp; - int done, timeout_val; + volatile int done, timeout_val; static unsigned char codec_dma_bits = 0; if (flag & CPF_FIRST) @@ -418,13 +407,19 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, /* * Transfer one code block using DMA */ - memcpy (audio_devs[devc->my_audiodev]->dmap_out->raw_buf, block, size); + if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) + { + printk ("SSCAPE: Error: DMA buffer not available\n"); + return 0; + } + + memcpy (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); save_flags (flags); cli (); /******** INTERRUPTS DISABLED NOW ********/ do_dma (devc, SSCAPE_DMA_A, - audio_devs[devc->my_audiodev]->dmap_out->raw_buf_phys, + audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, size, DMA_MODE_WRITE); /* @@ -432,17 +427,16 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, */ sscape_sleep_flag.opts = WK_NONE; done = 0; - timeout_val = 100; + timeout_val = 30; while (!done && timeout_val-- > 0) { int resid; - { unsigned long tlimit; - if (1) - current->timeout = tlimit = jiffies + (1); + if (HZ / 50) + current->timeout = tlimit = jiffies + (HZ / 50); else tlimit = (unsigned long) -1; sscape_sleep_flag.opts = WK_SLEEP; @@ -509,7 +503,7 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, x = inb (PORT (HOST_DATA)); if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ { - printk ("Soundscape: Acknowledge = %x\n", x); + DDB (printk ("Soundscape: Acknowledge = %x\n", x)); done = 1; } } @@ -555,9 +549,7 @@ sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, return 0; } - printk ("SoundScape board of type %d initialized OK\n", - get_board_type (devc)); - + printk ("SoundScape board initialized OK\n"); set_control (devc, CTL_MASTER_VOL, 100); set_control (devc, CTL_SYNTH_VOL, 100); @@ -633,7 +625,7 @@ static coproc_operations sscape_coproc_operations = sscape_coproc_close, sscape_coproc_ioctl, sscape_coproc_reset, - &dev_info + &adev_info }; static int sscape_detected = 0; @@ -678,6 +670,7 @@ attach_sscape (struct address_info *hw_config) if (sscape_detected != hw_config->io_base) return; + request_region (devc->base + 2, 6, "SoundScape"); if (old_hardware) { valid_interrupts = valid_interrupts_old; @@ -765,13 +758,17 @@ attach_sscape (struct address_info *hw_config) hw_config->irq *= -1; /* Restore it */ if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ - midi_devs[prev_devs]->coproc = &sscape_coproc_operations; + { + sscape_mididev = prev_devs; + midi_devs[prev_devs]->coproc = &sscape_coproc_operations; + } } #endif sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0; + } static int @@ -841,17 +838,13 @@ int probe_sscape (struct address_info *hw_config) { - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - if (sscape_detected != 0 && sscape_detected != hw_config->io_base) return 0; - devc->failed = 1; - - if (!detect_ga (devc)) - return 0; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + devc->osp = hw_config->osp; #ifdef SSCAPE_DEBUG1 /* @@ -866,6 +859,12 @@ probe_sscape (struct address_info *hw_config) } #endif + + devc->failed = 1; + + if (!detect_ga (devc)) + return 0; + if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ { unsigned char tmp; @@ -877,8 +876,6 @@ probe_sscape (struct address_info *hw_config) for (cc = 0; cc < 200000; ++cc) inb (devc->base + ODIE_ADDR); } - else - old_hardware = 0; } @@ -891,6 +888,7 @@ int probe_ss_ms_sound (struct address_info *hw_config) { int i, irq_bits = 0xff; + int ad_flags = 0; if (devc->failed) { @@ -917,7 +915,9 @@ probe_ss_ms_sound (struct address_info *hw_config) } - return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); + if (old_hardware) + ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ + return ad1848_detect (hw_config->io_base, &ad_flags, hw_config->osp); } void @@ -970,8 +970,13 @@ attach_ss_ms_sound (struct address_info *hw_config) devc->osp); if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ - audio_devs[prev_devs]->coproc = &sscape_coproc_operations; - devc->my_audiodev = prev_devs; + { + audio_devs[prev_devs]->coproc = &sscape_coproc_operations; + devc->codec_audiodev = prev_devs; + + /* Set proper routings here (what are they) */ + AD1848_REROUTE (SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + } #ifdef SSCAPE_DEBUG5 /* @@ -991,10 +996,10 @@ attach_ss_ms_sound (struct address_info *hw_config) void unload_sscape (struct address_info *hw_config) { + release_region (devc->base + 2, 6); #if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) unload_mpu401 (hw_config); #endif - snd_release_irq (hw_config->irq); } void @@ -1008,4 +1013,5 @@ unload_ss_ms_sound (struct address_info *hw_config) } + #endif diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 0dcd88a25a49..5bb60ea6ab60 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -339,9 +339,19 @@ probe_trix_sb (struct address_info *hw_config) void attach_trix_sb (struct address_info *hw_config) { + extern int sb_be_quiet; + int old_quiet; + #ifdef CONFIG_SBDSP hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; + + /* Prevent false alarms */ + old_quiet = sb_be_quiet; + sb_be_quiet = 1; + sb_dsp_init (hw_config); + + sb_be_quiet = old_quiet; #endif } diff --git a/drivers/sound/uart401.c b/drivers/sound/uart401.c index f2fef6d07a2b..e8a399cb615e 100644 --- a/drivers/sound/uart401.c +++ b/drivers/sound/uart401.c @@ -346,6 +346,7 @@ attach_uart401 (struct address_info *hw_config) strcpy (midi_devs[num_midis]->info.name, name); midi_devs[num_midis]->converter->id = "UART401"; num_midis++; + sequencer_init (); devc->opened = 0; } diff --git a/drivers/sound/uart6850.c b/drivers/sound/uart6850.c index 0610d1247f56..547cbba92dc9 100644 --- a/drivers/sound/uart6850.c +++ b/drivers/sound/uart6850.c @@ -294,6 +294,7 @@ attach_uart6850 (struct address_info *hw_config) std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &uart6850_operations; + sequencer_init (); } static int diff --git a/drivers/sound/ulaw.h b/drivers/sound/ulaw.h index be9f92d9984a..0ff8c0a3bda0 100644 --- a/drivers/sound/ulaw.h +++ b/drivers/sound/ulaw.h @@ -1,69 +1,69 @@ static unsigned char ulaw_dsp[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 5, 9, 13, 17, 21, 25, 29, 33, - 37, 41, 45, 49, 53, 57, 61, 65, - 68, 70, 72, 74, 76, 78, 80, 82, - 84, 86, 88, 90, 92, 94, 96, 98, - 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, - 115, 116, 116, 117, 117, 118, 118, 119, - 119, 120, 120, 121, 121, 122, 122, 123, - 123, 123, 124, 124, 124, 124, 125, 125, - 125, 125, 126, 126, 126, 126, 127, 127, - 127, 127, 127, 127, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 252, 248, 244, 240, 236, 232, 228, 224, - 220, 216, 212, 208, 204, 200, 196, 192, - 189, 187, 185, 183, 181, 179, 177, 175, - 173, 171, 169, 167, 165, 163, 161, 159, - 157, 156, 155, 154, 153, 152, 151, 150, - 149, 148, 147, 146, 145, 144, 143, 142, - 142, 141, 141, 140, 140, 139, 139, 138, - 138, 137, 137, 136, 136, 135, 135, 134, - 134, 134, 133, 133, 133, 133, 132, 132, - 132, 132, 131, 131, 131, 131, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 128, 128, 128, 128, + 3, 7, 11, 15, 19, 23, 27, 31, + 35, 39, 43, 47, 51, 55, 59, 63, + 66, 68, 70, 72, 74, 76, 78, 80, + 82, 84, 86, 88, 90, 92, 94, 96, + 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, + 113, 114, 114, 115, 115, 116, 116, 117, + 117, 118, 118, 119, 119, 120, 120, 121, + 121, 121, 122, 122, 122, 122, 123, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 126, 126, 126, 126, + 126, 126, 126, 126, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 253, 249, 245, 241, 237, 233, 229, 225, + 221, 217, 213, 209, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 174, 172, 170, 168, 166, 164, 162, 160, + 158, 157, 156, 155, 154, 153, 152, 151, + 150, 149, 148, 147, 146, 145, 144, 143, + 143, 142, 142, 141, 141, 140, 140, 139, + 139, 138, 138, 137, 137, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 133, 133, + 133, 133, 132, 132, 132, 132, 131, 131, + 131, 131, 131, 131, 130, 130, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, }; static unsigned char dsp_ulaw[] = { - 31, 31, 31, 32, 32, 32, 32, 33, - 33, 33, 33, 34, 34, 34, 34, 35, - 35, 35, 35, 36, 36, 36, 36, 37, - 37, 37, 37, 38, 38, 38, 38, 39, - 39, 39, 39, 40, 40, 40, 40, 41, - 41, 41, 41, 42, 42, 42, 42, 43, - 43, 43, 43, 44, 44, 44, 44, 45, - 45, 45, 45, 46, 46, 46, 46, 47, - 47, 47, 47, 48, 48, 49, 49, 50, - 50, 51, 51, 52, 52, 53, 53, 54, - 54, 55, 55, 56, 56, 57, 57, 58, - 58, 59, 59, 60, 60, 61, 61, 62, - 62, 63, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 81, 83, 85, 87, 89, - 91, 93, 95, 99, 103, 107, 111, 119, - 255, 247, 239, 235, 231, 227, 223, 221, - 219, 217, 215, 213, 211, 209, 207, 206, - 205, 204, 203, 202, 201, 200, 199, 198, - 197, 196, 195, 194, 193, 192, 191, 191, - 190, 190, 189, 189, 188, 188, 187, 187, - 186, 186, 185, 185, 184, 184, 183, 183, - 182, 182, 181, 181, 180, 180, 179, 179, - 178, 178, 177, 177, 176, 176, 175, 175, - 175, 175, 174, 174, 174, 174, 173, 173, - 173, 173, 172, 172, 172, 172, 171, 171, - 171, 171, 170, 170, 170, 170, 169, 169, - 169, 169, 168, 168, 168, 168, 167, 167, - 167, 167, 166, 166, 166, 166, 165, 165, - 165, 165, 164, 164, 164, 164, 163, 163, - 163, 163, 162, 162, 162, 162, 161, 161, - 161, 161, 160, 160, 160, 160, 159, 159, + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, + 3, 4, 4, 4, 4, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, + 7, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, + 13, 14, 14, 14, 14, 15, 15, 15, + 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 21, 22, 22, 23, + 23, 24, 24, 25, 25, 26, 26, 27, + 27, 28, 28, 29, 29, 30, 30, 31, + 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, + 47, 49, 51, 53, 55, 57, 59, 61, + 63, 66, 70, 74, 78, 84, 92, 104, + 254, 231, 219, 211, 205, 201, 197, 193, + 190, 188, 186, 184, 182, 180, 178, 176, + 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 160, + 159, 159, 158, 158, 157, 157, 156, 156, + 155, 155, 154, 154, 153, 153, 152, 152, + 151, 151, 150, 150, 149, 149, 148, 148, + 147, 147, 146, 146, 145, 145, 144, 144, + 143, 143, 143, 143, 142, 142, 142, 142, + 141, 141, 141, 141, 140, 140, 140, 140, + 139, 139, 139, 139, 138, 138, 138, 138, + 137, 137, 137, 137, 136, 136, 136, 136, + 135, 135, 135, 135, 134, 134, 134, 134, + 133, 133, 133, 133, 132, 132, 132, 132, + 131, 131, 131, 131, 130, 130, 130, 130, + 129, 129, 129, 129, 128, 128, 128, 128, }; diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index d3b6e484fc8a..4183b88b145e 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h @@ -12,6 +12,8 @@ /* Internal header file for autofs */ +#define DEBUG_WAITLIST 1 + #include /* This is the range of ioctl() numbers we claim as ours */ @@ -120,7 +122,10 @@ struct autofs_symlink { #define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1)) #endif +#define AUTOFS_SBI_MAGIC 0x6d4a556d + struct autofs_sb_info { + u32 magic; struct file *pipe; pid_t oz_pgrp; int catatonic; @@ -137,6 +142,15 @@ static inline int autofs_oz_mode(struct autofs_sb_info *sbi) { return sbi->catatonic || current->pgrp == sbi->oz_pgrp; } +/* Debug the mysteriously disappearing wait list */ + +#ifdef DEBUG_WAITLIST +#define CHECK_WAITLIST(S,O) autofs_check_waitlist_integrity(S,O) +void autofs_check_waitlist_integrity(struct autofs_sb_info *,char *); +#else +#define CHECK_WAITLIST(S,O) +#endif + /* Hash operations */ autofs_hash_t autofs_hash(const char *,int); diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index a8c176a02d32..20ca0907ad9c 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -150,6 +150,7 @@ struct super_block *autofs_read_super(struct super_block *s, void *data, DPRINTK(("autofs: starting up, sbi = %p\n",sbi)); s->u.generic_sbp = sbi; + sbi->magic = AUTOFS_SBI_MAGIC; sbi->catatonic = 0; sbi->exp_timeout = 0; sbi->oz_pgrp = current->pgrp; diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 57449e8165e2..69e62f823362 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -190,30 +190,33 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con DPRINTK(("autofs_root_symlink: %s <- ", symname)); autofs_say(name,len); - iput(dir); - - if ( !autofs_oz_mode(sbi) ) + if ( !autofs_oz_mode(sbi) ) { + iput(dir); return -EPERM; - - if ( autofs_hash_lookup(dh,hash,name,len) ) + } + if ( autofs_hash_lookup(dh,hash,name,len) ) { + iput(dir); return -EEXIST; - + } n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS); - if ( n >= AUTOFS_MAX_SYMLINKS ) + if ( n >= AUTOFS_MAX_SYMLINKS ) { + iput(dir); return -ENOSPC; - + } set_bit(n,sbi->symlink_bitmap); sl = &sbi->symlink[n]; sl->len = strlen(symname); sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL); if ( !sl->data ) { clear_bit(n,sbi->symlink_bitmap); + iput(dir); return -ENOSPC; } ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); if ( !ent ) { kfree(sl->data); clear_bit(n,sbi->symlink_bitmap); + iput(dir); return -ENOSPC; } ent->name = kmalloc(len, GFP_KERNEL); @@ -221,6 +224,7 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con kfree(sl->data); kfree(ent); clear_bit(n,sbi->symlink_bitmap); + iput(dir); return -ENOSPC; } memcpy(sl->data,symname,slsize); @@ -231,6 +235,7 @@ static int autofs_root_symlink(struct inode *dir, const char *name, int len, con memcpy(ent->name,name,ent->len = len); autofs_hash_insert(dh,ent); + iput(dir); return 0; } @@ -243,15 +248,19 @@ static int autofs_root_unlink(struct inode *dir, const char *name, int len) struct autofs_dir_ent *ent; unsigned int n; + iput(dir); /* Nothing below can sleep */ + if ( !autofs_oz_mode(sbi) ) return -EPERM; ent = autofs_hash_lookup(dh,hash,name,len); if ( !ent ) return -ENOENT; + n = ent->ino - AUTOFS_FIRST_SYMLINK; if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) ) return -EINVAL; /* Not a symlink inode, can't unlink */ + autofs_hash_delete(ent); clear_bit(n,sbi->symlink_bitmap); kfree(sbi->symlink[n].data); diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c index b37745f19798..719e04eb4486 100644 --- a/fs/autofs/waitq.c +++ b/fs/autofs/waitq.c @@ -16,6 +16,46 @@ #include #include "autofs_i.h" +#ifdef DEBUG_WAITLIST +#ifndef i386 +#error Only i386 implemented +#endif + +static inline int sane_pointer(void *p) +{ + return (p == NULL) || ((unsigned) p > 0xc0000000); +} + +void autofs_check_waitlist_integrity(struct autofs_sb_info *sbi, char *op) +{ + struct autofs_wait_queue **wqp, *wq; + + if ( sbi->magic != AUTOFS_SBI_MAGIC ) { + printk("autofs: CHECK_WAITLIST with bogus sbi pointer: %p\n", + sbi); + return; + } + + wqp = &(sbi->queues); + while ( (wq = *wqp) ) { + if ( !sane_pointer(wq) ) { + printk("autofs(%s): wait queue pointer corrupt: ", op); + wqp = &(sbi->queues); + do { + wq = *wqp; + printk(" %p", wq); + wqp = &(wq->next); + } while ( sane_pointer(*wqp) ); + printk("\n"); + *wqp = NULL; + break; + } else { + wqp = &(wq->next); + } + } +} +#endif + /* We make this a static variable rather than a part of the superblock; it is better if we don't reassign numbers easily even across filesystems */ static int autofs_next_wait_queue = 1; @@ -95,6 +135,8 @@ int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name struct autofs_wait_queue *wq; int status; + CHECK_WAITLIST(sbi,"wait"); + for ( wq = sbi->queues ; wq ; wq = wq->next ) { if ( wq->hash == hash && wq->len == len && @@ -148,6 +190,8 @@ int autofs_wait_release(struct autofs_sb_info *sbi, unsigned long wait_queue_tok { struct autofs_wait_queue *wq, **wql; + CHECK_WAITLIST(sbi,"release"); + for ( wql = &sbi->queues ; (wq = *wql) ; wql = &wq->next ) { if ( wq->wait_queue_token == wait_queue_token ) break; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 3c17b6eec206..4e2de9cfc903 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -178,7 +178,7 @@ nfs_writepage_sync(struct inode *inode, struct page *page, wsize = count; result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), - offset, wsize, IS_SWAPFILE(inode), + IS_SWAPFILE(inode), offset, wsize, buffer, &fattr); if (result < 0) { diff --git a/fs/proc/array.c b/fs/proc/array.c index aedecc322fe5..2c7da59c26a9 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -297,20 +297,14 @@ static int get_uptime(char * buffer) static int get_meminfo(char * buffer) { struct sysinfo i; - int len; si_meminfo(&i); si_swapinfo(&i); - len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n" - "Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n" - "Swap: %8lu %8lu %8lu\n", - i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, page_cache_size*PAGE_SIZE, - i.totalswap, i.totalswap-i.freeswap, i.freeswap); + /* - * Tagged format, for easy grepping and expansion. The above will go away - * eventually, once the tools have been updated. + * Tagged format, for easy grepping and expansion. */ - return len + sprintf(buffer+len, + return sprintf(buffer, "MemTotal: %8lu kB\n" "MemFree: %8lu kB\n" "MemShared: %8lu kB\n" diff --git a/include/linux/mtio.h b/include/linux/mtio.h index 2e20465a65df..9381d30a3d7f 100644 --- a/include/linux/mtio.h +++ b/include/linux/mtio.h @@ -225,6 +225,9 @@ struct mtconfiginfo { #define MT_ST_WRITE_THRESHOLD 0x20000000 #define MT_ST_DEF_BLKSIZE 0x50000000 #define MT_ST_DEF_OPTIONS 0x60000000 +#define MT_ST_TIMEOUTS 0x70000000 +#define MT_ST_SET_TIMEOUT (MT_ST_TIMEOUTS | 0x000000) +#define MT_ST_SET_LONG_TIMEOUT (MT_ST_TIMEOUTS | 0x100000) #define MT_ST_BUFFER_WRITES 0x1 #define MT_ST_ASYNC_WRITES 0x2 @@ -238,6 +241,7 @@ struct mtconfiginfo { #define MT_ST_NO_BLKLIMS 0x200 #define MT_ST_CAN_PARTITIONS 0x400 #define MT_ST_SCSI2LOGICAL 0x800 +#define MT_ST_SYSV 0x1000 /* The mode parameters to be controlled. Parameter chosen with bits 20-28 */ #define MT_ST_CLEAR_DEFAULT 0xfffff diff --git a/include/linux/soundcard.h b/include/linux/soundcard.h index bb338c462469..1626ea917b95 100644 --- a/include/linux/soundcard.h +++ b/include/linux/soundcard.h @@ -33,7 +33,7 @@ * Use ioctl(fd, OSS_GETVERSION, &int) to get the version number of * the currently active driver. */ -#define SOUND_VERSION 0x0307f1 +#define SOUND_VERSION 0x030800 #define OPEN_SOUND_SYSTEM /* In Linux we need to be prepared for cross compiling */ @@ -76,7 +76,7 @@ */ #ifndef _SIOWR -#if defined(_IOWR) && !defined(sun) && !defined(sparc) +#if defined(_IOWR) && (defined(_AIX) || (!defined(sun) && !defined(sparc) && !defined(__INCioctlh) && !defined(__Lynx__))) /* Use already defined ioctl defines if they exist (except with Sun) */ #define SIOCPARM_MASK IOCPARM_MASK #define SIOC_VOID IOC_VOID @@ -127,7 +127,7 @@ #define SNDCTL_SEQ_GETOUTCOUNT _SIOR ('Q', 4, int) #define SNDCTL_SEQ_GETINCOUNT _SIOR ('Q', 5, int) #define SNDCTL_SEQ_PERCMODE _SIOW ('Q', 6, int) -#define SNDCTL_FM_LOAD_INSTR _SIOW ('Q', 7, struct sbi_instrument) /* Obsolete */ +#define SNDCTL_FM_LOAD_INSTR _SIOW ('Q', 7, struct sbi_instrument) /* Obsolete. Don't use. */ #define SNDCTL_SEQ_TESTMIDI _SIOW ('Q', 8, int) #define SNDCTL_SEQ_RESETSAMPLES _SIOW ('Q', 9, int) #define SNDCTL_SEQ_NRSYNTHS _SIOR ('Q',10, int) @@ -140,10 +140,25 @@ #define SNDCTL_SEQ_OUTOFBAND _SIOW ('Q',18, struct seq_event_rec) #define SNDCTL_SEQ_GETTIME _SIOR ('Q',19, int) #define SNDCTL_SYNTH_ID _SIOWR('Q',20, struct synth_info) +#define SNDCTL_SYNTH_CONTROL _SIOWR('Q',21, struct synth_control) +#define SNDCTL_SYNTH_REMOVESAMPLE _SIOWR('Q',22, struct remove_sample) - struct seq_event_rec { - unsigned char arr[8]; - }; +typedef struct synth_control +{ + int devno; /* Synthesizer # */ + char data[4000]; /* Device spesific command/data record */ +}synth_control; + +typedef struct remove_sample +{ + int devno; /* Synthesizer # */ + int bankno; /* MIDI bank # (0=General MIDI) */ + int instrno; /* MIDI instrument number */ +} remove_sample; + +typedef struct seq_event_rec { + unsigned char arr[8]; +} seq_event_rec; #define SNDCTL_TMR_TIMEBASE _SIOWR('T', 1, int) #define SNDCTL_TMR_START _SIO ('T', 2) diff --git a/kernel/exit.c b/kernel/exit.c index b0fcfef1a7ab..7fa512da7532 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -32,6 +32,7 @@ int getrusage(struct task_struct *, int, struct rusage *); static inline void generate(unsigned long sig, struct task_struct * p) { + unsigned flags; unsigned long mask = 1 << (sig-1); struct sigaction * sa = sig + p->sig->action - 1; @@ -40,7 +41,7 @@ static inline void generate(unsigned long sig, struct task_struct * p) * be handled immediately (ie non-blocked and untraced) * and that is ignored (either explicitly or by default) */ - spin_lock_irq(&p->sig->siglock); + spin_lock_irqsave(&p->sig->siglock, flags); if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) { /* don't bother with ignored signals (but SIGCHLD is special) */ if (sa->sa_handler == SIG_IGN && sig != SIGCHLD) @@ -56,7 +57,7 @@ static inline void generate(unsigned long sig, struct task_struct * p) if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked)) wake_up_process(p); out: - spin_unlock_irq(&p->sig->siglock); + spin_unlock_irqrestore(&p->sig->siglock, flags); } /* @@ -67,10 +68,11 @@ void force_sig(unsigned long sig, struct task_struct * p) { sig--; if (p->sig) { + unsigned flags; unsigned long mask = 1UL << sig; struct sigaction *sa = p->sig->action + sig; - spin_lock_irq(&p->sig->siglock); + spin_lock_irqsave(&p->sig->siglock, flags); spin_lock(&p->sigmask_lock); p->signal |= mask; @@ -82,7 +84,7 @@ void force_sig(unsigned long sig, struct task_struct * p) if (p->state == TASK_INTERRUPTIBLE) wake_up_process(p); - spin_unlock_irq(&p->sig->siglock); + spin_unlock_irqrestore(&p->sig->siglock, flags); } } @@ -97,7 +99,8 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv) return -EPERM; if (sig && p->sig) { - spin_lock_irq(&p->sigmask_lock); + unsigned flags; + spin_lock_irqsave(&p->sigmask_lock, flags); if ((sig == SIGKILL) || (sig == SIGCONT)) { if (p->state == TASK_STOPPED) wake_up_process(p); @@ -107,7 +110,7 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv) } if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) p->signal &= ~(1<<(SIGCONT-1)); - spin_unlock_irq(&p->sigmask_lock); + spin_unlock_irqrestore(&p->sigmask_lock, flags); /* Actually generate the signal */ generate(sig,p); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 1fbb9512a008..74ae66240c0f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -343,4 +343,3 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, swap_free(entry); return; } - diff --git a/mm/slab.c b/mm/slab.c index 85d02894c2ae..79362a325832 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1433,6 +1433,7 @@ alloc_new_slab: /* Someone may have stolen our objs. Doesn't matter, we'll * just come back here again. */ + spin_lock_irq(&cachep->c_spinlock); goto try_again; } /* Couldn't grow, but some objs may have been freed. */ diff --git a/mm/vmscan.c b/mm/vmscan.c index d890be5df7cc..875f668eed00 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -345,7 +345,7 @@ out: * to be. This works out OK, because we now do proper aging on page * contents. */ -int try_to_free_page(int priority, int dma, int wait) +static inline int do_try_to_free_page(int priority, int dma, int wait) { static int state = 0; int i=6; @@ -379,6 +379,22 @@ int try_to_free_page(int priority, int dma, int wait) return 0; } +/* + * This is REALLY ugly. + * + * We need to make the locks finer granularity, but right + * now we need this so that we can do page allocations + * without holding the kernel lock etc. + */ +int try_to_free_page(int priority, int dma, int wait) +{ + int retval; + + lock_kernel(); + retval = do_try_to_free_page(priority,dma,wait); + unlock_kernel(); + return retval; +} /* * The background pageout daemon. -- 2.39.5