From: C.L. Tien - cmpci audio driver update. Changes, in reverse chronological order: - Load gameport driver only joystick == 1. - Change cm: -> cmpci: in debugging messages. - Remove ALLOCATE_IO since 8738-6ch will be used on HP's workstation. - Change IRQ print width. - Add inline back for those already have in kernel source tree. - Due to kernel team's oppinion, changes: 1. Return to save_irq/restore_irq. 2. Remove inline. 3. Remove PROC_FS support. 4. Remove some debugging messages. - Change mic_boost default as 0. - Change mic record gain setting for chip version 039 and later. - We don't need wave table. - Add mic_boost to control mic boost. - Only touch MIXER2 if we get MIC control. - Remove the DMA 16MB check. It is not useful. - Change to new style init/release. - Change wait/schedule and use list. - Add gameport support, now it can be loaded automatically. - Add SPDIF-IN in DSP_BIND and disable it after stop adc. - Use channel 0 for play and channel 1 for record, since I need SPDIF-in. - Fix typo. - Add ioctl for setting SPDIF out and in. - Change channel number in constants to DAC/ADC. This can ease switch channels. - Add more ioctl for SPDIF interface. - Implement write_proc, it only accept '0' for now. - Change const to macro. - Use different SPD24SEL for different chip versions. - Change register fields into document name. - Add interface of /proc, which can be used for configuration and info. - Add functions for SPDIF in/out and replace statements with them. - Add mic_as_boost back for ASUS. - Fix recording hang when SMP enabled. - Change the way handling mute. - Fix the code, now AUX can work as other sources. - Change OUTSRC, it is fully implemented now. - Add pseudo register and bits to support AUX volume/mute control. - Remove some mixer range check to allow value for pseudo bits work. - Change to SPDCOPYRHT. - Add SNDCTL_SPDIF_PROTECT ioctl, requested by ZapMedia and InterVideo. - Disable spdif out on all chip versions in set_dac_channels(). --- 25-akpm/sound/oss/cmpci.c | 1329 ++++++++++++++++++++++++++++++---------------- 1 files changed, 885 insertions(+), 444 deletions(-) diff -puN sound/oss/cmpci.c~cmpci.c-5.64 sound/oss/cmpci.c --- 25/sound/oss/cmpci.c~cmpci.c-5.64 2004-04-06 21:03:07.390540216 -0700 +++ 25-akpm/sound/oss/cmpci.c 2004-04-06 21:03:07.408537480 -0700 @@ -1,4 +1,5 @@ /*****************************************************************************/ + /* * cmpci.c -- C-Media PCI audio driver. * @@ -69,136 +70,167 @@ * (8738 only) * Fix bug cause x11amp cannot play. * - * Fixes: - * Arnaldo Carvalho de Melo - * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it - * was calling prog_dmabuf with s->lock held, call missing - * unlock_kernel in cm_midi_release - * 08/10/2001 - use set_current_state in some more places - * - * Carlos Eduardo Gorges - * Fri May 25 2001 - * - SMP support ( spin[un]lock* revision ) - * - speaker mixer support - * Mon Aug 13 2001 - * - optimizations and cleanups - * 03/01/2003 - open_mode fixes from Georg Acher - * */ + /*****************************************************************************/ +#define EXPORT_SYMTAB +#include #include #include #include -#include #include #include #include #include -#include +#include #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#endif +#include +#include #include #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) #include -#include -#include - -#include -#include +#endif +#else +#include +# define AFMT_AC3 0x00000400 /* Dolby Digital AC3 */ +# define DSP_CAP_BIND 0x00008000 /* channel binding to fr +ont/rear/cneter/lfe */ +#define SNDCTL_DSP_GETCHANNELMASK _SIOWR('P', 64, int) +#define SNDCTL_DSP_BIND_CHANNEL _SIOWR('P', 65, int) +# define DSP_BIND_QUERY 0x00000000 +# define DSP_BIND_FRONT 0x00000001 +# define DSP_BIND_SURR 0x00000002 +# define DSP_BIND_CENTER_LFE 0x00000004 +# define DSP_BIND_HANDSET 0x00000008 +# define DSP_BIND_MIC 0x00000010 +# define DSP_BIND_MODEM1 0x00000020 +# define DSP_BIND_MODEM2 0x00000040 +# define DSP_BIND_I2S 0x00000080 +# define DSP_BIND_SPDIF 0x00000100 +#endif #include +#include #include "dm.h" /* --------------------------------------------------------------------- */ + #undef OSS_DOCUMENTED_MIXER_SEMANTICS -#undef DMABYTEIO + /* --------------------------------------------------------------------- */ +#ifndef PCI_VENDOR_ID_CMEDIA +#define PCI_VENDOR_ID_CMEDIA 0x13F6 +#endif +#ifndef PCI_DEVICE_ID_CMEDIA_CM8338A +#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 +#endif +#ifndef PCI_DEVICE_ID_CMEDIA_CM8338B +#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 +#endif +#ifndef PCI_DEVICE_ID_CMEDIA_CM8738 +#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 +#endif +#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B +#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 +#endif + #define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A) -/* CM8338 registers definition ****************/ +/* + * CM8338 registers definition + */ -#define CODEC_CMI_FUNCTRL0 (0x00) -#define CODEC_CMI_FUNCTRL1 (0x04) -#define CODEC_CMI_CHFORMAT (0x08) -#define CODEC_CMI_INT_HLDCLR (0x0C) -#define CODEC_CMI_INT_STATUS (0x10) -#define CODEC_CMI_LEGACY_CTRL (0x14) -#define CODEC_CMI_MISC_CTRL (0x18) -#define CODEC_CMI_TDMA_POS (0x1C) -#define CODEC_CMI_MIXER (0x20) -#define CODEC_SB16_DATA (0x22) -#define CODEC_SB16_ADDR (0x23) -#define CODEC_CMI_MIXER1 (0x24) -#define CODEC_CMI_MIXER2 (0x25) -#define CODEC_CMI_AUX_VOL (0x26) -#define CODEC_CMI_MISC (0x27) -#define CODEC_CMI_AC97 (0x28) - -#define CODEC_CMI_CH0_FRAME1 (0x80) -#define CODEC_CMI_CH0_FRAME2 (0x84) -#define CODEC_CMI_CH1_FRAME1 (0x88) -#define CODEC_CMI_CH1_FRAME2 (0x8C) - -#define CODEC_CMI_EXT_REG (0xF0) - -/* Mixer registers for SB16 ******************/ - -#define DSP_MIX_DATARESETIDX ((unsigned char)(0x00)) - -#define DSP_MIX_MASTERVOLIDX_L ((unsigned char)(0x30)) -#define DSP_MIX_MASTERVOLIDX_R ((unsigned char)(0x31)) -#define DSP_MIX_VOICEVOLIDX_L ((unsigned char)(0x32)) -#define DSP_MIX_VOICEVOLIDX_R ((unsigned char)(0x33)) -#define DSP_MIX_FMVOLIDX_L ((unsigned char)(0x34)) -#define DSP_MIX_FMVOLIDX_R ((unsigned char)(0x35)) -#define DSP_MIX_CDVOLIDX_L ((unsigned char)(0x36)) -#define DSP_MIX_CDVOLIDX_R ((unsigned char)(0x37)) -#define DSP_MIX_LINEVOLIDX_L ((unsigned char)(0x38)) -#define DSP_MIX_LINEVOLIDX_R ((unsigned char)(0x39)) - -#define DSP_MIX_MICVOLIDX ((unsigned char)(0x3A)) -#define DSP_MIX_SPKRVOLIDX ((unsigned char)(0x3B)) - -#define DSP_MIX_OUTMIXIDX ((unsigned char)(0x3C)) - -#define DSP_MIX_ADCMIXIDX_L ((unsigned char)(0x3D)) -#define DSP_MIX_ADCMIXIDX_R ((unsigned char)(0x3E)) - -#define DSP_MIX_INGAINIDX_L ((unsigned char)(0x3F)) -#define DSP_MIX_INGAINIDX_R ((unsigned char)(0x40)) -#define DSP_MIX_OUTGAINIDX_L ((unsigned char)(0x41)) -#define DSP_MIX_OUTGAINIDX_R ((unsigned char)(0x42)) - -#define DSP_MIX_AGCIDX ((unsigned char)(0x43)) - -#define DSP_MIX_TREBLEIDX_L ((unsigned char)(0x44)) -#define DSP_MIX_TREBLEIDX_R ((unsigned char)(0x45)) -#define DSP_MIX_BASSIDX_L ((unsigned char)(0x46)) -#define DSP_MIX_BASSIDX_R ((unsigned char)(0x47)) - -#define CM_CH0_RESET 0x04 -#define CM_CH1_RESET 0x08 -#define CM_EXTENT_CODEC 0x100 -#define CM_EXTENT_MIDI 0x2 -#define CM_EXTENT_SYNTH 0x4 -#define CM_INT_CH0 1 -#define CM_INT_CH1 2 - -#define CM_CFMT_STEREO 0x01 -#define CM_CFMT_16BIT 0x02 -#define CM_CFMT_MASK 0x03 -#define CM_CFMT_DACSHIFT 2 -#define CM_CFMT_ADCSHIFT 0 +#define CODEC_CMI_FUNCTRL0 (0x00) +#define CODEC_CMI_FUNCTRL1 (0x04) +#define CODEC_CMI_CHFORMAT (0x08) +#define CODEC_CMI_INT_HLDCLR (0x0C) +#define CODEC_CMI_INT_STATUS (0x10) +#define CODEC_CMI_LEGACY_CTRL (0x14) +#define CODEC_CMI_MISC_CTRL (0x18) +#define CODEC_CMI_TDMA_POS (0x1C) +#define CODEC_CMI_MIXER (0x20) +#define CODEC_SB16_DATA (0x22) +#define CODEC_SB16_ADDR (0x23) +#define CODEC_CMI_MIXER1 (0x24) +#define CODEC_CMI_MIXER2 (0x25) +#define CODEC_CMI_AUX_VOL (0x26) +#define CODEC_CMI_MISC (0x27) +#define CODEC_CMI_AC97 (0x28) + +#define CODEC_CMI_CH0_FRAME1 (0x80) +#define CODEC_CMI_CH0_FRAME2 (0x84) +#define CODEC_CMI_CH1_FRAME1 (0x88) +#define CODEC_CMI_CH1_FRAME2 (0x8C) -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; +#define CODEC_CMI_EXT_REG (0xF0) +#define UCHAR unsigned char +/* +** Mixer registers for SB16 +*/ + +#define DSP_MIX_DATARESETIDX ((UCHAR)(0x00)) + +#define DSP_MIX_MASTERVOLIDX_L ((UCHAR)(0x30)) +#define DSP_MIX_MASTERVOLIDX_R ((UCHAR)(0x31)) +#define DSP_MIX_VOICEVOLIDX_L ((UCHAR)(0x32)) +#define DSP_MIX_VOICEVOLIDX_R ((UCHAR)(0x33)) +#define DSP_MIX_FMVOLIDX_L ((UCHAR)(0x34)) +#define DSP_MIX_FMVOLIDX_R ((UCHAR)(0x35)) +#define DSP_MIX_CDVOLIDX_L ((UCHAR)(0x36)) +#define DSP_MIX_CDVOLIDX_R ((UCHAR)(0x37)) +#define DSP_MIX_LINEVOLIDX_L ((UCHAR)(0x38)) +#define DSP_MIX_LINEVOLIDX_R ((UCHAR)(0x39)) + +#define DSP_MIX_MICVOLIDX ((UCHAR)(0x3A)) +#define DSP_MIX_SPKRVOLIDX ((UCHAR)(0x3B)) + +#define DSP_MIX_OUTMIXIDX ((UCHAR)(0x3C)) + +#define DSP_MIX_ADCMIXIDX_L ((UCHAR)(0x3D)) +#define DSP_MIX_ADCMIXIDX_R ((UCHAR)(0x3E)) + +#define DSP_MIX_INGAINIDX_L ((UCHAR)(0x3F)) +#define DSP_MIX_INGAINIDX_R ((UCHAR)(0x40)) +#define DSP_MIX_OUTGAINIDX_L ((UCHAR)(0x41)) +#define DSP_MIX_OUTGAINIDX_R ((UCHAR)(0x42)) + +#define DSP_MIX_AGCIDX ((UCHAR)(0x43)) + +#define DSP_MIX_TREBLEIDX_L ((UCHAR)(0x44)) +#define DSP_MIX_TREBLEIDX_R ((UCHAR)(0x45)) +#define DSP_MIX_BASSIDX_L ((UCHAR)(0x46)) +#define DSP_MIX_BASSIDX_R ((UCHAR)(0x47)) +#define CM_CH0_RESET 0x04 +#define CM_CH1_RESET 0x08 +#define CM_EXTENT_CODEC 0x100 +#define CM_EXTENT_MIDI 0x2 +#define CM_EXTENT_SYNTH 0x4 +#define CM_INT_CH0 1 +#define CM_INT_CH1 2 + +#define CM_CFMT_STEREO 0x01 +#define CM_CFMT_16BIT 0x02 +#define CM_CFMT_MASK 0x03 +#define CM_CFMT_DACSHIFT 2 +#define CM_CFMT_ADCSHIFT 0 + +static const unsigned sample_size[] = { 1, 2, 2, 4 }; +static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define CM_ENABLE_CH1 0x2 #define CM_ENABLE_CH0 0x1 -/* MIDI buffer sizes **************************/ + +/* MIDI buffer sizes */ #define MIDIINBUF 256 #define MIDIOUTBUF 256 @@ -211,35 +243,49 @@ static const unsigned sample_shift[] = { #define SND_DEV_DSP16 5 -#define NR_DEVICE 3 /* maximum number of devices */ +#define set_dac1_rate set_adc_rate +#define stop_dac1 stop_adc +#define get_dmadac1 get_dmaadc -/*********************************************/ +/* --------------------------------------------------------------------- */ struct cm_state { - unsigned int magic; /* magic */ - struct cm_state *next; /* we keep cm cards in a linked list */ + /* magic */ + unsigned int magic; - int dev_audio; /* soundcore stuff */ + /* we keep cm cards in a linked list */ + struct cm_state *next; + + /* soundcore stuff */ + int dev_audio; int dev_mixer; int dev_midi; int dev_dmfm; - unsigned int iosb, iobase, iosynth, - iomidi, iogame, irq; /* hardware resources */ - unsigned short deviceid; /* pci_id */ + /* hardware resources */ + unsigned int iosb, iobase, iosynth, iomidi, iogame, irq; + unsigned short deviceid; - struct { /* mixer stuff */ + /* mixer stuff */ + struct { unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } mix; - unsigned int rateadc, ratedac; /* wave stuff */ + /* wave stuff */ + unsigned int rateadc, ratedac; unsigned char fmt, enable; spinlock_t lock; struct semaphore open_sem; mode_t open_mode; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) wait_queue_head_t open_wait; +#else + struct wait_queue *open_wait; +#endif struct dmabuf { void *rawbuf; @@ -250,15 +296,19 @@ struct cm_state { unsigned hwptr, swptr; unsigned total_bytes; int count; - unsigned error; /* over/underrun */ + unsigned error; /* over/underrun */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) wait_queue_head_t wait; - - unsigned fragsize; /* redundant, but makes calculations easier */ +#else + struct wait_queue *wait; +#endif + /* redundant, but makes calculations easier */ + unsigned fragsize; unsigned dmasize; unsigned fragsamples; unsigned dmasamples; - - unsigned mapped:1; /* OSS stuff */ + /* OSS stuff */ + unsigned mapped:1; unsigned ready:1; unsigned endcleared:1; unsigned ossfragshift; @@ -266,78 +316,119 @@ struct cm_state { unsigned subdivision; } dma_dac, dma_adc; - struct { /* midi stuff */ + /* midi stuff */ + struct { unsigned ird, iwr, icnt; unsigned ord, owr, ocnt; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) wait_queue_head_t iwait; wait_queue_head_t owait; +#else + struct wait_queue *iwait; + struct wait_queue *owait; +#endif struct timer_list timer; unsigned char ibuf[MIDIINBUF]; unsigned char obuf[MIDIOUTBUF]; } midi; - int chip_version; + /* misc stuff */ + int modem; + int chip_version; int max_channels; - int curr_channels; - int speakers; /* number of speakers */ - int capability; /* HW capability, various for chip versions */ - - int status; /* HW or SW state */ + int curr_channels; + int speakers; // number of speakers + int capability; // HW capability, various for chip versions + int status; // HW or SW state - int spdif_counter; /* spdif frame counter */ + /* spdif frame counter */ + int spdif_counter; }; /* flags used for capability */ -#define CAN_AC3_HW 0x00000001 /* 037 or later */ -#define CAN_AC3_SW 0x00000002 /* 033 or later */ -#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW) -#define CAN_DUAL_DAC 0x00000004 /* 033 or later */ -#define CAN_MULTI_CH_HW 0x00000008 /* 039 or later */ -#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC) -#define CAN_LINE_AS_REAR 0x00000010 /* 033 or later */ -#define CAN_LINE_AS_BASS 0x00000020 /* 039 or later */ -#define CAN_MIC_AS_BASS 0x00000040 /* 039 or later */ +#define CAN_AC3_HW 0x00000001 // 037 or later +#define CAN_AC3_SW 0x00000002 // 033 or later +#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW) +#define CAN_DUAL_DAC 0x00000004 // 033 or later +#define CAN_MULTI_CH_HW 0x00000008 // 039 or later +#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC) +#define CAN_LINE_AS_REAR 0x00000010 // 033 or later +#define CAN_LINE_AS_BASS 0x00000020 // 039 or later +#define CAN_MIC_AS_BASS 0x00000040 // 039 or later /* flags used for status */ -#define DO_AC3_HW 0x00000001 -#define DO_AC3_SW 0x00000002 -#define DO_AC3 (DO_AC3_HW | DO_AC3_SW) -#define DO_DUAL_DAC 0x00000004 -#define DO_MULTI_CH_HW 0x00000008 -#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC) -#define DO_LINE_AS_REAR 0x00000010 /* 033 or later */ -#define DO_LINE_AS_BASS 0x00000020 /* 039 or later */ -#define DO_MIC_AS_BASS 0x00000040 /* 039 or later */ -#define DO_SPDIF_OUT 0x00000100 -#define DO_SPDIF_IN 0x00000200 -#define DO_SPDIF_LOOP 0x00000400 +#define DO_AC3_HW 0x00000001 +#define DO_AC3_SW 0x00000002 +#define DO_AC3 (DO_AC3_HW | DO_AC3_SW) +#define DO_DUAL_DAC 0x00000004 +#define DO_MULTI_CH_HW 0x00000008 +#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC) +#define DO_LINE_AS_REAR 0x00000010 // 033 or later +#define DO_LINE_AS_BASS 0x00000020 // 039 or later +#define DO_MIC_AS_BASS 0x00000040 // 039 or later +#define DO_SPDIF_OUT 0x00000100 +#define DO_SPDIF_IN 0x00000200 +#define DO_SPDIF_LOOP 0x00000400 -static struct cm_state *devs; -static unsigned long wavetable_mem; +/* --------------------------------------------------------------------- */ + +static struct cm_state *devs = NULL; +static struct cm_state *devaudio = NULL; +static unsigned long wavetable_mem = 0; /* --------------------------------------------------------------------- */ -static inline unsigned ld2(unsigned int x) +extern __inline__ unsigned ld2(unsigned int x) { - unsigned exp=16,l=5,r=0; - static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000}; - - /* num: 2, 4, 16, 256, 65536 */ - /* exp: 1, 2, 4, 8, 16 */ + unsigned r = 0; - while(l--) { - if( x >= num[l] ) { - if(num[l]>2) x >>= exp; - r+=exp; - } - exp>>=1; + if (x >= 0x10000) { + x >>= 16; + r += 16; + } + if (x >= 0x100) { + x >>= 8; + r += 8; + } + if (x >= 0x10) { + x >>= 4; + r += 4; + } + if (x >= 4) { + x >>= 2; + r += 2; } - + if (x >= 2) + r++; return r; } +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#ifdef hweight32 +#undef hweight32 +#endif + +extern __inline__ unsigned int hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + /* --------------------------------------------------------------------- */ +/* + * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver. + */ + +#undef DMABYTEIO + static void maskb(unsigned int addr, unsigned int mask, unsigned int value) { outb((inb(addr) & mask) | value, addr); @@ -389,77 +480,69 @@ static void set_countdac(struct cm_state set_countadc(s, count); } -static inline unsigned get_dmadac(struct cm_state *s) +extern __inline__ unsigned get_dmadac(struct cm_state *s) { unsigned int curr_addr; +#if 1 curr_addr = inw(s->iobase + CODEC_CMI_CH1_FRAME2) + 1; curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; curr_addr = s->dma_dac.dmasize - curr_addr; - +#else + curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1); + curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]-1); + curr_addr -= s->dma_dac.rawphys; +#endif return curr_addr; } -static inline unsigned get_dmaadc(struct cm_state *s) +extern __inline__ unsigned get_dmaadc(struct cm_state *s) { unsigned int curr_addr; +#if 1 curr_addr = inw(s->iobase + CODEC_CMI_CH0_FRAME2) + 1; curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]; curr_addr = s->dma_adc.dmasize - curr_addr; - +#else + curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1); + curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]-1); + curr_addr -= s->dma_adc.rawphys; +#endif return curr_addr; } static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data) { outb(idx, s->iobase + CODEC_SB16_ADDR); - udelay(10); outb(data, s->iobase + CODEC_SB16_DATA); - udelay(10); } static unsigned char rdmixer(struct cm_state *s, unsigned char idx) { unsigned char v; - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); + outb(idx, s->iobase + CODEC_SB16_ADDR); - udelay(10); v = inb(s->iobase + CODEC_SB16_DATA); - udelay(10); - spin_unlock_irqrestore(&s->lock, flags); return v; } -static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data) -{ - if (mask) - { - s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT); - udelay(10); - } - s->fmt = (s->fmt & mask) | data; - outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT); - udelay(10); -} - static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data) { unsigned long flags; spin_lock_irqsave(&s->lock, flags); - set_fmt_unlocked(s,mask,data); + if (mask) + s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT); + s->fmt = (s->fmt & mask) | data; + outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT); spin_unlock_irqrestore(&s->lock, flags); } static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data) { outb(idx, s->iobase + CODEC_SB16_ADDR); - udelay(10); outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA); - udelay(10); } static struct { @@ -479,8 +562,11 @@ static struct { { 48000, (44100 + 48000) / 2, 48000, 7 } }; -static void set_spdifout_unlocked(struct cm_state *s, unsigned rate) +static void set_spdifout(struct cm_state *s, unsigned rate) { + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); if (rate == 48000 || rate == 44100) { // SPDIFI48K SPDF_ACc97 maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~0x01008000, rate == 48000 ? 0x01008000 : 0); @@ -499,14 +585,6 @@ static void set_spdifout_unlocked(struct maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0); s->status &= ~DO_SPDIF_OUT; } -} - -static void set_spdifout(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - set_spdifout_unlocked(s,rate); spin_unlock_irqrestore(&s->lock, flags); } @@ -526,8 +604,12 @@ static unsigned parity(unsigned data) return parity & 1; } -static void set_ac3_unlocked(struct cm_state *s, unsigned rate) +static void set_ac3(struct cm_state *s, unsigned rate) { + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + set_spdifout(s, rate); /* enable AC3 */ if (rate == 48000 || rate == 44100) { // mute DAC @@ -567,30 +649,18 @@ static void set_ac3_unlocked(struct cm_s s->status &= ~DO_AC3; } s->spdif_counter = 0; - -} - -static void set_ac3(struct cm_state *s, unsigned rate) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - set_spdifout_unlocked(s, rate); - set_ac3_unlocked(s,rate); spin_unlock_irqrestore(&s->lock, flags); } -static int trans_ac3(struct cm_state *s, void *dest, const char *source, int size) +static void trans_ac3(struct cm_state *s, void *dest, const char *source, int size) { int i = size / 2; - int err; unsigned long data; unsigned long *dst = (unsigned long *) dest; unsigned short *src = (unsigned short *)source; do { - if ((err = __get_user(data, src++))) - return err; + data = (unsigned long) *src++; data <<= 12; // ok for 16-bit data if (s->spdif_counter == 2 || s->spdif_counter == 3) data |= 0x40000000; // indicate AC-3 raw data @@ -607,30 +677,6 @@ static int trans_ac3(struct cm_state *s, if (s->spdif_counter == 384) s->spdif_counter = 0; } while (--i); - - return 0; -} - -static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate) -{ - unsigned char freq = 4; - int i; - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) { - if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) { - rate = rate_lookup[i].rate; - freq = rate_lookup[i].freq; - break; - } - } - s->rateadc = rate; - freq <<= 2; - - maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq); } static void set_adc_rate(struct cm_state *s, unsigned rate) @@ -652,7 +698,6 @@ static void set_adc_rate(struct cm_state } s->rateadc = rate; freq <<= 2; - spin_lock_irqsave(&s->lock, flags); maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq); spin_unlock_irqrestore(&s->lock, flags); @@ -677,17 +722,13 @@ static void set_dac_rate(struct cm_state } s->ratedac = rate; freq <<= 5; - spin_lock_irqsave(&s->lock, flags); maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0xe0, freq); - - + spin_unlock_irqrestore(&s->lock, flags); if (s->curr_channels <= 2) - set_spdifout_unlocked(s, rate); + set_spdifout(s, rate); if (s->status & DO_DUAL_DAC) - set_adc_rate_unlocked(s, rate); - - spin_unlock_irqrestore(&s->lock, flags); + set_dac1_rate(s, rate); } /* --------------------------------------------------------------------- */ @@ -695,7 +736,6 @@ static inline void reset_adc(struct cm_s { /* reset bus master */ outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2); - udelay(10); outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } @@ -720,7 +760,7 @@ static inline void pause_dac(struct cm_s pause_adc(s); } -static inline void disable_adc(struct cm_state *s) +extern inline void disable_adc(struct cm_state *s) { /* disable channel */ s->enable &= ~CM_ENABLE_CH0; @@ -728,7 +768,7 @@ static inline void disable_adc(struct cm reset_adc(s); } -static inline void disable_dac(struct cm_state *s) +extern inline void disable_dac(struct cm_state *s) { /* disable channel */ s->enable &= ~CM_ENABLE_CH1; @@ -738,7 +778,7 @@ static inline void disable_dac(struct cm disable_adc(s); } -static inline void enable_adc(struct cm_state *s) +extern inline void enable_adc(struct cm_state *s) { if (!(s->enable & CM_ENABLE_CH0)) { /* enable channel */ @@ -748,7 +788,7 @@ static inline void enable_adc(struct cm_ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~4, 0); } -static inline void enable_dac_unlocked(struct cm_state *s) +extern inline void enable_dac(struct cm_state *s) { if (!(s->enable & CM_ENABLE_CH1)) { /* enable channel */ @@ -756,105 +796,78 @@ static inline void enable_dac_unlocked(s outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~8, 0); - if (s->status & DO_DUAL_DAC) enable_adc(s); } -static inline void enable_dac(struct cm_state *s) +extern inline void stop_adc(struct cm_state *s) { unsigned long flags; spin_lock_irqsave(&s->lock, flags); - enable_dac_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_adc_unlocked(struct cm_state *s) -{ if (s->enable & CM_ENABLE_CH0) { /* disable interrupt */ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~1, 0); disable_adc(s); } + spin_unlock_irqrestore(&s->lock, flags); } -static inline void stop_adc(struct cm_state *s) +extern inline void stop_dac(struct cm_state *s) { unsigned long flags; spin_lock_irqsave(&s->lock, flags); - stop_adc_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); - -} - -static inline void stop_dac_unlocked(struct cm_state *s) -{ if (s->enable & CM_ENABLE_CH1) { /* disable interrupt */ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~2, 0); disable_dac(s); } + spin_unlock_irqrestore(&s->lock, flags); if (s->status & DO_DUAL_DAC) - stop_adc_unlocked(s); + stop_dac1(s); } -static inline void stop_dac(struct cm_state *s) +static void start_adc(struct cm_state *s) { unsigned long flags; spin_lock_irqsave(&s->lock, flags); - stop_dac_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc_unlocked(struct cm_state *s) -{ if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) && s->dma_adc.ready) { /* enable interrupt */ maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1); enable_adc(s); } -} + spin_unlock_irqrestore(&s->lock, flags); +} -static void start_adc(struct cm_state *s) +static void start_dac1(struct cm_state *s) { unsigned long flags; spin_lock_irqsave(&s->lock, flags); - start_adc_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac1_unlocked(struct cm_state *s) -{ if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) { /* enable interrupt */ // maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1); - enable_dac_unlocked(s); - } -} - -static void start_dac_unlocked(struct cm_state *s) -{ - if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { - /* enable interrupt */ - maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 2); - enable_dac_unlocked(s); + enable_dac(s); } - if (s->status & DO_DUAL_DAC) - start_dac1_unlocked(s); -} + spin_unlock_irqrestore(&s->lock, flags); +} static void start_dac(struct cm_state *s) { unsigned long flags; spin_lock_irqsave(&s->lock, flags); - start_dac_unlocked(s); + if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { + /* enable interrupt */ + maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 2); + enable_dac(s); + } spin_unlock_irqrestore(&s->lock, flags); + if (s->status & DO_DUAL_DAC) + start_dac1(s); } static int prog_dmabuf(struct cm_state *s, unsigned rec); @@ -862,11 +875,11 @@ static int prog_dmabuf(struct cm_state * static int set_dac_channels(struct cm_state *s, int channels) { unsigned long flags; - spin_lock_irqsave(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); if ((channels > 2) && (channels <= s->max_channels) && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) { - set_spdifout_unlocked(s, 0); + set_spdifout(s, 0); if (s->capability & CAN_MULTI_CH_HW) { // NXCHG maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, 0x80); @@ -886,12 +899,8 @@ static int set_dac_channels(struct cm_st maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0xC0); s->status |= DO_DUAL_DAC; // prepare secondary buffer - - spin_unlock_irqrestore(&s->lock, flags); ret = prog_dmabuf(s, 1); if (ret) return ret; - spin_lock_irqsave(&s->lock, flags); - // copy the hw state fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT); @@ -900,12 +909,10 @@ static int set_dac_channels(struct cm_st fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT; fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT; fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT; - - set_fmt_unlocked(s, fmtm, fmts); - set_adc_rate_unlocked(s, s->ratedac); - + set_fmt(s, fmtm, fmts); + set_dac1_rate(s, s->ratedac); } - + // N4SPK3D, disable 4 speaker mode (analog duplicate) if (s->speakers > 2) maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0x04, 0); s->curr_channels = channels; @@ -923,7 +930,6 @@ static int set_dac_channels(struct cm_st s->status &= ~DO_MULTI_CH; s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1; } - spin_unlock_irqrestore(&s->lock, flags); return s->curr_channels; } @@ -935,19 +941,30 @@ static int set_dac_channels(struct cm_st static void dealloc_dmabuf(struct dmabuf *db) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) struct page *pstart, *pend; +#else + unsigned long map, mapend; +#endif if (db->rawbuf) { /* undo marking the pages as reserved */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++) - ClearPageReserved(pstart); + mem_map_unreserve(pstart); +#else + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &mem_map[map].flags); +#endif free_pages((unsigned long)db->rawbuf, db->buforder); } db->rawbuf = NULL; db->mapped = db->ready = 0; } + /* Ch1 is used for playback, Ch0 is used for recording */ static int prog_dmabuf(struct cm_state *s, unsigned rec) @@ -957,10 +974,15 @@ static int prog_dmabuf(struct cm_state * int order; unsigned bytepersec; unsigned bufs; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) struct page *pstart, *pend; +#else + unsigned long map, mapend; +#endif unsigned char fmt; unsigned long flags; + spin_lock_irqsave(&s->lock, flags); fmt = s->fmt; if (rec) { stop_adc(s); @@ -969,7 +991,7 @@ static int prog_dmabuf(struct cm_state * stop_dac(s); fmt >>= CM_CFMT_DACSHIFT; } - + spin_unlock_irqrestore(&s->lock, flags); fmt &= CM_CFMT_MASK; db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { @@ -982,15 +1004,21 @@ static int prog_dmabuf(struct cm_state * db->buforder = order; db->rawphys = virt_to_bus(db->rawbuf); if ((db->rawphys ^ (db->rawphys + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) - printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", + printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", (long) db->rawphys, PAGE_SIZE << db->buforder); if ((db->rawphys + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) - printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", + printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", (long) db->rawphys, PAGE_SIZE << db->buforder); /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++) - SetPageReserved(pstart); + mem_map_reserve(pstart); +#else + mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = MAP_NR(db->rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &mem_map[map].flags); +#endif } bytepersec = rate << sample_shift[fmt]; bufs = PAGE_SIZE << db->buforder; @@ -1013,6 +1041,13 @@ static int prog_dmabuf(struct cm_state * if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) db->numfrag = db->ossmaxfrags; /* to make fragsize >= 4096 */ + if (s->modem) { + while (db->fragsize < 4096 && db->numfrag >= 4) { + db->fragsize *= 2; + db->fragshift++; + db->numfrag /= 2; + } + } db->fragsamples = db->fragsize >> sample_shift[fmt]; db->dmasize = db->numfrag << db->fragshift; db->dmasamples = db->dmasize >> sample_shift[fmt]; @@ -1035,7 +1070,7 @@ static int prog_dmabuf(struct cm_state * return 0; } -static inline void clear_advance(struct cm_state *s) +extern __inline__ void clear_advance(struct cm_state *s) { unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80; unsigned char *buf = s->dma_dac.rawbuf; @@ -1159,7 +1194,7 @@ static void cm_handle_midi(struct cm_sta } #endif -static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct cm_state *s = (struct cm_state *)dev_id; unsigned int intsrc, intstat; @@ -1168,7 +1203,7 @@ static irqreturn_t cm_interrupt(int irq, /* fastpath out, to ease interrupt sharing */ intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS); if (!(intsrc & 0x80000000)) - return IRQ_NONE; + return; spin_lock(&s->lock); intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* acknowledge interrupt */ @@ -1183,7 +1218,6 @@ static irqreturn_t cm_interrupt(int irq, cm_handle_midi(s); #endif spin_unlock(&s->lock); - return IRQ_HANDLED; } #ifdef CONFIG_SOUND_CMPCI_MIDI @@ -1202,7 +1236,7 @@ static void cm_midi_timer(unsigned long /* --------------------------------------------------------------------- */ -static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n"; +static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n"; #ifdef CONFIG_SOUND_CMPCI /* support multiple chips */ #define VALIDATE_STATE(s) @@ -1236,10 +1270,62 @@ static const struct { [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 }, [SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 }, [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 }, - [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 }, - [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX, DSP_MIX_SPKRVOLIDX, MT_5MUTEMONO, 0x01, 0x01 } + [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 } }; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + +static int return_mixval(struct cm_state *s, unsigned i, int *arg) +{ + unsigned long flags; + unsigned char l, r, rl, rr; + + spin_lock_irqsave(&s->lock, flags); + l = rdmixer(s, mixtable[i].left); + r = rdmixer(s, mixtable[i].right); + spin_unlock_irqrestore(&s->lock, flags); + switch (mixtable[i].type) { + case MT_4: + r &= 0xf; + l &= 0xf; + rl = 10 + 6 * (l & 15); + rr = 10 + 6 * (r & 15); + break; + + case MT_4MUTEMONO: + rl = 55 - 3 * (l & 15); + if (r & 0x10) + rl += 45; + rr = rl; + r = l; + break; + + case MT_5MUTEMONO: + r = l; + rl = 100 - 3 * ((l >> 3) & 31); + rr = rl; + break; + + case MT_5MUTE: + default: + rl = 100 - 3 * ((l >> 3) & 31); + rr = 100 - 3 * ((r >> 3) & 31); + break; + + case MT_6MUTE: + rl = 100 - 3 * (l & 63) / 2; + rr = 100 - 3 * (r & 63) / 2; + break; + } + if (l & 0x80) + rl = 0; + if (r & 0x80) + rr = 0; + return put_user((rr << 8) | rl, arg); +} + +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_CD] = 1, @@ -1247,15 +1333,19 @@ static const unsigned char volidx[SOUND_ [SOUND_MIXER_MIC] = 3, [SOUND_MIXER_SYNTH] = 4, [SOUND_MIXER_VOLUME] = 5, - [SOUND_MIXER_PCM] = 6, - [SOUND_MIXER_SPEAKER]= 7 + [SOUND_MIXER_PCM] = 6 }; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + static unsigned mixer_recmask(struct cm_state *s) { + unsigned long flags; int i, j, k; + spin_lock_irqsave(&s->lock, flags); j = rdmixer(s, DSP_MIX_ADCMIXIDX_L); + spin_unlock_irqrestore(&s->lock, flags); j &= 0x7f; for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (j & mixtable[i].rec) @@ -1272,9 +1362,8 @@ static int mixer_ioctl(struct cm_state * VALIDATE_STATE(s); if (cmd == SOUND_MIXER_INFO) { mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "cmpci", sizeof(info.id)); - strlcpy(info.name, "C-Media PCI", sizeof(info.name)); + strncpy(info.id, "cmpci", sizeof(info.id)); + strncpy(info.name, "C-Media PCI", sizeof(info.name)); info.modify_counter = s->mix.modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -1282,9 +1371,8 @@ static int mixer_ioctl(struct cm_state * } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; - memset(&info, 0, sizeof(info)); - strlcpy(info.id, "cmpci", sizeof(info.id)); - strlcpy(info.name, "C-Media cmpci", sizeof(info.name)); + strncpy(info.id, "cmpci", sizeof(info.id)); + strncpy(info.name, "C-Media cmpci", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; @@ -1332,9 +1420,13 @@ static int mixer_ioctl(struct cm_state * i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ if (!volidx[i]) return -EINVAL; return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) @@ -1342,9 +1434,13 @@ static int mixer_ioctl(struct cm_state * s->mix.modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; - i = generic_hweight32(val); +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif + i = hweight32(val); for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) continue; @@ -1361,8 +1457,12 @@ static int mixer_ioctl(struct cm_state * return 0; case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (!(val & (1 << i))) continue; @@ -1381,8 +1481,12 @@ static int mixer_ioctl(struct cm_state * i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif l = val & 0xff; r = (val >> 8) & 0xff; if (l > 100) @@ -1436,19 +1540,29 @@ static int mixer_ioctl(struct cm_state * break; } spin_unlock_irqrestore(&s->lock, flags); - +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ if (!volidx[i]) return -EINVAL; s->mix.vol[volidx[i]-1] = val; return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } /* --------------------------------------------------------------------- */ +static loff_t cm_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* --------------------------------------------------------------------- */ + static int cm_open_mixdev(struct inode *inode, struct file *file) { - int minor = iminor(inode); + int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; while (s && s->dev_mixer != minor) @@ -1457,6 +1571,9 @@ static int cm_open_mixdev(struct inode * return -ENODEV; VALIDATE_STATE(s); file->private_data = s; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_INC_USE_COUNT; +#endif return 0; } @@ -1467,6 +1584,9 @@ static int cm_release_mixdev(struct inod s = file->private_data; VALIDATE_STATE(s); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_DEC_USE_COUNT; +#endif return 0; } @@ -1476,25 +1596,140 @@ static int cm_ioctl_mixdev(struct inode } static /*const*/ struct file_operations cm_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = cm_ioctl_mixdev, - .open = cm_open_mixdev, - .release = cm_release_mixdev, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + owner: THIS_MODULE, +#endif + llseek: cm_llseek, + ioctl: cm_ioctl_mixdev, + open: cm_open_mixdev, + release: cm_release_mixdev, }; +int IntrOpen(void) +{ + struct cm_state *s = devs; + unsigned char fmtm = ~0, fmts = 0; + + /* Locate the /dev/dsp file descriptor */ + while (s && ((s->dev_audio ^ 3) & ~0xf)) + s = s->next; + + devaudio = s; + down(&s->open_sem); + if (s->open_mode & FMODE_WRITE) { + up(&s->open_sem); + devaudio = NULL; + return -EBUSY; + } + + if (!s->dma_dac.ready) { + set_dac_rate(s, 8000); + fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT); + set_fmt(s, fmtm, fmts); + s->modem = 1; + } + + s->open_mode |= FMODE_WRITE; + up(&s->open_sem); + MOD_INC_USE_COUNT; + return 0; +} +EXPORT_SYMBOL(IntrOpen); + +int IntrClose(void) +{ + struct cm_state *s = devaudio; + + if (!s) + return -ENODEV; + down(&s->open_sem); + stop_dac(s); +#ifndef FIXEDDMA + dealloc_dmabuf(&s->dma_dac); +#endif + + s->open_mode &= ~FMODE_WRITE; + s->modem = 0; + up(&s->open_sem); + wake_up(&s->open_wait); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_DEC_USE_COUNT; +#endif + devaudio = NULL; + return 0; +} +EXPORT_SYMBOL(IntrClose); + +int IntrWrite(const char *buffer, int count) +{ + struct cm_state *s = devaudio; + ssize_t ret = 0; + unsigned long flags; + unsigned swptr; + int cnt; + + if (!s) + return -ENODEV; + VALIDATE_STATE(s); + if (s->dma_dac.mapped) + return -ENXIO; + + if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0))) + return ret; + + s->dma_dac.ossfragshift = 8; + s->dma_dac.ossmaxfrags = 16; + s->dma_dac.subdivision = 0; + + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + cnt = s->dma_dac.dmasize-swptr; + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_dac(s); + return ret; + } + if (__copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_dac.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } + return ret; +} +EXPORT_SYMBOL(IntrWrite); /* --------------------------------------------------------------------- */ static int drain_dac(struct cm_state *s, int nonblock) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue wait = { current, NULL }; +#endif unsigned long flags; int count, tmo; if (s->dma_dac.mapped || !s->dma_dac.ready) return 0; - set_current_state(TASK_INTERRUPTIBLE); + current->state = TASK_INTERRUPTIBLE; add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -1506,16 +1741,16 @@ static int drain_dac(struct cm_state *s, break; if (nonblock) { remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); + current->state = TASK_RUNNING; return -EBUSY; } tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "cmpci: dma timed out??\n"); + printk(KERN_DEBUG "cm: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); - set_current_state(TASK_RUNNING); + current->state = TASK_RUNNING; if (signal_pending(current)) return -ERESTARTSYS; return 0; @@ -1541,7 +1776,11 @@ static ssize_t cm_read(struct file *file if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; - +#if 0 + spin_lock_irqsave(&s->lock, flags); + cm_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; @@ -1556,11 +1795,11 @@ static ssize_t cm_read(struct file *file if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { - printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + printk(KERN_DEBUG "cm: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); spin_lock_irqsave(&s->lock, flags); - stop_adc_unlocked(s); set_dmaadc(s, s->dma_adc.rawphys, s->dma_adc.dmasamples); /* program sample counts */ set_countadc(s, s->dma_adc.fragsamples); @@ -1577,11 +1816,11 @@ static ssize_t cm_read(struct file *file spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; s->dma_adc.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); count -= cnt; buffer += cnt; ret += cnt; - start_adc_unlocked(s); - spin_unlock_irqrestore(&s->lock, flags); + start_adc(s); } return ret; } @@ -1612,7 +1851,11 @@ static ssize_t cm_write(struct file *fil return -EFAULT; } ret = 0; - +#if 0 + spin_lock_irqsave(&s->lock, flags); + cm_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); +#endif while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac.count < 0) { @@ -1643,11 +1886,11 @@ static ssize_t cm_write(struct file *fil if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { - printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + printk(KERN_DEBUG "cm: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); spin_lock_irqsave(&s->lock, flags); - stop_dac_unlocked(s); set_dmadac(s, s->dma_dac.rawphys, s->dma_dac.dmasamples); /* program sample counts */ set_countdac(s, s->dma_dac.fragsamples); @@ -1663,16 +1906,13 @@ static ssize_t cm_write(struct file *fil continue; } if (s->status & DO_AC3_SW) { - int err; - // clip exceeded data, caught by 033 and 037 if (swptr + 2 * cnt > s->dma_dac.dmasize) cnt = (s->dma_dac.dmasize - swptr) / 2; - if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) - return err; + trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt); swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; } else if (s->status & DO_DUAL_DAC) { - int i, err; + int i; unsigned long *src, *dst0, *dst1; src = (unsigned long *) buffer; @@ -1680,10 +1920,8 @@ static ssize_t cm_write(struct file *fil dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time for (i = 0; i <= cnt / 4; i++) { - if ((err = __get_user(*dst0++, src++))) - return err; - if ((err = __get_user(*dst1++, src++))) - return err; + *dst0++ = *src++; + *dst1++ = *src++; } swptr = (swptr + cnt) % s->dma_dac.dmasize; } else { @@ -1749,7 +1987,9 @@ static int cm_mmap(struct file *file, st unsigned long size; VALIDATE_STATE(s); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) lock_kernel(); +#endif if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(s, 0)) != 0) goto out; @@ -1761,18 +2001,24 @@ static int cm_mmap(struct file *file, st } else goto out; ret = -EINVAL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) if (vma->vm_pgoff != 0) +#else + if (vma->vm_offset != 0) +#endif goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) goto out; ret = -EINVAL; - if (remap_page_range(vma, vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) goto out; db->mapped = 1; ret = 0; out: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) unlock_kernel(); +#endif return ret; } @@ -1806,28 +2052,30 @@ static int cm_ioctl(struct inode *inode, case SNDCTL_DSP_RESET: if (file->f_mode & FMODE_WRITE) { stop_dac(s); - synchronize_irq(s->irq); + synchronize_irq(); s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0; if (s->status & DO_DUAL_DAC) s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } if (file->f_mode & FMODE_READ) { stop_adc(s); - synchronize_irq(s->irq); + synchronize_irq(); s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; } return 0; case SNDCTL_DSP_SPEED: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif if (val >= 0) { if (file->f_mode & FMODE_READ) { - spin_lock_irqsave(&s->lock, flags); - stop_adc_unlocked(s); + stop_adc(s); s->dma_adc.ready = 0; - set_adc_rate_unlocked(s, val); - spin_unlock_irqrestore(&s->lock, flags); + set_adc_rate(s, val); } if (file->f_mode & FMODE_WRITE) { stop_dac(s); @@ -1840,8 +2088,12 @@ static int cm_ioctl(struct inode *inode, return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); case SNDCTL_DSP_STEREO: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif fmtd = 0; fmtm = ~0; if (file->f_mode & FMODE_READ) { @@ -1871,8 +2123,12 @@ static int cm_ioctl(struct inode *inode, return 0; case SNDCTL_DSP_CHANNELS: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif if (val != 0) { fmtd = 0; fmtm = ~0; @@ -1913,8 +2169,12 @@ static int cm_ioctl(struct inode *inode, return put_user(AFMT_S16_LE|AFMT_U8|AFMT_AC3, (int *)arg); case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif if (val != AFMT_QUERY) { fmtd = 0; fmtm = ~0; @@ -1971,8 +2231,12 @@ static int cm_ioctl(struct inode *inode, return put_user(val, (int *)arg); case SNDCTL_DSP_SETTRIGGER: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif if (file->f_mode & FMODE_READ) { if (val & PCM_ENABLE_INPUT) { if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1))) @@ -2047,9 +2311,7 @@ static int cm_ioctl(struct inode *inode, if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETOPTR: if (!(file->f_mode & FMODE_WRITE)) @@ -2066,9 +2328,7 @@ static int cm_ioctl(struct inode *inode, s->dma_adc.count &= s->dma_adc.fragsize-1; } spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); case SNDCTL_DSP_GETBLKSIZE: if (file->f_mode & FMODE_WRITE) { @@ -2086,8 +2346,12 @@ static int cm_ioctl(struct inode *inode, return put_user(s->dma_adc.fragsize, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = val & 0xffff; s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; @@ -2118,8 +2382,12 @@ static int cm_ioctl(struct inode *inode, if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) return -EINVAL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (get_user(val, (int *)arg)) return -EFAULT; +#else + get_user_ret(val, (int *)arg, -EFAULT); +#endif if (val != 1 && val != 2 && val != 4) return -EINVAL; if (file->f_mode & FMODE_READ) @@ -2209,7 +2477,7 @@ static int cm_ioctl(struct inode *inode, static int cm_open(struct inode *inode, struct file *file) { - int minor = iminor(inode); + int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; unsigned char fmtm = ~0, fmts = 0; @@ -2255,6 +2523,9 @@ static int cm_open(struct inode *inode, set_fmt(s, fmtm, fmts); s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + MOD_INC_USE_COUNT; +#endif return 0; } @@ -2263,17 +2534,19 @@ static int cm_release(struct inode *inod struct cm_state *s = (struct cm_state *)file->private_data; VALIDATE_STATE(s); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) lock_kernel(); +#endif if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); if (file->f_mode & FMODE_WRITE) { stop_dac(s); - +#ifndef FIXEDDMA dealloc_dmabuf(&s->dma_dac); if (s->status & DO_DUAL_DAC) dealloc_dmabuf(&s->dma_adc); - +#endif if (s->status & DO_MULTI_CH) set_dac_channels(s, 0); if (s->status & DO_AC3) @@ -2283,25 +2556,33 @@ static int cm_release(struct inode *inod } if (file->f_mode & FMODE_READ) { stop_adc(s); +#ifndef FIXEDDMA dealloc_dmabuf(&s->dma_adc); +#endif } - s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); + s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) unlock_kernel(); +#else + MOD_DEC_USE_COUNT; +#endif return 0; } static /*const*/ struct file_operations cm_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cm_read, - .write = cm_write, - .poll = cm_poll, - .ioctl = cm_ioctl, - .mmap = cm_mmap, - .open = cm_open, - .release = cm_release, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + owner: THIS_MODULE, +#endif + llseek: cm_llseek, + read: cm_read, + write: cm_write, + poll: cm_poll, + ioctl: cm_ioctl, + mmap: cm_mmap, + open: cm_open, + release: cm_release, }; #ifdef CONFIG_SOUND_CMPCI_MIDI @@ -2310,7 +2591,9 @@ static /*const*/ struct file_operations static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct cm_state *s = (struct cm_state *)file->private_data; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) DECLARE_WAITQUEUE(wait, current); +#endif ssize_t ret; unsigned long flags; unsigned ptr; @@ -2322,7 +2605,9 @@ static ssize_t cm_midi_read(struct file if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) add_wait_queue(&s->midi.iwait, &wait); +#endif while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.ird; @@ -2334,6 +2619,7 @@ static ssize_t cm_midi_read(struct file cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) { if (!ret) ret = -EAGAIN; @@ -2347,14 +2633,24 @@ static ssize_t cm_midi_read(struct file ret = -ERESTARTSYS; break; } +#else + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->midi.iwait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; +#endif continue; } if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) { if (!ret) ret = -EFAULT; break; } +#else + return ret ? ret : -EFAULT; +#endif ptr = (ptr + cnt) % MIDIINBUF; spin_lock_irqsave(&s->lock, flags); s->midi.ird = ptr; @@ -2363,17 +2659,23 @@ static ssize_t cm_midi_read(struct file count -= cnt; buffer += cnt; ret += cnt; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) break; +#endif } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) __set_current_state(TASK_RUNNING); remove_wait_queue(&s->midi.iwait, &wait); +#endif return ret; } static ssize_t cm_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct cm_state *s = (struct cm_state *)file->private_data; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) DECLARE_WAITQUEUE(wait, current); +#endif ssize_t ret; unsigned long flags; unsigned ptr; @@ -2384,10 +2686,14 @@ static ssize_t cm_midi_write(struct file return -ESPIPE; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) if (count == 0) return 0; +#endif ret = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) add_wait_queue(&s->midi.owait, &wait); +#endif while (count > 0) { spin_lock_irqsave(&s->lock, flags); ptr = s->midi.owr; @@ -2401,6 +2707,7 @@ static ssize_t cm_midi_write(struct file cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) { if (!ret) ret = -EAGAIN; @@ -2413,14 +2720,24 @@ static ssize_t cm_midi_write(struct file ret = -ERESTARTSYS; break; } +#else + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->midi.owait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; +#endif continue; } if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) { if (!ret) ret = -EFAULT; break; } +#else + return ret ? ret : -EFAULT; +#endif ptr = (ptr + cnt) % MIDIOUTBUF; spin_lock_irqsave(&s->lock, flags); s->midi.owr = ptr; @@ -2433,8 +2750,10 @@ static ssize_t cm_midi_write(struct file cm_handle_midi(s); spin_unlock_irqrestore(&s->lock, flags); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) __set_current_state(TASK_RUNNING); remove_wait_queue(&s->midi.owait, &wait); +#endif return ret; } @@ -2464,7 +2783,7 @@ static unsigned int cm_midi_poll(struct static int cm_midi_open(struct inode *inode, struct file *file) { - int minor = iminor(inode); + int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; unsigned long flags; @@ -2515,21 +2834,32 @@ static int cm_midi_open(struct inode *in spin_unlock_irqrestore(&s->lock, flags); s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); up(&s->open_sem); + MOD_INC_USE_COUNT; return 0; } static int cm_midi_release(struct inode *inode, struct file *file) { struct cm_state *s = (struct cm_state *)file->private_data; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue wait = { current, NULL }; +#endif unsigned long flags; unsigned count, tmo; VALIDATE_STATE(s); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) lock_kernel(); +#endif if (file->f_mode & FMODE_WRITE) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) __set_current_state(TASK_INTERRUPTIBLE); +#else + current->state = TASK_INTERRUPTIBLE; +#endif add_wait_queue(&s->midi.owait, &wait); for (;;) { spin_lock_irqsave(&s->lock, flags); @@ -2541,19 +2871,26 @@ static int cm_midi_release(struct inode break; if (file->f_flags & O_NONBLOCK) { remove_wait_queue(&s->midi.owait, &wait); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) set_current_state(TASK_RUNNING); - unlock_kernel(); +#else + current->state = TASK_RUNNING; +#endif return -EBUSY; } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "cmpci: midi timed out??\n"); + printk(KERN_DEBUG "cm: midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) set_current_state(TASK_RUNNING); +#else + current->state = TASK_RUNNING; +#endif } down(&s->open_sem); - s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE)); + s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); spin_lock_irqsave(&s->lock, flags); if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { del_timer(&s->midi.timer); @@ -2566,18 +2903,24 @@ static int cm_midi_release(struct inode spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) unlock_kernel(); +#else + MOD_DEC_USE_COUNT; +#endif return 0; } static /*const*/ struct file_operations cm_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = cm_midi_read, - .write = cm_midi_write, - .poll = cm_midi_poll, - .open = cm_midi_open, - .release = cm_midi_release, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + owner: THIS_MODULE, +#endif + llseek: cm_llseek, + read: cm_midi_read, + write: cm_midi_write, + poll: cm_midi_poll, + open: cm_midi_open, + release: cm_midi_release, }; #endif @@ -2675,13 +3018,15 @@ static int cm_dmfm_ioctl(struct inode *i outb(5, s->iosynth+2); outb(arg & 1, s->iosynth+3); return 0; + + default: + return -EINVAL; } - return -EINVAL; } static int cm_dmfm_open(struct inode *inode, struct file *file) { - int minor = iminor(inode); + int minor = MINOR(inode->i_rdev); struct cm_state *s = devs; while (s && s->dev_dmfm != minor) @@ -2712,6 +3057,7 @@ static int cm_dmfm_open(struct inode *in outb(1, s->iosynth+3); /* enable OPL3 */ s->open_mode |= FMODE_DMFM; up(&s->open_sem); + MOD_INC_USE_COUNT; return 0; } @@ -2721,7 +3067,9 @@ static int cm_dmfm_release(struct inode unsigned int regb; VALIDATE_STATE(s); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) lock_kernel(); +#endif down(&s->open_sem); s->open_mode &= ~FMODE_DMFM; for (regb = 0xb0; regb < 0xb9; regb++) { @@ -2732,20 +3080,37 @@ static int cm_dmfm_release(struct inode } up(&s->open_sem); wake_up(&s->open_wait); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) unlock_kernel(); +#else + MOD_DEC_USE_COUNT; +#endif return 0; } static /*const*/ struct file_operations cm_dmfm_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = cm_dmfm_ioctl, - .open = cm_dmfm_open, - .release = cm_dmfm_release, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + owner: THIS_MODULE, +#endif + llseek: cm_llseek, + ioctl: cm_dmfm_ioctl, + open: cm_dmfm_open, + release: cm_dmfm_release, }; #endif /* CONFIG_SOUND_CMPCI_FM */ +/* --------------------------------------------------------------------- */ + +/* maximum number of devices */ +#define NR_DEVICE 5 +#if 0 +static int reverb[NR_DEVICE] = { 0, }; + +static int wavetable[NR_DEVICE] = { 0, }; +#endif + +/* --------------------------------------------------------------------- */ static struct initvol { int mixch; @@ -2808,24 +3173,24 @@ static int query_chip(struct cm_state *s } #ifdef CONFIG_SOUND_CMPCI_MIDI -static int mpuio = CONFIG_SOUND_CMPCI_MPUIO; +static int mpu_io = CONFIG_SOUND_CMPCI_MPUIO; #else -static int mpuio; +static int mpu_io = 0; #endif #ifdef CONFIG_SOUND_CMPCI_FM -static int fmio = CONFIG_SOUND_CMPCI_FMIO; +static int fm_io = CONFIG_SOUND_CMPCI_FMIO; #else -static int fmio; +static int fm_io = 0; #endif #ifdef CONFIG_SOUND_CMPCI_SPDIFINVERSE static int spdif_inverse = 1; #else -static int spdif_inverse; +static int spdif_inverse = 0; #endif #ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP static int spdif_loop = 1; #else -static int spdif_loop; +static int spdif_loop = 0; #endif #ifdef CONFIG_SOUND_CMPCI_SPEAKERS static int speakers = CONFIG_SOUND_CMPCI_SPEAKERS; @@ -2835,51 +3200,48 @@ static int speakers = 2; #ifdef CONFIG_SOUND_CMPCI_LINE_REAR static int use_line_as_rear = 1; #else -static int use_line_as_rear; +static int use_line_as_rear = 0; #endif #ifdef CONFIG_SOUND_CMPCI_LINE_BASS static int use_line_as_bass = 1; #else -static int use_line_as_bass; +static int use_line_as_bass = 0; +#endif +#ifdef CONFIG_SOUND_CMPCI_PCTEL +static int modem = 1; +#else +static int modem = 0; #endif #ifdef CONFIG_SOUND_CMPCI_JOYSTICK static int joystick = 1; #else -static int joystick; +static int joystick = 0; #endif -MODULE_PARM(mpuio, "i"); -MODULE_PARM(fmio, "i"); +MODULE_PARM(mpu_io, "i"); +MODULE_PARM(fm_io, "i"); MODULE_PARM(spdif_inverse, "i"); MODULE_PARM(spdif_loop, "i"); MODULE_PARM(speakers, "i"); MODULE_PARM(use_line_as_rear, "i"); MODULE_PARM(use_line_as_bass, "i"); +MODULE_PARM(modem, "i"); MODULE_PARM(joystick, "i"); -MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable"); -MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable"); +MODULE_PARM_DESC(mpu_io, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable"); +MODULE_PARM_DESC(fm_io, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable"); MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal"); MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly"); MODULE_PARM_DESC(speakers, "(2-6) Number of speakers you connect"); MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out"); MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center"); +MODULE_PARM_DESC(modem, "(1/0) Use HSP modem, still need PCTel modem driver"); MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver"); -static struct pci_device_id cmpci_pci_tbl[] = { - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, cmpci_pci_tbl); - void initialize_chip(struct pci_dev *pcidev) { struct cm_state *s; + mm_segment_t fs; int i, val; -#if defined(CONFIG_SOUND_CMPCI_MIDI) || defined(CONFIG_SOUND_CMPCI_FM) +#ifdef CONFIG_SOUND_CMPCI_MIDI unsigned char reg_mask = 0; #endif struct { @@ -2894,13 +3256,14 @@ void initialize_chip(struct pci_dev *pci }; char *devicename = "unknown"; { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (pci_enable_device(pcidev)) return; +#endif if (pcidev->irq == 0) return; - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (!s) { - printk(KERN_WARNING "cmpci: out of memory\n"); + if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) { + printk(KERN_WARNING "cm: out of memory\n"); return; } /* search device name */ @@ -2912,17 +3275,32 @@ void initialize_chip(struct pci_dev *pci } } memset(s, 0, sizeof(struct cm_state)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) init_waitqueue_head(&s->dma_adc.wait); init_waitqueue_head(&s->dma_dac.wait); init_waitqueue_head(&s->open_wait); init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); +#else + init_waitqueue(&s->dma_adc.wait); + init_waitqueue(&s->dma_dac.wait); + init_waitqueue(&s->open_wait); + init_waitqueue(&s->midi.iwait); + init_waitqueue(&s->midi.owait); + s->open_sem = MUTEX; +#endif spin_lock_init(&s->lock); s->magic = CM_MAGIC; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) s->iobase = pci_resource_start(pcidev, 0); - s->iosynth = fmio; - s->iomidi = mpuio; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + s->iobase = pcidev->resource[0].start; +#else + s->iobase = pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; +#endif + s->iosynth = fm_io; + s->iomidi = mpu_io; s->status = 0; /* range check */ if (speakers < 2) @@ -2934,16 +3312,27 @@ void initialize_chip(struct pci_dev *pci return; s->irq = pcidev->irq; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) { - printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1); +#else + if (check_region(s->iobase, CM_EXTENT_CODEC)) { +#endif + printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1); goto err_region5; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + request_region(s->iobase, CM_EXTENT_CODEC, "cmpci"); +#endif #ifdef CONFIG_SOUND_CMPCI_MIDI /* disable MPU-401 */ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0); if (s->iomidi) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) { - printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1); +#else + if (check_region(s->iomidi, CM_EXTENT_MIDI)) { +#endif + printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1); s->iomidi = 0; } else { /* set IO based at 0x330 */ @@ -2968,6 +3357,9 @@ void initialize_chip(struct pci_dev *pci /* enable MPU-401 */ if (s->iomidi) { maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci MPU"); +#endif } } } @@ -2976,8 +3368,12 @@ void initialize_chip(struct pci_dev *pci /* disable FM */ maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0); if (s->iosynth) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) { - printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1); +#else + if (check_region(s->iosynth, CM_EXTENT_SYNTH)) { +#endif + printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1); s->iosynth = 0; } else { /* set IO based at 0x388 */ @@ -3002,6 +3398,9 @@ void initialize_chip(struct pci_dev *pci /* enable FM */ if (s->iosynth) { maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM"); +#endif } } } @@ -3019,10 +3418,10 @@ void initialize_chip(struct pci_dev *pci /* request irq */ if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) { - printk(KERN_ERR "cmpci: irq %u in use\n", s->irq); + printk(KERN_ERR "cm: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n", + printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n", devicename, s->iobase, s->irq); /* register devices */ if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) @@ -3039,6 +3438,8 @@ void initialize_chip(struct pci_dev *pci #endif pci_set_master(pcidev); /* enable bus mastering */ /* initialize the chips */ + fs = get_fs(); + set_fs(KERNEL_DS); /* set mixer output */ frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f); /* set mixer input */ @@ -3050,19 +3451,25 @@ void initialize_chip(struct pci_dev *pci } /* use channel 0 for record, channel 1 for play */ maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 1); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + set_fs(fs); +#endif s->deviceid = pcidev->device; - if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) { - /* chip version and hw capability check */ s->chip_version = query_chip(s); - printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version); - + printk(KERN_INFO "chip version = 0%d\n", s->chip_version); + s->modem = modem; + if (modem) { + /* enable FLINKON and disable FLINKOFF */ + maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0x40, 0x80); + printk(KERN_INFO "cm: modem function supported\n"); + } /* seet SPDIF-in inverse before enable SPDIF loop */ if (spdif_inverse) { /* turn on spdif-in inverse */ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1); - printk(KERN_INFO "cmpci: Inverse SPDIF-in\n"); + printk(KERN_INFO "cm: Inverse SPDIF-in\n"); } else { /* turn off spdif-ininverse */ maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0); @@ -3073,7 +3480,7 @@ void initialize_chip(struct pci_dev *pci s->status |= DO_SPDIF_LOOP; /* turn on spdif-in to spdif-out */ maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x80); - printk(KERN_INFO "cmpci: Enable SPDIF loop\n"); + printk(KERN_INFO "cm: Enable SPDIF loop\n"); } else { s->status &= ~DO_SPDIF_LOOP; /* turn off spdif-in to spdif-out */ @@ -3097,6 +3504,9 @@ void initialize_chip(struct pci_dev *pci /* 8338 will fall here */ s->max_channels = 2; } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + set_fs(fs); +#endif /* queue it for later freeing */ s->next = devs; devs = s; @@ -3114,7 +3524,7 @@ void initialize_chip(struct pci_dev *pci err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: - printk(KERN_ERR "cmpci: cannot register misc device\n"); + printk(KERN_ERR "cm: cannot register misc device\n"); free_irq(s->irq, s); err_irq: #ifdef CONFIG_SOUND_CMPCI_FM @@ -3125,7 +3535,11 @@ void initialize_chip(struct pci_dev *pci #endif release_region(s->iobase, CM_EXTENT_CODEC); err_region5: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) kfree(s); +#else + kfree_s(s, sizeof(struct cm_state)); +#endif } if (!devs) { if (wavetable_mem) @@ -3135,13 +3549,28 @@ void initialize_chip(struct pci_dev *pci return; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static int __init init_cmpci(void) +#else +#ifdef MODULE +int __init init_module(void) +#else +int __init init_cmpci(void) +#endif +#endif { struct pci_dev *pcidev = NULL; int index = 0; - printk(KERN_INFO "cmpci: version $Revision: 5.64 $ time " __TIME__ " " __DATE__ "\n"); - +#ifdef CONFIG_PCI + if (!pci_present()) /* No PCI bus in this machine! */ +#endif + return -ENODEV; + printk(KERN_INFO "cm: version $Revision: 5.64 $ time " __TIME__ " " __DATE__ "\n"); +#if 0 + if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) + printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); +#endif while (index < NR_DEVICE && ( (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) { initialize_chip(pcidev); @@ -3164,19 +3593,25 @@ static int __init init_cmpci(void) MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw"); MODULE_DESCRIPTION("CM8x38 Audio Driver"); -MODULE_LICENSE("GPL"); - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static void __exit cleanup_cmpci(void) +#else +void cleanup_module(void) +#endif { struct cm_state *s; while ((s = devs)) { devs = devs->next; outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */ - synchronize_irq(s->irq); + synchronize_irq(); outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */ free_irq(s->irq, s); +#ifdef FIXEDDMA + dealloc_dmabuf(&s->dma_dac); + dealloc_dmabuf(&s->dma_adc); +#endif /* reset mixer */ wrmixer(s, DSP_MIX_DATARESETIDX, 0); @@ -3196,12 +3631,18 @@ static void __exit cleanup_cmpci(void) #ifdef CONFIG_SOUND_CMPCI_FM unregister_sound_special(s->dev_dmfm); #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) kfree(s); +#else + kfree_s(s, sizeof(struct cm_state)); +#endif } if (wavetable_mem) free_pages(wavetable_mem, 20-PAGE_SHIFT); - printk(KERN_INFO "cmpci: unloading\n"); + printk(KERN_INFO "cm: unloading\n"); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) module_init(init_cmpci); module_exit(cleanup_cmpci); +#endif _