patch-2.3.43 linux/drivers/sound/es1371.c
Next file: linux/drivers/sound/esssolo1.c
Previous file: linux/drivers/sound/es1370.c
Back to the patch index
Back to the overall index
- Lines: 1162
- Date:
Wed Feb 9 11:42:35 2000
- Orig file:
v2.3.42/linux/drivers/sound/es1371.c
- Orig date:
Fri Jan 21 18:19:17 2000
diff -u --recursive --new-file v2.3.42/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
@@ -98,6 +98,8 @@
* Eric Lemar, elemar@cs.washington.edu
* 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun;
* Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * 07.02.2000 0.24 Use pci_alloc_consistent and pci_register_driver
+ * 07.02.2000 0.25 Use ac97_codec
*/
/*****************************************************************************/
@@ -121,7 +123,7 @@
#include <asm/dma.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
-#include "ac97.h"
+#include "ac97_codec.h"
/* --------------------------------------------------------------------- */
@@ -376,49 +378,18 @@
/* --------------------------------------------------------------------- */
-static const char *stereo_enhancement[] __initdata =
-{
- "no 3D stereo enhancement",
- "Analog Devices Phat Stereo",
- "Creative Stereo Enhancement",
- "National Semiconductor 3D Stereo Enhancement",
- "YAMAHA Ymersion",
- "BBE 3D Stereo Enhancement",
- "Crystal Semiconductor 3D Stereo Enhancement",
- "Qsound QXpander",
- "Spatializer 3D Stereo Enhancement",
- "SRS 3D Stereo Enhancement",
- "Platform Technologies 3D Stereo Enhancement",
- "AKM 3D Audio",
- "Aureal Stereo Enhancement",
- "AZTECH 3D Enhancement",
- "Binaura 3D Audio Enhancement",
- "ESS Technology Stereo Enhancement",
- "Harman International VMAx",
- "NVidea 3D Stereo Enhancement",
- "Philips Incredible Sound",
- "Texas Instruments 3D Stereo Enhancement",
- "VLSI Technology 3D Stereo Enhancement",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "SigmaTel SS3D"
-};
-
-/* --------------------------------------------------------------------- */
-
struct es1371_state {
/* magic */
unsigned int magic;
- /* we keep sb cards in a linked list */
- struct es1371_state *next;
+ /* list of es1371 devices */
+ struct list_head devs;
+
+ /* the corresponding pci_dev structure */
+ struct pci_dev *dev;
/* soundcore stuff */
int dev_audio;
- int dev_mixer;
int dev_dac;
int dev_midi;
@@ -435,14 +406,8 @@
/* debug /proc entry */
struct proc_dir_entry *ps;
#endif /* ES1371_DEBUG */
- /* mixer registers; there is no HW readback */
- struct {
- unsigned short codec_id;
- unsigned int modcnt;
-#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS
- unsigned short vol[13];
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- } mix;
+
+ struct ac97_codec codec;
/* wave stuff */
unsigned ctrl;
@@ -456,6 +421,7 @@
struct dmabuf {
void *rawbuf;
+ dma_addr_t dmaaddr;
unsigned buforder;
unsigned numfrag;
unsigned fragshift;
@@ -490,7 +456,7 @@
/* --------------------------------------------------------------------- */
-static struct es1371_state *devs = NULL;
+static LIST_HEAD(devs);
/* --------------------------------------------------------------------- */
@@ -707,8 +673,9 @@
/* --------------------------------------------------------------------- */
-static void wrcodec(struct es1371_state *s, unsigned addr, unsigned data)
+static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
{
+ struct es1371_state *s = (struct es1371_state *)codec->private_data;
unsigned long flags;
unsigned t, x;
@@ -721,7 +688,7 @@
x = wait_src_ready(s);
/* enable SRC state data in SRC mux */
- outl(( x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
+ outl((x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000,
s->io+ES1371_REG_SRCONV);
/* wait for not busy (state 0) first to avoid
@@ -748,8 +715,9 @@
spin_unlock_irqrestore(&s->lock, flags);
}
-static unsigned rdcodec(struct es1371_state *s, unsigned addr)
+static u16 rdcodec(struct ac97_codec *codec, u8 addr)
{
+ struct es1371_state *s = (struct es1371_state *)codec->private_data;
unsigned long flags;
unsigned t, x;
@@ -907,7 +875,7 @@
#define DMABUF_MINORDER 1
-extern inline void dealloc_dmabuf(struct dmabuf *db)
+extern inline void dealloc_dmabuf(struct es1371_state *s, struct dmabuf *db)
{
unsigned long map, mapend;
@@ -915,8 +883,8 @@
/* undo marking the pages as reserved */
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);
- free_pages((unsigned long)db->rawbuf, db->buforder);
+ clear_bit(PG_reserved, &mem_map[map].flags);
+ pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
}
db->rawbuf = NULL;
db->mapped = db->ready = 0;
@@ -933,7 +901,7 @@
if (!db->rawbuf) {
db->ready = db->mapped = 0;
for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
+ if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
break;
if (!db->rawbuf)
return -ENOMEM;
@@ -968,7 +936,7 @@
db->dmasize = db->numfrag << db->fragshift;
memset(db->rawbuf, (fmt & ES1371_FMT_S16) ? 0 : 0x80, db->dmasize);
outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE);
- outl(virt_to_bus(db->rawbuf), s->io+(reg & 0xff));
+ outl(db->dmaaddr, s->io+(reg & 0xff));
outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
db->ready = 1;
return 0;
@@ -1157,6 +1125,13 @@
/* --------------------------------------------------------------------- */
+static loff_t es1371_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
/*
* AC97 Mixer Register to Connections mapping of the Concert 97 board
*
@@ -1172,435 +1147,19 @@
* AC97_PCMOUT_VOL Wave Output (stereo)
*/
-#define AC97_PESSIMISTIC
-
-/*
- * this define causes the driver to assume that all optional
- * AC97 bits are missing. This is what Ensoniq does too in their
- * Windows driver. Maybe we should one day autoprobe for these
- * bits. But anyway I have to see an AC97 codec that implements
- * one of those optional (volume) bits.
- */
-
-static const unsigned int recsrc[8] =
-{
- SOUND_MASK_MIC,
- SOUND_MASK_CD,
- SOUND_MASK_VIDEO,
- SOUND_MASK_LINE1,
- SOUND_MASK_LINE,
- SOUND_MASK_VOLUME,
- SOUND_MASK_PHONEOUT,
- SOUND_MASK_PHONEIN
-};
-
-static const unsigned char volreg[SOUND_MIXER_NRDEVICES] =
-{
- /* 5 bit stereo */
- [SOUND_MIXER_LINE] = AC97_LINEIN_VOL,
- [SOUND_MIXER_CD] = AC97_CD_VOL,
- [SOUND_MIXER_VIDEO] = AC97_VIDEO_VOL,
- [SOUND_MIXER_LINE1] = AC97_AUX_VOL,
- [SOUND_MIXER_PCM] = AC97_PCMOUT_VOL,
- /* 6 bit stereo */
- [SOUND_MIXER_VOLUME] = AC97_MASTER_VOL_STEREO,
- [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONE_VOL,
- /* 6 bit mono */
- [SOUND_MIXER_OGAIN] = AC97_MASTER_VOL_MONO,
- [SOUND_MIXER_PHONEIN] = AC97_PHONE_VOL,
- /* 4 bit mono but shifted by 1 */
- [SOUND_MIXER_SPEAKER] = AC97_MASTER_TONE,
- /* 6 bit mono + preamp */
- [SOUND_MIXER_MIC] = AC97_MIC_VOL,
- /* 4 bit stereo */
- [SOUND_MIXER_RECLEV] = AC97_RECORD_GAIN,
- /* 4 bit mono */
- [SOUND_MIXER_IGAIN] = AC97_RECORD_GAIN_MIC
-};
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
-
-static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg)
-{
- int j;
-
- switch (ch) {
- case SOUND_MIXER_MIC:
- j = rdcodec(s, AC97_MIC_VOL);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
-#ifdef AC97_PESSIMISTIC
- return put_user(0x4949 - 0x202 * (j & 0x1f) + ((j & 0x40) ? 0x1b1b : 0), (int *)arg);
-#else /* AC97_PESSIMISTIC */
- return put_user(0x5757 - 0x101 * ((j & 0x3f) * 5 / 4) + ((j & 0x40) ? 0x0d0d : 0), (int *)arg);
-#endif /* AC97_PESSIMISTIC */
-
- case SOUND_MIXER_OGAIN:
- case SOUND_MIXER_PHONEIN:
- j = rdcodec(s, volreg[ch]);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
-#ifdef AC97_PESSIMISTIC
- return put_user(0x6464 - 0x303 * (j & 0x1f), (int *)arg);
-#else /* AC97_PESSIMISTIC */
- return put_user((0x6464 - 0x303 * (j & 0x3f) / 2) & 0x7f7f, (int *)arg);
-#endif /* AC97_PESSIMISTIC */
-
- case SOUND_MIXER_PHONEOUT:
- if (!(s->mix.codec_id & CODEC_ID_HEADPHONEOUT))
- return -EINVAL;
- /* fall through */
- case SOUND_MIXER_VOLUME:
- j = rdcodec(s, volreg[ch]);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
-#ifdef AC97_PESSIMISTIC
- return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
-#else /* AC97_PESSIMISTIC */
- return put_user((0x6464 - (swab(j) & 0x3f3f) * 3 / 2) & 0x7f7f, (int *)arg);
-#endif /* AC97_PESSIMISTIC */
-
- case SOUND_MIXER_SPEAKER:
- j = rdcodec(s, AC97_PCBEEP_VOL);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
- return put_user(0x6464 - ((j >> 1) & 0xf) * 0x606, (int *)arg);
-
- case SOUND_MIXER_LINE:
- case SOUND_MIXER_CD:
- case SOUND_MIXER_VIDEO:
- case SOUND_MIXER_LINE1:
- case SOUND_MIXER_PCM:
- j = rdcodec(s, volreg[ch]);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
- return put_user(0x6464 - (swab(j) & 0x1f1f) * 3, (int *)arg);
-
- case SOUND_MIXER_BASS:
- case SOUND_MIXER_TREBLE:
- if (!(s->mix.codec_id & CODEC_ID_BASSTREBLE))
- return -EINVAL;
- j = rdcodec(s, AC97_MASTER_TONE);
- if (ch == SOUND_MIXER_BASS)
- j >>= 8;
- return put_user((((j & 15) * 100) / 15) * 0x101, (int *)arg);
-
- /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
- case SOUND_MIXER_RECLEV:
- j = rdcodec(s, AC97_RECORD_GAIN);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
- return put_user((swab(j) & 0xf0f) * 6 + 0xa0a, (int *)arg);
-
- case SOUND_MIXER_IGAIN:
- if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
- return -EINVAL;
- j = rdcodec(s, AC97_RECORD_GAIN_MIC);
- if (j & AC97_MUTE)
- return put_user(0, (int *)arg);
- return put_user((j & 0xf) * 0x606 + 0xa0a, (int *)arg);
-
- default:
- return -EINVAL;
- }
-}
-
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
- /* 5 bit stereo */
- [SOUND_MIXER_LINE] = 1,
- [SOUND_MIXER_CD] = 2,
- [SOUND_MIXER_VIDEO] = 3,
- [SOUND_MIXER_LINE1] = 4,
- [SOUND_MIXER_PCM] = 5,
- /* 6 bit stereo */
- [SOUND_MIXER_VOLUME] = 6,
- [SOUND_MIXER_PHONEOUT] = 7,
- /* 6 bit mono */
- [SOUND_MIXER_OGAIN] = 8,
- [SOUND_MIXER_PHONEIN] = 9,
- /* 4 bit mono but shifted by 1 */
- [SOUND_MIXER_SPEAKER] = 10,
- /* 6 bit mono + preamp */
- [SOUND_MIXER_MIC] = 11,
- /* 4 bit stereo */
- [SOUND_MIXER_RECLEV] = 12,
- /* 4 bit mono */
- [SOUND_MIXER_IGAIN] = 13
-};
-
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val)
-{
- int i;
- unsigned l1, r1;
-
- l1 = val & 0xff;
- r1 = (val >> 8) & 0xff;
- if (l1 > 100)
- l1 = 100;
- if (r1 > 100)
- r1 = 100;
- switch (ch) {
- case SOUND_MIXER_LINE:
- case SOUND_MIXER_CD:
- case SOUND_MIXER_VIDEO:
- case SOUND_MIXER_LINE1:
- case SOUND_MIXER_PCM:
- if (l1 < 7 && r1 < 7) {
- wrcodec(s, volreg[ch], AC97_MUTE);
- return 0;
- }
- if (l1 < 7)
- l1 = 7;
- if (r1 < 7)
- r1 = 7;
- wrcodec(s, volreg[ch], (((100 - l1) / 3) << 8) | ((100 - r1) / 3));
- return 0;
-
- case SOUND_MIXER_PHONEOUT:
- if (!(s->mix.codec_id & CODEC_ID_HEADPHONEOUT))
- return -EINVAL;
- /* fall through */
- case SOUND_MIXER_VOLUME:
-#ifdef AC97_PESSIMISTIC
- if (l1 < 7 && r1 < 7) {
- wrcodec(s, volreg[ch], AC97_MUTE);
- return 0;
- }
- if (l1 < 7)
- l1 = 7;
- if (r1 < 7)
- r1 = 7;
- wrcodec(s, volreg[ch], (((100 - l1) / 3) << 8) | ((100 - r1) / 3));
- return 0;
-#else /* AC97_PESSIMISTIC */
- if (l1 < 4 && r1 < 4) {
- wrcodec(s, volreg[ch], AC97_MUTE);
- return 0;
- }
- if (l1 < 4)
- l1 = 4;
- if (r1 < 4)
- r1 = 4;
- wrcodec(s, volreg[ch], ((2 * (100 - l1) / 3) << 8) | (2 * (100 - r1) / 3));
- return 0;
-#endif /* AC97_PESSIMISTIC */
-
- case SOUND_MIXER_OGAIN:
- case SOUND_MIXER_PHONEIN:
-#ifdef AC97_PESSIMISTIC
- wrcodec(s, volreg[ch], (l1 < 7) ? AC97_MUTE : (100 - l1) / 3);
- return 0;
-#else /* AC97_PESSIMISTIC */
- wrcodec(s, volreg[ch], (l1 < 4) ? AC97_MUTE : (2 * (100 - l1) / 3));
- return 0;
-#endif /* AC97_PESSIMISTIC */
-
- case SOUND_MIXER_SPEAKER:
- wrcodec(s, AC97_PCBEEP_VOL, (l1 < 10) ? AC97_MUTE : ((100 - l1) / 6) << 1);
- return 0;
-
- case SOUND_MIXER_MIC:
-#ifdef AC97_PESSIMISTIC
- if (l1 < 11) {
- wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
- return 0;
- }
- i = 0;
- if (l1 >= 27) {
- l1 -= 27;
- i = 0x40;
- }
- if (l1 < 11)
- l1 = 11;
- wrcodec(s, AC97_MIC_VOL, ((73 - l1) / 2) | i);
- return 0;
-#else /* AC97_PESSIMISTIC */
- if (l1 < 9) {
- wrcodec(s, AC97_MIC_VOL, AC97_MUTE);
- return 0;
- }
- i = 0;
- if (l1 >= 13) {
- l1 -= 13;
- i = 0x40;
- }
- if (l1 < 9)
- l1 = 9;
- wrcodec(s, AC97_MIC_VOL, (((87 - l1) * 4) / 5) | i);
- return 0;
-#endif /* AC97_PESSIMISTIC */
-
- case SOUND_MIXER_BASS:
- val = ((l1 * 15) / 100) & 0xf;
- wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0x00ff) | (val << 8));
- return 0;
-
- case SOUND_MIXER_TREBLE:
- val = ((l1 * 15) / 100) & 0xf;
- wrcodec(s, AC97_MASTER_TONE, (rdcodec(s, AC97_MASTER_TONE) & 0xff00) | val);
- return 0;
-
- /* SOUND_MIXER_RECLEV and SOUND_MIXER_IGAIN specify gain */
- case SOUND_MIXER_RECLEV:
- if (l1 < 10 || r1 < 10) {
- wrcodec(s, AC97_RECORD_GAIN, AC97_MUTE);
- return 0;
- }
- if (l1 < 10)
- l1 = 10;
- if (r1 < 10)
- r1 = 10;
- wrcodec(s, AC97_RECORD_GAIN, (((l1 - 10) / 6) << 8) | ((r1 - 10) / 6));
- return 0;
-
- case SOUND_MIXER_IGAIN:
- if (!(s->mix.codec_id & CODEC_ID_DEDICATEDMIC))
- return -EINVAL;
- wrcodec(s, AC97_RECORD_GAIN_MIC, (l1 < 10) ? AC97_MUTE : ((l1 - 10) / 6) & 0xf);
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long arg)
-{
- int i, val;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_PRIVATE1) {
- if (!(s->mix.codec_id & (CODEC_ID_SEMASK << CODEC_ID_SESHIFT)))
- return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
- if (val & 1)
- wrcodec(s, AC97_3D_CONTROL, ((val << 3) & 0xf00) | ((val >> 1) & 0xf));
- val = rdcodec(s, AC97_3D_CONTROL);
- return put_user(((val & 0xf) << 1) | ((val & 0xf00) >> 3), (int *)arg);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strncpy(info.id, "ES1371", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1371", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strncpy(info.id, "ES1371", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1371", sizeof(info.name));
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7], (int *)arg);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO |
- SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME |
- SOUND_MASK_OGAIN | SOUND_MASK_PHONEIN | SOUND_MASK_SPEAKER |
- SOUND_MASK_MIC | SOUND_MASK_RECLEV |
- ((s->mix.codec_id & CODEC_ID_BASSTREBLE) ? (SOUND_MASK_BASS | SOUND_MASK_TREBLE) : 0) |
- ((s->mix.codec_id & CODEC_ID_HEADPHONEOUT) ? SOUND_MASK_PHONEOUT : 0) |
- ((s->mix.codec_id & CODEC_ID_DEDICATEDMIC) ? SOUND_MASK_IGAIN : 0), (int *)arg);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- return put_user(SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VIDEO | SOUND_MASK_LINE1 |
- SOUND_MASK_LINE | SOUND_MASK_VOLUME | SOUND_MASK_PHONEOUT |
- SOUND_MASK_PHONEIN, (int *)arg);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- return put_user(SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_VIDEO |
- SOUND_MASK_LINE1 | SOUND_MASK_PCM | SOUND_MASK_VOLUME |
- SOUND_MASK_PHONEOUT | SOUND_MASK_RECLEV, (int *)arg);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES)
- return -EINVAL;
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- return mixer_rdch(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))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- get_user_ret(val, (int *)arg, -EFAULT);
- i = hweight32(val);
- if (i == 0)
- return 0; /*val = mixer_recmask(s);*/
- else if (i > 1)
- val &= ~recsrc[rdcodec(s, AC97_RECORD_SELECT) & 7];
- for (i = 0; i < 8; i++) {
- if (val & recsrc[i]) {
- wrcodec(s, AC97_RECORD_SELECT, 0x101 * i);
- return 0;
- }
- }
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES)
- return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
- if (mixer_wrch(s, i, val))
- return -EINVAL;
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- return mixer_rdch(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 es1371_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-/* --------------------------------------------------------------------- */
-
static int es1371_open_mixdev(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
- struct es1371_state *s = devs;
+ struct list_head *list;
+ struct es1371_state *s;
- while (s && s->dev_mixer != minor)
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct es1371_state, devs);
+ if (s->codec.dev_mixer == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
MOD_INC_USE_COUNT;
@@ -1618,23 +1177,15 @@
static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- return mixer_ioctl((struct es1371_state *)file->private_data, cmd, arg);
+ struct ac97_codec *codec = &((struct es1371_state *)file->private_data)->codec;
+ return codec->mixer_ioctl(codec, cmd, arg);
}
static /*const*/ struct file_operations es1371_mixer_fops = {
- &es1371_llseek,
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- &es1371_ioctl_mixdev,
- NULL, /* mmap */
- &es1371_open_mixdev,
- NULL, /* flush */
- &es1371_release_mixdev,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: es1371_llseek,
+ ioctl: es1371_ioctl_mixdev,
+ open: es1371_open_mixdev,
+ release: es1371_release_mixdev,
};
/* --------------------------------------------------------------------- */
@@ -2223,20 +1774,24 @@
return -EINVAL;
}
- return mixer_ioctl(s, cmd, arg);
+ return s->codec.mixer_ioctl(&s->codec, cmd, arg);
}
static int es1371_open(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct es1371_state *s = devs;
unsigned long flags;
+ struct list_head *list;
+ struct es1371_state *s;
- while (s && ((s->dev_audio ^ minor) & ~0xf))
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct es1371_state, devs);
+ if (!((s->dev_audio ^ minor) & ~0xf))
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -2297,11 +1852,11 @@
down(&s->open_sem);
if (file->f_mode & FMODE_WRITE) {
stop_dac2(s);
- dealloc_dmabuf(&s->dma_dac2);
+ dealloc_dmabuf(s, &s->dma_dac2);
}
if (file->f_mode & FMODE_READ) {
stop_adc(s);
- dealloc_dmabuf(&s->dma_adc);
+ dealloc_dmabuf(s, &s->dma_adc);
}
s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
up(&s->open_sem);
@@ -2311,19 +1866,14 @@
}
static /*const*/ struct file_operations es1371_audio_fops = {
- &es1371_llseek,
- &es1371_read,
- &es1371_write,
- NULL, /* readdir */
- &es1371_poll,
- &es1371_ioctl,
- &es1371_mmap,
- &es1371_open,
- NULL, /* flush */
- &es1371_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: es1371_llseek,
+ read: es1371_read,
+ write: es1371_write,
+ poll: es1371_poll,
+ ioctl: es1371_ioctl,
+ mmap: es1371_mmap,
+ open: es1371_open,
+ release: es1371_release,
};
/* --------------------------------------------------------------------- */
@@ -2626,20 +2176,24 @@
return -EINVAL;
}
- return mixer_ioctl(s, cmd, arg);
+ return s->codec.mixer_ioctl(&s->codec, cmd, arg);
}
static int es1371_open_dac(struct inode *inode, struct file *file)
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct es1371_state *s = devs;
unsigned long flags;
+ struct list_head *list;
+ struct es1371_state *s;
- while (s && ((s->dev_dac ^ minor) & ~0xf))
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct es1371_state, devs);
+ if (!((s->dev_dac ^ minor) & ~0xf))
+ break;
+ }
VALIDATE_STATE(s);
/* we allow opening with O_RDWR, most programs do it although they will only write */
#if 0
@@ -2690,7 +2244,7 @@
drain_dac1(s, file->f_flags & O_NONBLOCK);
down(&s->open_sem);
stop_dac1(s);
- dealloc_dmabuf(&s->dma_dac1);
+ dealloc_dmabuf(s, &s->dma_dac1);
s->open_mode &= ~FMODE_DAC;
up(&s->open_sem);
wake_up(&s->open_wait);
@@ -2699,19 +2253,13 @@
}
static /*const*/ struct file_operations es1371_dac_fops = {
- &es1371_llseek,
- NULL, /* read */
- &es1371_write_dac,
- NULL, /* readdir */
- &es1371_poll_dac,
- &es1371_ioctl_dac,
- &es1371_mmap_dac,
- &es1371_open_dac,
- NULL, /* flush */
- &es1371_release_dac,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: es1371_llseek,
+ write: es1371_write_dac,
+ poll: es1371_poll_dac,
+ ioctl: es1371_ioctl_dac,
+ mmap: es1371_mmap_dac,
+ open: es1371_open_dac,
+ release: es1371_release_dac,
};
/* --------------------------------------------------------------------- */
@@ -2874,13 +2422,17 @@
{
int minor = MINOR(inode->i_rdev);
DECLARE_WAITQUEUE(wait, current);
- struct es1371_state *s = devs;
unsigned long flags;
+ struct list_head *list;
+ struct es1371_state *s;
- while (s && s->dev_midi != minor)
- s = s->next;
- if (!s)
- return -ENODEV;
+ for (list = devs.next; ; list = list->next) {
+ if (list == &devs)
+ return -ENODEV;
+ s = list_entry(list, struct es1371_state, devs);
+ if (s->dev_midi == minor)
+ break;
+ }
VALIDATE_STATE(s);
file->private_data = s;
/* wait for device to become free */
@@ -2970,45 +2522,38 @@
}
static /*const*/ struct file_operations es1371_midi_fops = {
- &es1371_llseek,
- &es1371_midi_read,
- &es1371_midi_write,
- NULL, /* readdir */
- &es1371_midi_poll,
- NULL, /* ioctl */
- NULL, /* mmap */
- &es1371_midi_open,
- NULL, /* flush */
- &es1371_midi_release,
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: es1371_llseek,
+ read: es1371_midi_read,
+ write: es1371_midi_write,
+ poll: es1371_midi_poll,
+ open: es1371_midi_open,
+ release: es1371_midi_release,
};
/* --------------------------------------------------------------------- */
/*
* for debugging purposes, we'll create a proc device that dumps the
- * CODEC chipstate
+ * CODEC chipstate
*/
#ifdef ES1371_DEBUG
static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data)
{
- int len = 0;
-
- struct es1371_state *s = devs;
- int cnt;
+ struct es1371_state *s;
+ int cnt, len = 0;
+ if (list_empty(&devs))
+ return 0;
+ s = list_entry(devs.next, struct es1371_state, devs);
/* print out header */
len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n");
/* print out CODEC state */
len += sprintf (buf + len, "AC97 CODEC state\n");
-
- for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
- len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s , cnt));
-
+ for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
+ len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(&s->codec, cnt));
+
if (fpos >=len){
*start = buf;
*eof =1;
@@ -3025,12 +2570,14 @@
/* --------------------------------------------------------------------- */
-/* maximum number of devices */
+/* maximum number of devices; only used for command line params */
#define NR_DEVICE 5
static int joystick[NR_DEVICE] = { 0, };
static int spdif[NR_DEVICE] = { 0, };
+static unsigned int devindex = 0;
+
MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i");
MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)");
MODULE_PARM(spdif, "1-" __MODULE_STRING(NR_DEVICE) "i");
@@ -3064,12 +2611,11 @@
((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-static int __init probe_chip(struct pci_dev *pcidev, int index)
+static int es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct es1371_state *s;
mm_segment_t fs;
- int i, val, val2;
- unsigned char id[4];
+ int i, val;
unsigned long tmo;
signed long tmo2;
unsigned int cssr;
@@ -3092,28 +2638,33 @@
init_MUTEX(&s->open_sem);
spin_lock_init(&s->lock);
s->magic = ES1371_MAGIC;
+ s->dev = pcidev;
s->io = RSRCADDRESS(pcidev, 0);
s->irq = pcidev->irq;
s->vendor = pcidev->vendor;
s->device = pcidev->device;
pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
+ s->codec.private_data = s;
+ s->codec.id = 0;
+ s->codec.codec_read = rdcodec;
+ s->codec.codec_write = wrcodec;
printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n",
s->vendor, s->device, s->rev);
- if (check_region(s->io, ES1371_EXTENT)) {
+ if (!request_region(s->io, ES1371_EXTENT, "es1371")) {
printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1);
goto err_region;
}
- request_region(s->io, ES1371_EXTENT, "es1371");
if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) {
printk(KERN_ERR "es1371: irq %u in use\n", s->irq);
goto err_irq;
}
+ pci_enable_device(pcidev);
printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n"
- KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]);
+ KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[devindex]);
/* register devices */
if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0)
goto err_dev1;
- if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0)
+ if ((s->codec.dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0)
goto err_dev2;
if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0)
goto err_dev3;
@@ -3126,17 +2677,17 @@
/* initialize codec registers */
s->ctrl = 0;
- if ((joystick[index] & ~0x18) == 0x200) {
- if (check_region(joystick[index], JOY_EXTENT))
- printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]);
+ if ((joystick[devindex] & ~0x18) == 0x200) {
+ if (check_region(joystick[devindex], JOY_EXTENT))
+ printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[devindex]);
else {
- s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+ s->ctrl |= CTRL_JYSTK_EN | (((joystick[devindex] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
}
}
s->sctrl = 0;
cssr = 0;
/* check to see if s/pdif mode is being requested */
- if (spdif[index]) {
+ if (spdif[devindex]) {
if (s->rev >= 4) {
printk(KERN_INFO "es1371: enabling S/PDIF output\n");
cssr |= STAT_EN_SPDIF;
@@ -3173,68 +2724,34 @@
/* init the sample rate converter */
src_init(s);
/* codec init */
- wrcodec(s, AC97_RESET, 0); /* reset codec */
- s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */
- val = rdcodec(s, AC97_VENDOR_ID1);
- val2 = rdcodec(s, AC97_VENDOR_ID2);
- id[0] = val >> 8;
- id[1] = val;
- id[2] = val2 >> 8;
- id[3] = 0;
- if (id[0] <= ' ' || id[0] > 0x7f)
- id[0] = ' ';
- if (id[1] <= ' ' || id[1] > 0x7f)
- id[1] = ' ';
- if (id[2] <= ' ' || id[2] > 0x7f)
- id[2] = ' ';
- printk(KERN_INFO "es1371: codec vendor %s (0x%04x%02x) revision %d (0x%02x)\n",
- id, val & 0xffff, (val2 >> 8) & 0xff, val2 & 0xff, val2 & 0xff);
- printk(KERN_INFO "es1371: codec features");
- if (s->mix.codec_id & CODEC_ID_DEDICATEDMIC)
- printk(" dedicated MIC PCM in");
- if (s->mix.codec_id & CODEC_ID_MODEMCODEC)
- printk(" Modem Line Codec");
- if (s->mix.codec_id & CODEC_ID_BASSTREBLE)
- printk(" Bass & Treble");
- if (s->mix.codec_id & CODEC_ID_SIMULATEDSTEREO)
- printk(" Simulated Stereo");
- if (s->mix.codec_id & CODEC_ID_HEADPHONEOUT)
- printk(" Headphone out");
- if (s->mix.codec_id & CODEC_ID_LOUDNESS)
- printk(" Loudness");
- if (s->mix.codec_id & CODEC_ID_18BITDAC)
- printk(" 18bit DAC");
- if (s->mix.codec_id & CODEC_ID_20BITDAC)
- printk(" 20bit DAC");
- if (s->mix.codec_id & CODEC_ID_18BITADC)
- printk(" 18bit ADC");
- if (s->mix.codec_id & CODEC_ID_20BITADC)
- printk(" 20bit ADC");
- printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none");
- val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK;
- printk(KERN_INFO "es1371: stereo enhancement: %s\n",
- (val <= 26 && stereo_enhancement[val]) ? stereo_enhancement[val] : "unknown");
-
+ if (!ac97_probe_codec(&s->codec))
+ goto err_dev4;
+ /* set default values */
fs = get_fs();
set_fs(KERNEL_DS);
val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
+ s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
+ s->codec.mixer_ioctl(&s->codec, initvol[i].mixch, (unsigned long)&val);
}
set_fs(fs);
/* turn on S/PDIF output driver if requested */
outl(cssr, s->io+ES1371_REG_STATUS);
- /* queue it for later freeing */
- s->next = devs;
- devs = s;
+ /* store it in the driver field */
+ pcidev->driver_data = s;
+ pcidev->dma_mask = 0xffffffff;
+ /* put it into driver list */
+ list_add_tail(&s->devs, &devs);
+ /* increment devindex */
+ if (devindex < NR_DEVICE-1)
+ devindex++;
return 0;
err_dev4:
unregister_sound_dsp(s->dev_dac);
err_dev3:
- unregister_sound_mixer(s->dev_mixer);
+ unregister_sound_mixer(s->codec.dev_mixer);
err_dev2:
unregister_sound_dsp(s->dev_audio);
err_dev1:
@@ -3247,55 +2764,60 @@
return -1;
}
+static void es1371_remove(struct pci_dev *dev)
+{
+ struct es1371_state *s = (struct es1371_state *)dev->driver_data;
+
+ if (!s)
+ return;
+ list_del(&s->devs);
+#ifdef ES1371_DEBUG
+ if (s->ps)
+ remove_proc_entry("es1371", NULL);
+#endif /* ES1371_DEBUG */
+ outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
+ outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
+ synchronize_irq();
+ free_irq(s->irq, s);
+ release_region(s->io, ES1371_EXTENT);
+ unregister_sound_dsp(s->dev_audio);
+ unregister_sound_mixer(s->codec.dev_mixer);
+ unregister_sound_dsp(s->dev_dac);
+ unregister_sound_midi(s->dev_midi);
+ kfree_s(s, sizeof(struct es1371_state));
+ dev->driver_data = NULL;
+}
+
+static const struct pci_device_id id_table[] = {
+ { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, id_table);
+
+static struct pci_driver es1371_driver = {
+ name: "es1371",
+ id_table: id_table,
+ probe: es1371_probe,
+ remove: es1371_remove
+};
static int __init init_es1371(void)
{
- struct pci_dev *pcidev = NULL;
- int index = 0;
-
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1371: version v0.23 time " __TIME__ " " __DATE__ "\n");
- while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))) {
- if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) {
- if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 &&
- pcidev->device != PCI_DEVICE_ID_ENSONIQ_CT5880)
- continue;
- } else if (pcidev->vendor == PCI_VENDOR_ID_ECTIVA) {
- if (pcidev->device != PCI_DEVICE_ID_ECTIVA_EV1938)
- continue;
- } else
- continue;
- if (!probe_chip(pcidev, index))
- index++;
- }
- if (!devs)
+ printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n");
+ if (!pci_register_driver(&es1371_driver))
return -ENODEV;
return 0;
}
static void __exit cleanup_es1371(void)
{
- struct es1371_state *s;
-
- while ((s = devs)) {
- devs = devs->next;
-#ifdef ES1371_DEBUG
- if (s->ps)
- remove_proc_entry("es1371", NULL);
-#endif /* ES1371_DEBUG */
- outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */
- outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
- synchronize_irq();
- free_irq(s->irq, s);
- release_region(s->io, ES1371_EXTENT);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_dsp(s->dev_dac);
- unregister_sound_midi(s->dev_midi);
- kfree_s(s, sizeof(struct es1371_state));
- }
printk(KERN_INFO "es1371: unloading\n");
+ pci_unregister_driver(&es1371_driver);
}
module_init(init_es1371);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)