📄 ad1816.c
字号:
/* mark device as open */ devc->opened = 1; devc->audio_mode = 0; devc->speed = 8000; devc->audio_format=AFMT_U8; devc->channels=1; ad1816_reset(devc->dev_no); /* halt all pending output */ restore_flags (flags); return 0;}static void ad1816_close (int dev) /* close device */{ unsigned long flags; ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc; save_flags (flags); cli (); /* halt all pending output */ ad1816_reset(devc->dev_no); devc->opened = 0; devc->audio_mode = 0; devc->speed = 8000; devc->audio_format=AFMT_U8; devc->format_bits = 0; restore_flags (flags);}/* ------------------------------------------------------------------- *//* Audio driver structure */static struct audio_driver ad1816_audio_driver ={ owner: THIS_MODULE, open: ad1816_open, close: ad1816_close, output_block: ad1816_output_block, start_input: ad1816_start_input, prepare_for_input: ad1816_prepare_for_input, prepare_for_output: ad1816_prepare_for_output, halt_io: ad1816_halt, halt_input: ad1816_halt_input, halt_output: ad1816_halt_output, trigger: ad1816_trigger, set_speed: ad1816_set_speed, set_bits: ad1816_set_bits, set_channels: ad1816_set_channels,};/* ------------------------------------------------------------------- *//* Interrupt handler */static void ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy){ unsigned char status; ad1816_info *devc; int dev; unsigned long flags; if (irq < 0 || irq > 15) { printk ("ad1816: Got bogus interrupt %d\n", irq); return; } dev = irq2dev[irq]; if (dev < 0 || dev >= num_audiodevs) { printk ("ad1816: IRQ2AD1816-mapping failed for irq %d device %d\n", irq,dev); return; } devc = (ad1816_info *) audio_devs[dev]->devc; save_flags(flags); cli(); /* read interrupt register */ status = inb (devc->base+1); /* Clear all interrupt */ outb (~status, devc->base+1); DEBUGNOISE (printk("ad1816: Got interrupt subclass %d\n",status)); devc->irq_ok=1; if (status == 0) DEBUGWARN(printk ("ad1816: interrupt: Got interrupt, but no reason?\n")); if (devc->opened && (devc->audio_mode & PCM_ENABLE_INPUT) && (status&64)) DMAbuf_inputintr (dev); if (devc->opened && (devc->audio_mode & PCM_ENABLE_OUTPUT) && (status & 128)) DMAbuf_outputintr (dev, 1); restore_flags(flags);}/* ------------------------------------------------------------------- *//* Mixer stuff */struct mixer_def { unsigned int regno: 7; unsigned int polarity:1; /* 0=normal, 1=reversed */ unsigned int bitpos:4; unsigned int nbits:4;};static char mix_cvt[101] = { 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99, 100};typedef struct mixer_def mixer_ent;/* * Most of the mixer entries work in backwards. Setting the polarity field * makes them to work correctly. * * The channel numbering used by individual soundcards is not fixed. Some * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. * The current version doesn't try to compensate this. */#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \ {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {MIX_ENT(SOUND_MIXER_VOLUME, 14, 1, 8, 5, 14, 1, 0, 5),MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_SYNTH, 5, 1, 8, 6, 5, 1, 0, 6),MIX_ENT(SOUND_MIXER_PCM, 4, 1, 8, 6, 4, 1, 0, 6),MIX_ENT(SOUND_MIXER_SPEAKER, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_LINE, 18, 1, 8, 5, 18, 1, 0, 5),MIX_ENT(SOUND_MIXER_MIC, 19, 1, 8, 5, 19, 1, 0, 5),MIX_ENT(SOUND_MIXER_CD, 15, 1, 8, 5, 15, 1, 0, 5),MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_RECLEV, 20, 0, 8, 4, 20, 0, 0, 4),MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0),MIX_ENT(SOUND_MIXER_LINE1, 17, 1, 8, 5, 17, 1, 0, 5),MIX_ENT(SOUND_MIXER_LINE2, 16, 1, 8, 5, 16, 1, 0, 5),MIX_ENT(SOUND_MIXER_LINE3, 39, 0, 9, 4, 39, 1, 0, 5)};static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] ={ 0x4343, /* Master Volume */ 0x3232, /* Bass */ 0x3232, /* Treble */ 0x0000, /* FM */ 0x4343, /* PCM */ 0x0000, /* PC Speaker */ 0x0000, /* Ext Line */ 0x0000, /* Mic */ 0x0000, /* CD */ 0x0000, /* Recording monitor */ 0x0000, /* SB PCM */ 0x0000, /* Recording level */ 0x0000, /* Input gain */ 0x0000, /* Output gain */ 0x0000, /* Line1 */ 0x0000, /* Line2 */ 0x0000 /* Line3 (usually line in)*/};#define LEFT_CHN 0#define RIGHT_CHN 1static intad1816_set_recmask (ad1816_info * devc, int mask){ unsigned char recdev; int i, n; mask &= devc->supported_rec_devices; n = 0; /* Count selected device bits */ for (i = 0; i < 32; i++) if (mask & (1 << i)) n++; if (n == 0) mask = SOUND_MASK_MIC; else if (n != 1) { /* Too many devices selected */ /* Filter out active settings */ mask &= ~devc->recmask; n = 0; /* Count selected device bits */ for (i = 0; i < 32; i++) if (mask & (1 << i)) n++; if (n != 1) mask = SOUND_MASK_MIC; } switch (mask) { case SOUND_MASK_MIC: recdev = 5; break; case SOUND_MASK_LINE: recdev = 0; break; case SOUND_MASK_CD: recdev = 2; break; case SOUND_MASK_LINE1: recdev = 4; break; case SOUND_MASK_LINE2: recdev = 3; break; case SOUND_MASK_VOLUME: recdev = 1; break; default: mask = SOUND_MASK_MIC; recdev = 5; } recdev <<= 4; ad_write (devc, 20, (ad_read (devc, 20) & 0x8f8f) | recdev | (recdev<<8)); devc->recmask = mask; return mask;}static voidchange_bits (int *regval, int dev, int chn, int newval){ unsigned char mask; int shift; /* Reverse polarity*/ if (mix_devices[dev][chn].polarity == 1) newval = 100 - newval; mask = (1 << mix_devices[dev][chn].nbits) - 1; shift = mix_devices[dev][chn].bitpos; /* Scale it */ newval = (int) ((newval * mask) + 50) / 100; /* Clear bits */ *regval &= ~(mask << shift); /* Set new value */ *regval |= (newval & mask) << shift; }static intad1816_mixer_get (ad1816_info * devc, int dev){ DEBUGINFO(printk("ad1816: mixer_get called!\n")); /* range check + supported mixer check */ if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES ) return (-(EINVAL)); if (!((1 << dev) & devc->supported_devices)) return -(EINVAL); return devc->levels[dev];}static intad1816_mixer_set (ad1816_info * devc, int dev, int value){ int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; int retvol; int regoffs; int val; int valmute; DEBUGINFO(printk("ad1816: mixer_set called!\n")); if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES ) return -(EINVAL); if (left > 100) left = 100; if (left < 0) left = 0; if (right > 100) right = 100; if (right < 0) right = 0; /* Mono control */ if (mix_devices[dev][RIGHT_CHN].nbits == 0) right = left; retvol = left | (right << 8); /* Scale it */ left = mix_cvt[left]; right = mix_cvt[right]; /* reject all mixers that are not supported */ if (!(devc->supported_devices & (1 << dev))) return -(EINVAL); /* sanity check */ if (mix_devices[dev][LEFT_CHN].nbits == 0) return -(EINVAL); /* keep precise volume internal */ devc->levels[dev] = retvol; /* Set the left channel */ regoffs = mix_devices[dev][LEFT_CHN].regno; val = ad_read (devc, regoffs); change_bits (&val, dev, LEFT_CHN, left); valmute=val; /* Mute bit masking on some registers */ if ( regoffs==5 || regoffs==14 || regoffs==15 || regoffs==16 || regoffs==17 || regoffs==18 || regoffs==19 || regoffs==39) { if (left==0) valmute |= 0x8000; else valmute &= ~0x8000; } ad_write (devc, regoffs, valmute); /* mute */ /* * Set the right channel */ /* Was just a mono channel */ if (mix_devices[dev][RIGHT_CHN].nbits == 0) return retvol; regoffs = mix_devices[dev][RIGHT_CHN].regno; val = ad_read (devc, regoffs); change_bits (&val, dev, RIGHT_CHN, right); valmute=val; if ( regoffs==5 || regoffs==14 || regoffs==15 || regoffs==16 || regoffs==17 || regoffs==18 || regoffs==19 || regoffs==39) { if (right==0) valmute |= 0x80; else valmute &= ~0x80; } ad_write (devc, regoffs, valmute); /* mute */ return retvol;}#define MIXER_DEVICES ( SOUND_MASK_VOLUME | \ SOUND_MASK_SYNTH | \ SOUND_MASK_PCM | \ SOUND_MASK_LINE | \ SOUND_MASK_LINE1 | \ SOUND_MASK_LINE2 | \ SOUND_MASK_LINE3 | \ SOUND_MASK_MIC | \ SOUND_MASK_CD | \ SOUND_MASK_RECLEV \ )#define REC_DEVICES ( SOUND_MASK_LINE2 |\ SOUND_MASK_LINE |\ SOUND_MASK_LINE1 |\ SOUND_MASK_MIC |\ SOUND_MASK_CD |\ SOUND_MASK_VOLUME \ ) static voidad1816_mixer_reset (ad1816_info * devc){ int i; devc->supported_devices = MIXER_DEVICES; devc->supported_rec_devices = REC_DEVICES; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) if (devc->supported_devices & (1 << i)) ad1816_mixer_set (devc, i, default_mixer_levels[i]); ad1816_set_recmask (devc, SOUND_MASK_MIC);}static intad1816_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg){ ad1816_info *devc = mixer_devs[dev]->devc; int val; DEBUGINFO(printk("ad1816: mixer_ioctl called!\n")); /* Mixer ioctl */ if (((cmd >> 8) & 0xff) == 'M') { /* set ioctl */ if (_SIOC_DIR (cmd) & _SIOC_WRITE) { switch (cmd & 0xff){ case SOUND_MIXER_RECSRC: if (get_user(val, (int *)arg)) return -EFAULT; val=ad1816_set_recmask (devc, val); return put_user(val, (int *)arg); break; default: if (get_user(val, (int *)arg)) return -EFAULT; if ((val=ad1816_mixer_set (devc, cmd & 0xff, val))<0) return val; else return put_user(val, (int *)arg); } } else { /* read ioctl */ switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: val=devc->recmask; return put_user(val, (int *)arg); break; case SOUND_MIXER_DEVMASK: val=devc->supported_devices; return put_user(val, (int *)arg); break; case SOUND_MIXER_STEREODEVS: val=devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); return put_user(val, (int *)arg); break; case SOUND_MIXER_RECMASK: val=devc->supported_rec_devices; return put_user(val, (int *)arg); break; case SOUND_MIXER_CAPS: val=SOUND_CAP_EXCL_INPUT; return put_user(val, (int *)arg); break; default: if ((val=ad1816_mixer_get (devc, cmd & 0xff))<0) return val; else return put_user(val, (int *)arg); } } } else /* not for mixer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -