diff -u --recursive --new-file v2.1.40/linux/Makefile linux/Makefile --- v2.1.40/linux/Makefile Sat May 24 09:10:22 1997 +++ linux/Makefile Sat May 24 09:09:51 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.1.40/linux/drivers/isdn/isdn_net.c Tue May 13 22:41:08 1997 +++ linux/drivers/isdn/isdn_net.c Tue May 27 11:34:02 1997 @@ -374,7 +374,7 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/pnp/parport_procfs.c linux/drivers/pnp/parport_procfs.c --- v2.1.40/linux/drivers/pnp/parport_procfs.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/pnp/parport_procfs.c Sat May 24 09:07:57 1997 @@ -16,10 +16,10 @@ #include #include #include -#include #include #include #include +#include #include diff -u --recursive --new-file v2.1.40/linux/drivers/pnp/parport_share.c linux/drivers/pnp/parport_share.c --- v2.1.40/linux/drivers/pnp/parport_share.c Wed Apr 23 19:01:21 1997 +++ linux/drivers/pnp/parport_share.c Sat May 24 09:06:34 1997 @@ -220,6 +220,7 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v2.1.40/linux/drivers/scsi/README.st Wed Jan 1 08:54:02 1997 +++ linux/drivers/scsi/README.st Tue May 27 13:20:09 1997 @@ -2,7 +2,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.1.40/linux/drivers/scsi/st.c Fri Apr 4 08:52:23 1997 +++ linux/drivers/scsi/st.c Tue May 27 13:20:09 1997 @@ -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 @@ } 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ ((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 @@ 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 @@ 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 @@ } 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 @@ if(st_template.module) __MOD_DEC_USE_COUNT(st_template.module); - return 0; + return result; } @@ -1083,7 +1110,7 @@ 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 @@ } 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 @@ 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 @@ 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%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 @@ 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 @@ 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_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 @@ 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 @@ 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 @@ (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_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 @@ 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 @@ 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 @@ 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 @@ } #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 @@ 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 @@ 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 @@ (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 @@ 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 @@ 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 @@ } #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 @@ 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 @@ 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 @@ /* 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 @@ 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_registered = 0; -/* Driver initialization */ +/* Driver initialization (not __initfunc because may be called later) */ static int st_init() { int i; @@ -3213,8 +3263,25 @@ #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 -u --recursive --new-file v2.1.40/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.1.40/linux/drivers/scsi/st.h Wed Jan 1 08:54:02 1997 +++ linux/drivers/scsi/st.h Tue May 27 13:20:09 1997 @@ -20,6 +20,7 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h --- v2.1.40/linux/drivers/scsi/st_options.h Thu Jan 2 10:27:46 1997 +++ linux/drivers/scsi/st_options.h Tue May 27 13:20:09 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/.version linux/drivers/sound/.version --- v2.1.40/linux/drivers/sound/.version Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/.version Sun May 11 02:58:40 1997 @@ -1,2 +1,2 @@ -3.8-beta9 -0x030803 +3.8a +0x030804 diff -u --recursive --new-file v2.1.40/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v2.1.40/linux/drivers/sound/CHANGELOG Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/CHANGELOG Sun May 11 02:58:43 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.40/linux/drivers/sound/Config.in Tue May 13 22:41:13 1997 +++ linux/drivers/sound/Config.in Sun May 11 02:59:35 1997 @@ -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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/Config.std linux/drivers/sound/Config.std --- v2.1.40/linux/drivers/sound/Config.std Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/Config.std Sun May 11 02:59:35 1997 @@ -44,7 +44,7 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.40/linux/drivers/sound/Makefile Sun Nov 17 14:33:33 1996 +++ linux/drivers/sound/Makefile Sun May 11 02:58:39 1997 @@ -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 @@ install: sound.o cp sound.o $(MODULEDIR) +else endif .c.o: @@ -159,5 +186,6 @@ # ifeq (.depend,$(wildcard .depend)) include .depend +endif endif endif diff -u --recursive --new-file v2.1.40/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v2.1.40/linux/drivers/sound/Readme Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/Readme Sun May 11 02:58:41 1997 @@ -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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards --- v2.1.40/linux/drivers/sound/Readme.cards Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/Readme.cards Sun May 11 02:58:42 1997 @@ -43,8 +43,8 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux --- v2.1.40/linux/drivers/sound/Readme.linux Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/Readme.linux Sun May 11 02:58:40 1997 @@ -72,171 +72,14 @@ 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 +SURPRISE SURPRISE!!! -if [ -e /dev/dspW1 ]; then - rm -f /dev/dspW1 -fi -mknod -m $AUDIOPERMS /dev/dspW1 c 14 37 +The device file creation script that used to be here earlier is +obviously not here any more. -# -# 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 +Why? -# -# 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 +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 -u --recursive --new-file v2.1.40/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30 --- v2.1.40/linux/drivers/sound/Readme.v30 Fri Nov 15 00:15:00 1996 +++ linux/drivers/sound/Readme.v30 Wed Dec 31 16:00:00 1969 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.40/linux/drivers/sound/ad1848.c Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/ad1848.c Sun May 11 02:58:54 1997 @@ -71,6 +71,7 @@ int irq_ok; mixer_ents *mix_devices; int mixer_output_port; + int c930_password_port; } ad1848_info; @@ -107,7 +108,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ restore_flags (flags); } - static int ad1848_set_recmask (ad1848_info * devc, int mask) { @@ -381,16 +364,32 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* * 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 @@ else ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ + if (ad_flags) *ad_flags = 0; @@ -1630,6 +1672,15 @@ 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 @@ 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 @@ 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 @@ 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_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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ -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 @@ 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 @@ * 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 @@ } } 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h --- v2.1.40/linux/drivers/sound/ad1848_mixer.h Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/ad1848_mixer.h Sun May 11 02:58:33 1997 @@ -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 @@ * 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 @@ * 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.40/linux/drivers/sound/audio.c Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/audio.c Sun May 11 02:58:55 1997 @@ -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 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 @@ { if (fmt != AFMT_QUERY) { - local_conversion[dev] = 0; if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ @@ -57,10 +54,10 @@ 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 @@ local_conversion[dev] = 0; - if (dev_type == SND_DEV_AUDIO) { set_format (dev, AFMT_MU_LAW); @@ -127,19 +123,12 @@ /* 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 @@ { 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 @@ 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 @@ } 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 @@ 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 @@ * 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ !(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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ { 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v2.1.40/linux/drivers/sound/configure.c Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/configure.c Sun May 11 02:58:58 1997 @@ -145,7 +145,7 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.1.40/linux/drivers/sound/dev_table.c Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/dev_table.c Sun May 11 02:58:59 1997 @@ -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 @@ #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 @@ /* * 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.1.40/linux/drivers/sound/dev_table.h Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/dev_table.h Sun May 11 02:58:34 1997 @@ -70,6 +70,7 @@ char *raw_buf; unsigned long raw_buf_phys; + int buffsize; /* * Device state tables @@ -85,6 +86,8 @@ #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 @@ 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 @@ 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 @@ 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 @@ #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 @@ 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 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 @@ {"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 @@ # 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 @@ {"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 @@ #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 -u --recursive --new-file v2.1.40/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.40/linux/drivers/sound/dmabuf.c Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/dmabuf.c Sun May 11 02:59:01 1997 @@ -12,7 +12,7 @@ */ #include -#undef BE_CONSERVATIVE +#define BE_CONSERVATIVE #include "sound_config.h" @@ -44,18 +44,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ */ int pos; unsigned long flags; - int chan = dmap->dma; save_flags (flags); cli (); @@ -697,26 +719,31 @@ 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 @@ 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 @@ if (len >= max) return 0; - return 1; + return max - len; } static int @@ -812,7 +839,7 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } - 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 @@ 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 @@ dmap->cfrag = -1; - prev_count = dmap->user_counter; dmap->user_counter += l; + dmap->flags |= DMA_DIRTY; - if (dmap->user_counter < prev_count) /* Wrap? */ - { /* Wrap the device counter too */ - dmap->byte_counter %= dmap->bytes_in_use; + if (dmap->user_counter >= dmap->max_byte_counter) + { /* Wrap the byte counters */ + long decr = dmap->user_counter; + + 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ } 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; + if (audio_devs[dev]->dmap_out == NULL) + { + if (audio_devs[dev]->d == NULL) + panic ("OSS: audio_devs[%d]->d == NULL\n", dev); - 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]->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 @@ 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; @@ -1447,6 +1526,9 @@ 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) { diff -u --recursive --new-file v2.1.40/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.1.40/linux/drivers/sound/dmasound.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/dmasound.c Sun May 11 02:59:34 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/dmasound.h linux/drivers/sound/dmasound.h --- v2.1.40/linux/drivers/sound/dmasound.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/dmasound.h Sun May 11 02:59:34 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.40/linux/drivers/sound/gus_card.c Tue Mar 4 10:25:24 1997 +++ linux/drivers/sound/gus_card.c Sun May 11 02:59:02 1997 @@ -123,7 +123,7 @@ #ifdef CONFIG_GUSMAX if (have_gus_max) - ad1848_interrupt (irq, NULL, NULL); + adintr (irq, NULL, NULL); #endif while (1) diff -u --recursive --new-file v2.1.40/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.1.40/linux/drivers/sound/gus_midi.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/gus_midi.c Sun May 11 02:59:02 1997 @@ -248,6 +248,7 @@ std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &gus_midi_operations; + sequencer_init (); return; } diff -u --recursive --new-file v2.1.40/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.40/linux/drivers/sound/gus_wave.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/gus_wave.c Sun May 11 02:59:06 1997 @@ -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 @@ 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 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 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 @@ /* * 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 @@ 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 @@ 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 @@ 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_read8 (0x0f); /* Clear pending IRQs */ + if (iw_mode) + gus_write8 (0x19, gus_read8 (0x19) | 0x01); restore_flags (flags); } @@ -1022,10 +1042,10 @@ */ 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 @@ 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 @@ 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 @@ 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 @@ * 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; - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + 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 */ + } /* * Start the DMA transfer @@ -2280,6 +2325,7 @@ } } +static int saved_iw_mode; /* A hack hack hack */ static int gus_audio_open (int dev, int mode) @@ -2300,6 +2346,13 @@ 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 @@ static void gus_audio_close (int dev) { + iw_mode = saved_iw_mode; gus_reset (); gus_busy = 0; pcm_opened = 0; @@ -2428,7 +2482,7 @@ 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 @@ } 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 @@ 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 @@ */ 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 (); } @@ -2567,13 +2604,58 @@ } 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ gus_audio_prepare_for_output, gus_audio_reset, gus_local_qlen, - gus_copy_from_user + NULL }; static void @@ -3218,7 +3253,10 @@ 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_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 @@ 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 @@ } /* - * 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 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/lowlevel/Config.tmpl linux/drivers/sound/lowlevel/Config.tmpl --- v2.1.40/linux/drivers/sound/lowlevel/Config.tmpl Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/lowlevel/Config.tmpl Fri Apr 4 09:06:22 1997 @@ -32,7 +32,7 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/lowlevel/aci.c linux/drivers/sound/lowlevel/aci.c --- v2.1.40/linux/drivers/sound/lowlevel/aci.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/lowlevel/aci.c Fri Mar 7 04:08:42 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.1.40/linux/drivers/sound/maui.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/maui.c Sun May 11 02:59:09 1997 @@ -333,7 +333,7 @@ { 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v2.1.40/linux/drivers/sound/midi_synth.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/midi_synth.c Sun May 11 02:59:10 1997 @@ -537,7 +537,7 @@ { 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.1.40/linux/drivers/sound/midibuf.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/midibuf.c Sun May 11 02:59:11 1997 @@ -12,6 +12,7 @@ */ #include +#define MIDIBUF_C #include "sound_config.h" diff -u --recursive --new-file v2.1.40/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.1.40/linux/drivers/sound/mpu401.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/mpu401.c Sun May 11 02:59:12 1997 @@ -1183,6 +1183,7 @@ irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; + sequencer_init (); } static int diff -u --recursive --new-file v2.1.40/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.1.40/linux/drivers/sound/opl3.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/opl3.c Sun May 11 23:01:14 1997 @@ -112,6 +112,7 @@ 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_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 -u --recursive --new-file v2.1.40/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v2.1.40/linux/drivers/sound/os.h Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/os.h Sun May 11 02:58:40 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.1.40/linux/drivers/sound/pas2_card.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/pas2_card.c Sun May 11 02:59:14 1997 @@ -283,7 +283,7 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v2.1.40/linux/drivers/sound/pas2_midi.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/pas2_midi.c Sun May 11 02:59:15 1997 @@ -236,6 +236,7 @@ std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &pas_midi_operations; + sequencer_init (); } void diff -u --recursive --new-file v2.1.40/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v2.1.40/linux/drivers/sound/pas2_pcm.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/pas2_pcm.c Sun May 11 02:59:16 1997 @@ -55,12 +55,12 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/pnp.c linux/drivers/sound/pnp.c --- v2.1.40/linux/drivers/sound/pnp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/pnp.c Sun May 11 02:59:16 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/pnp.h linux/drivers/sound/pnp.h --- v2.1.40/linux/drivers/sound/pnp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/pnp.h Sun May 11 02:58:36 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.1.40/linux/drivers/sound/sb.h Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sb.h Sun May 11 02:58:36 1997 @@ -105,6 +105,7 @@ /* MIDI fields */ int my_mididev; int input_opened; + int midi_broken; void (*midi_input_intr) (int dev, unsigned char data); } sb_devc; diff -u --recursive --new-file v2.1.40/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.40/linux/drivers/sound/sb_common.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sb_common.c Sun May 11 02:59:20 1997 @@ -58,10 +58,7 @@ 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 @@ break; default: - printk ("Sound Blaster: Unexpected interrupt\n"); + /* printk ("Sound Blaster: Unexpected interrupt\n"); */ + ; } /* * Acknowledge interrupts @@ -633,6 +631,7 @@ 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_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 @@ { 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 @@ #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 -u --recursive --new-file v2.1.40/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v2.1.40/linux/drivers/sound/sb_midi.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sb_midi.c Sun May 11 02:59:20 1997 @@ -52,6 +52,7 @@ restore_flags (flags); devc->irq_mode = IMODE_MIDI; + devc->midi_broken = 0; sb_dsp_reset (devc); @@ -96,9 +97,16 @@ 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 @@ midi_devs[num_midis]->converter->id = "SBMIDI"; num_midis++; + sequencer_init (); } #endif diff -u --recursive --new-file v2.1.40/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.40/linux/drivers/sound/sequencer.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sequencer.c Sun May 11 02:59:23 1997 @@ -24,6 +24,9 @@ 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 @@ unsigned long prev_input_time = 0; int prev_event_time; -unsigned long seq_time = 0; #include "tuning.h" @@ -312,6 +314,9 @@ 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 @@ 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 @@ default:; } +#undef dev +#undef cmd +#undef chn +#undef note +#undef parm } @@ -1105,6 +1116,7 @@ return -EBUSY; } sequencer_busy = 1; + obsolete_api_used = 0; restore_flags (flags); max_mididev = num_midis; @@ -1322,6 +1334,8 @@ 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 @@ break; case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SYNTH_REMOVESAMPLE: + case SNDCTL_SYNTH_CONTROL: { int err; @@ -1870,7 +1886,7 @@ */ 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 @@ } semitones = bend / 100; + if (semitones > 99) + semitones = 99; cents = bend % 100; amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) @@ -1955,6 +1973,10 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.1.40/linux/drivers/sound/sound_calls.h Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sound_calls.h Sun May 11 02:58:37 1997 @@ -10,7 +10,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ #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 -u --recursive --new-file v2.1.40/linux/drivers/sound/sound_pnp.c linux/drivers/sound/sound_pnp.c --- v2.1.40/linux/drivers/sound/sound_pnp.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/sound_pnp.c Sun May 11 02:59:25 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c --- v2.1.40/linux/drivers/sound/sound_switch.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sound_switch.c Sun May 11 02:59:26 1997 @@ -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 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.40/linux/drivers/sound/soundcard.c Fri Apr 4 08:52:23 1997 +++ linux/drivers/sound/soundcard.c Sun May 11 02:59:27 1997 @@ -139,8 +139,8 @@ sound_release_sw (dev, &files[dev]); #ifdef MODULE MOD_DEC_USE_COUNT; -#endif return 0; +#endif } static int @@ -156,7 +156,7 @@ 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 @@ if (ptr != NULL && alloced) vfree (ptr); - return err; + return ((err < 0) ? err : 0); } static int @@ -229,7 +229,7 @@ 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 @@ 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 @@ #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 @@ #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 @@ 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 @@ 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 @@ || 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 @@ 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 @@ 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 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h --- v2.1.40/linux/drivers/sound/soundvers.h Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/soundvers.h Sun May 11 03:16:26 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.1.40/linux/drivers/sound/sscape.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/sscape.c Sun May 11 02:59:28 1997 @@ -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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ /* * 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_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 @@ 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 @@ 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 @@ sscape_coproc_close, sscape_coproc_ioctl, sscape_coproc_reset, - &dev_info + &adev_info }; static int sscape_detected = 0; @@ -678,6 +670,7 @@ 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 @@ 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 @@ 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 @@ } #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 @@ for (cc = 0; cc < 200000; ++cc) inb (devc->base + ODIE_ADDR); } - else - old_hardware = 0; } @@ -891,6 +888,7 @@ 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 @@ } - 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 @@ 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 @@ 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 @@ -1006,6 +1011,7 @@ devc->dma, 0); } + #endif diff -u --recursive --new-file v2.1.40/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.1.40/linux/drivers/sound/trix.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/trix.c Sun May 11 02:59:29 1997 @@ -339,9 +339,19 @@ 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 -u --recursive --new-file v2.1.40/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.1.40/linux/drivers/sound/uart401.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/uart401.c Sun May 11 02:59:30 1997 @@ -346,6 +346,7 @@ strcpy (midi_devs[num_midis]->info.name, name); midi_devs[num_midis]->converter->id = "UART401"; num_midis++; + sequencer_init (); devc->opened = 0; } diff -u --recursive --new-file v2.1.40/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.1.40/linux/drivers/sound/uart6850.c Tue Mar 4 10:25:25 1997 +++ linux/drivers/sound/uart6850.c Sun May 11 02:59:30 1997 @@ -294,6 +294,7 @@ std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &uart6850_operations; + sequencer_init (); } static int diff -u --recursive --new-file v2.1.40/linux/drivers/sound/ulaw.h linux/drivers/sound/ulaw.h --- v2.1.40/linux/drivers/sound/ulaw.h Fri Nov 15 00:14:56 1996 +++ linux/drivers/sound/ulaw.h Sun May 11 02:58:39 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h --- v2.1.40/linux/fs/autofs/autofs_i.h Thu May 15 16:48:03 1997 +++ linux/fs/autofs/autofs_i.h Tue May 27 15:23:46 1997 @@ -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 @@ #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; @@ -136,6 +141,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 */ diff -u --recursive --new-file v2.1.40/linux/fs/autofs/inode.c linux/fs/autofs/inode.c --- v2.1.40/linux/fs/autofs/inode.c Tue May 13 22:41:14 1997 +++ linux/fs/autofs/inode.c Tue May 27 15:20:09 1997 @@ -150,6 +150,7 @@ 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 -u --recursive --new-file v2.1.40/linux/fs/autofs/root.c linux/fs/autofs/root.c --- v2.1.40/linux/fs/autofs/root.c Sat May 24 09:10:24 1997 +++ linux/fs/autofs/root.c Tue May 27 15:20:09 1997 @@ -190,30 +190,33 @@ 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 @@ kfree(sl->data); kfree(ent); clear_bit(n,sbi->symlink_bitmap); + iput(dir); return -ENOSPC; } memcpy(sl->data,symname,slsize); @@ -231,6 +235,7 @@ memcpy(ent->name,name,ent->len = len); autofs_hash_insert(dh,ent); + iput(dir); return 0; } @@ -243,15 +248,19 @@ 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 -u --recursive --new-file v2.1.40/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c --- v2.1.40/linux/fs/autofs/waitq.c Sat May 24 09:10:24 1997 +++ linux/fs/autofs/waitq.c Tue May 27 15:20:09 1997 @@ -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 @@ 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 && @@ -147,6 +189,8 @@ int autofs_wait_release(struct autofs_sb_info *sbi, unsigned long wait_queue_token, int status) { 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 ) diff -u --recursive --new-file v2.1.40/linux/fs/nfs/write.c linux/fs/nfs/write.c --- v2.1.40/linux/fs/nfs/write.c Tue May 13 22:41:15 1997 +++ linux/fs/nfs/write.c Sat May 24 09:07:22 1997 @@ -178,7 +178,7 @@ 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 -u --recursive --new-file v2.1.40/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.40/linux/fs/proc/array.c Sat May 24 09:10:24 1997 +++ linux/fs/proc/array.c Tue May 27 12:04:10 1997 @@ -297,20 +297,14 @@ 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 -u --recursive --new-file v2.1.40/linux/include/linux/mtio.h linux/include/linux/mtio.h --- v2.1.40/linux/include/linux/mtio.h Wed Jan 1 08:54:02 1997 +++ linux/include/linux/mtio.h Tue May 27 13:20:10 1997 @@ -225,6 +225,9 @@ #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 @@ #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 -u --recursive --new-file v2.1.40/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v2.1.40/linux/include/linux/soundcard.h Tue Mar 4 10:25:26 1997 +++ linux/include/linux/soundcard.h Sun May 11 23:02:24 1997 @@ -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 -u --recursive --new-file v2.1.40/linux/kernel/exit.c linux/kernel/exit.c --- v2.1.40/linux/kernel/exit.c Sat May 24 09:10:25 1997 +++ linux/kernel/exit.c Thu May 22 19:14:18 1997 @@ -32,6 +32,7 @@ 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 @@ * 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ } 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 -u --recursive --new-file v2.1.40/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.40/linux/mm/page_alloc.c Tue May 13 22:41:20 1997 +++ linux/mm/page_alloc.c Sat May 24 09:35:33 1997 @@ -343,4 +343,3 @@ swap_free(entry); return; } - diff -u --recursive --new-file v2.1.40/linux/mm/slab.c linux/mm/slab.c --- v2.1.40/linux/mm/slab.c Sat May 24 09:10:25 1997 +++ linux/mm/slab.c Tue May 27 11:45:01 1997 @@ -1433,6 +1433,7 @@ /* 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 -u --recursive --new-file v2.1.40/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.40/linux/mm/vmscan.c Tue May 13 22:41:20 1997 +++ linux/mm/vmscan.c Sat May 24 09:45:24 1997 @@ -345,7 +345,7 @@ * 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 @@ 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.