📄 ad1848.c
字号:
if (muteregoffs != regoffs) { ad_write(devc, muteregoffs, muteval); devc->saved_regs[muteregoffs] = muteval; }}static int ad1848_mixer_set(ad1848_info * devc, int dev, int value){ int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; int retvol; if (dev > 31) return -EINVAL; if (!(devc->supported_devices & (1 << dev))) return -EINVAL; dev = devc->mixer_reroute[dev]; if (devc->mix_devices[dev][LEFT_CHN].nbits == 0) return -EINVAL; if (left > 100) left = 100; if (right > 100) right = 100; if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */ right = left; retvol = left | (right << 8); /* Scale volumes */ left = mix_cvt[left]; right = mix_cvt[right]; devc->levels[dev] = retvol; /* * Set the left channel */ ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN); /* * Set the right channel */ if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) goto out; ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); out: return retvol;}static void ad1848_mixer_reset(ad1848_info * devc){ int i; char name[32]; devc->mix_devices = &(ad1848_mix_devices[0]); sprintf(name, "%s_%d", devc->chip_name, nr_ad1848_devs); for (i = 0; i < 32; i++) devc->mixer_reroute[i] = i; devc->supported_rec_devices = MODE1_REC_DEVICES; switch (devc->model) { case MD_4231: case MD_4231A: case MD_1845: case MD_1845_SSCAPE: devc->supported_devices = MODE2_MIXER_DEVICES; break; case MD_C930: devc->supported_devices = C930_MIXER_DEVICES; devc->mix_devices = &(c930_mix_devices[0]); break; case MD_IWAVE: devc->supported_devices = MODE3_MIXER_DEVICES; devc->mix_devices = &(iwave_mix_devices[0]); break; case MD_42xB: case MD_4239: devc->mix_devices = &(cs42xb_mix_devices[0]); devc->supported_devices = MODE3_MIXER_DEVICES; break; case MD_4232: case MD_4236: devc->supported_devices = MODE3_MIXER_DEVICES; break; case MD_1848: if (soundpro) { devc->supported_devices = SPRO_MIXER_DEVICES; devc->supported_rec_devices = SPRO_REC_DEVICES; devc->mix_devices = &(spro_mix_devices[0]); break; } default: devc->supported_devices = MODE1_MIXER_DEVICES; } devc->orig_devices = devc->supported_devices; devc->orig_rec_devices = devc->supported_rec_devices; devc->levels = load_mixer_volumes(name, default_mixer_levels, 1); for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if (devc->supported_devices & (1 << i)) ad1848_mixer_set(devc, i, devc->levels[i]); } ad1848_set_recmask(devc, SOUND_MASK_MIC); devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; if (!soundpro) { if (devc->mixer_output_port & AUDIO_SPEAKER) ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ else ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ } else { /* * From the "wouldn't it be nice if the mixer API had (better) * support for custom stuff" category */ /* Enable surround mode and SB16 mixer */ ad_write(devc, 16, 0x60); }}static int ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg){ ad1848_info *devc = mixer_devs[dev]->devc; int val; if (cmd == SOUND_MIXER_PRIVATE1) { if (get_user(val, (int *)arg)) return -EFAULT; if (val != 0xffff) { val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); devc->mixer_output_port = val; val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ devc->mixer_output_port = val; if (val & AUDIO_SPEAKER) ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ else ad_write(devc, 26, ad_read(devc, 26) | 0x40); /* Mute mono out */ } val = devc->mixer_output_port; return put_user(val, (int *)arg); } if (cmd == SOUND_MIXER_PRIVATE2) { if (get_user(val, (int *)arg)) return -EFAULT; return(ad1848_control(AD1848_MIXER_REROUTE, val)); } if (((cmd >> 8) & 0xff) == 'M') { if (_SIOC_DIR(cmd) & _SIOC_WRITE) { switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: if (get_user(val, (int *)arg)) return -EFAULT; val = ad1848_set_recmask(devc, val); break; default: if (get_user(val, (int *)arg)) return -EFAULT; val = ad1848_mixer_set(devc, cmd & 0xff, val); break; } return put_user(val, (int *)arg); } else { switch (cmd & 0xff) { /* * Return parameters */ case SOUND_MIXER_RECSRC: val = devc->recmask; break; case SOUND_MIXER_DEVMASK: val = devc->supported_devices; break; case SOUND_MIXER_STEREODEVS: val = devc->supported_devices; if (devc->model != MD_C930) val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); break; case SOUND_MIXER_RECMASK: val = devc->supported_rec_devices; break; case SOUND_MIXER_CAPS: val=SOUND_CAP_EXCL_INPUT; break; default: val = ad1848_mixer_get(devc, cmd & 0xff); break; } return put_user(val, (int *)arg); } } else return -EINVAL;}static int ad1848_set_speed(int dev, int arg){ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; /* * The sampling speed is encoded in the least significant nibble of I8. The * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other * three bits select the divisor (indirectly): * * The available speeds are in the following table. Keep the speeds in * the increasing order. */ typedef struct { int speed; unsigned char bits; } speed_struct; static speed_struct speed_table[] = { {5510, (0 << 1) | 1}, {5510, (0 << 1) | 1}, {6620, (7 << 1) | 1}, {8000, (0 << 1) | 0}, {9600, (7 << 1) | 0}, {11025, (1 << 1) | 1}, {16000, (1 << 1) | 0}, {18900, (2 << 1) | 1}, {22050, (3 << 1) | 1}, {27420, (2 << 1) | 0}, {32000, (3 << 1) | 0}, {33075, (6 << 1) | 1}, {37800, (4 << 1) | 1}, {44100, (5 << 1) | 1}, {48000, (6 << 1) | 0} }; int i, n, selected = -1; n = sizeof(speed_table) / sizeof(speed_struct); if (arg <= 0) return portc->speed; if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE) /* AD1845 has different timer than others */ { if (arg < 4000) arg = 4000; if (arg > 50000) arg = 50000; portc->speed = arg; portc->speed_bits = speed_table[3].bits; return portc->speed; } if (arg < speed_table[0].speed) selected = 0; if (arg > speed_table[n - 1].speed) selected = n - 1; for (i = 1 /*really */ ; selected == -1 && i < n; i++) { if (speed_table[i].speed == arg) selected = i; else if (speed_table[i].speed > arg) { int diff1, diff2; diff1 = arg - speed_table[i - 1].speed; diff2 = speed_table[i].speed - arg; if (diff1 < diff2) selected = i - 1; else selected = i; } } if (selected == -1) { printk(KERN_WARNING "ad1848: Can't find speed???\n"); selected = 3; } portc->speed = speed_table[selected].speed; portc->speed_bits = speed_table[selected].bits; return portc->speed;}static short ad1848_set_channels(int dev, short arg){ ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; if (arg != 1 && arg != 2) return portc->channels; portc->channels = arg; return arg;}static unsigned int ad1848_set_bits(int dev, unsigned int arg){ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; static struct format_tbl { int format; unsigned char bits; } format2bits[] = { { 0, 0 } , { AFMT_MU_LAW, 1 } , { AFMT_A_LAW, 3 } , { AFMT_IMA_ADPCM, 5 } , { AFMT_U8, 0 } , { AFMT_S16_LE, 2 } , { AFMT_S16_BE, 6 } , { AFMT_S8, 0 } , { AFMT_U16_LE, 0 } , { AFMT_U16_BE, 0 } }; int i, n = sizeof(format2bits) / sizeof(struct format_tbl); if (arg == 0) return portc->audio_format; if (!(arg & ad_format_mask[devc->model])) arg = AFMT_U8; portc->audio_format = arg; for (i = 0; i < n; i++) if (format2bits[i].format == arg) { if ((portc->format_bits = format2bits[i].bits) == 0) return portc->audio_format = AFMT_U8; /* Was not supported */ return arg; } /* Still hanging here. Something must be terribly wrong */ portc->format_bits = 0; return portc->audio_format = AFMT_U8;}static struct audio_driver ad1848_audio_driver ={ owner: THIS_MODULE, open: ad1848_open, close: ad1848_close, output_block: ad1848_output_block, start_input: ad1848_start_input, prepare_for_input: ad1848_prepare_for_input, prepare_for_output: ad1848_prepare_for_output, halt_io: ad1848_halt, halt_input: ad1848_halt_input, halt_output: ad1848_halt_output, trigger: ad1848_trigger, set_speed: ad1848_set_speed, set_bits: ad1848_set_bits, set_channels: ad1848_set_channels};static struct mixer_operations ad1848_mixer_operations ={ owner: THIS_MODULE, id: "SOUNDPORT", name: "AD1848/CS4248/CS4231", ioctl: ad1848_mixer_ioctl};static int ad1848_open(int dev, int mode){ ad1848_info *devc = NULL; ad1848_port_info *portc; unsigned long flags; if (dev < 0 || dev >= num_audiodevs) return -ENXIO; devc = (ad1848_info *) audio_devs[dev]->devc; portc = (ad1848_port_info *) audio_devs[dev]->portc; save_flags(flags); cli(); if (portc->open_mode || (devc->open_mode & mode)) { restore_flags(flags); return -EBUSY; } devc->dual_dma = 0; if (audio_devs[dev]->flags & DMA_DUPLEX) { devc->dual_dma = 1; } devc->intr_active = 0; devc->audio_mode = 0; devc->open_mode |= mode; portc->open_mode = mode; ad1848_trigger(dev, 0); if (mode & OPEN_READ) devc->record_dev = dev; if (mode & OPEN_WRITE) devc->playback_dev = dev; restore_flags(flags);/* * Mute output until the playback really starts. This decreases clicking (hope so). */ ad_mute(devc); return 0;}static void ad1848_close(int dev){ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; DEB(printk("ad1848_close(void)\n")); save_flags(flags); cli(); devc->intr_active = 0; ad1848_halt(dev); devc->audio_mode = 0; devc->open_mode &= ~portc->open_mode; portc->open_mode = 0; ad_unmute(devc); restore_flags(flags);}static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag){ unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; cnt = count; if (portc->audio_format == AFMT_IMA_ADPCM) { cnt /= 4; } else { if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ cnt >>= 1; } if (portc->channels > 1) cnt >>= 1; cnt--; if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && intrflag && cnt == devc->xfer_count) { devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; return; /* * Auto DMA mode on. No need to react */ } save_flags(flags); cli(); ad_write(devc, 15, (unsigned char) (cnt & 0xff)); ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); devc->xfer_count = cnt; devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; restore_flags(flags);}static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -