📄 mixer_oss.c
字号:
static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn){ struct slot *p = (struct slot *)chn->private_data; if (p) { if (p->allocated && p->assigned) { kfree(p->assigned->name); kfree(p->assigned); } kfree(p); }}static void mixer_slot_clear(snd_mixer_oss_slot_t *rslot){ int idx = rslot->number; /* remember this */ if (rslot->private_free) rslot->private_free(rslot); memset(rslot, 0, sizeof(*rslot)); rslot->number = idx;}/* * build an OSS mixer element. * ptr_allocated means the entry is dynamically allocated (change via proc file). * when replace_old = 1, the old entry is replaced with the new one. */static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old){ struct slot slot; struct slot *pslot; snd_kcontrol_t *kctl; snd_mixer_oss_slot_t *rslot; char str[64]; /* check if already assigned */ if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) return 0; memset(&slot, 0, sizeof(slot)); memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, SNDRV_MIXER_OSS_ITEM_GLOBAL)) return 0; sprintf(str, "%s Switch", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_GSWITCH)) return 0; sprintf(str, "%s Route", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_GROUTE)) return 0; sprintf(str, "%s Volume", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_GVOLUME)) return 0; sprintf(str, "%s Playback Switch", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_PSWITCH)) return 0; sprintf(str, "%s Playback Route", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_PROUTE)) return 0; sprintf(str, "%s Playback Volume", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_PVOLUME)) return 0; sprintf(str, "%s Capture Switch", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_CSWITCH)) return 0; sprintf(str, "%s Capture Route", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_CROUTE)) return 0; sprintf(str, "%s Capture Volume", ptr->name); if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_CVOLUME)) return 0; down_read(&mixer->card->controls_rwsem); if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { snd_ctl_elem_info_t *uinfo; uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); if (! uinfo) { up_read(&mixer->card->controls_rwsem); return -ENOMEM; } memset(uinfo, 0, sizeof(*uinfo)); if (kctl->info(kctl, uinfo)) { up_read(&mixer->card->controls_rwsem); return 0; } strcpy(str, ptr->name); if (!strcmp(str, "Master")) strcpy(str, "Mix"); if (!strcmp(str, "Master Mono")) strcpy(str, "Mix Mono"); slot.capture_item = 0; if (!strcmp(uinfo->value.enumerated.name, str)) { slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; } else { for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { uinfo->value.enumerated.item = slot.capture_item; if (kctl->info(kctl, uinfo)) { up_read(&mixer->card->controls_rwsem); return 0; } if (!strcmp(uinfo->value.enumerated.name, str)) { slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; break; } } } kfree(uinfo); } up_read(&mixer->card->controls_rwsem); if (slot.present != 0) { pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL); if (! pslot) return -ENOMEM; *pslot = slot; pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; pslot->assigned = ptr; pslot->allocated = ptr_allocated; rslot = &mixer->slots[ptr->oss_id]; mixer_slot_clear(rslot); rslot->stereo = slot.channels > 1 ? 1 : 0; rslot->get_volume = snd_mixer_oss_get_volume1; rslot->put_volume = snd_mixer_oss_put_volume1; /* note: ES18xx have both Capture Source and XX Capture Volume !!! */ if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) { rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw; rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw; } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) { rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route; rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route; } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) { mixer->mask_recsrc |= 1 << ptr->oss_id; } rslot->private_data = pslot; rslot->private_free = snd_mixer_oss_slot_free; return 1; } return 0;}/* */#define MIXER_VOL(name) [SOUND_MIXER_##name] = #namestatic char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = { MIXER_VOL(VOLUME), MIXER_VOL(BASS), MIXER_VOL(TREBLE), MIXER_VOL(SYNTH), MIXER_VOL(PCM), MIXER_VOL(SPEAKER), MIXER_VOL(LINE), MIXER_VOL(MIC), MIXER_VOL(CD), MIXER_VOL(IMIX), MIXER_VOL(ALTPCM), MIXER_VOL(RECLEV), MIXER_VOL(IGAIN), MIXER_VOL(OGAIN), MIXER_VOL(LINE1), MIXER_VOL(LINE2), MIXER_VOL(LINE3), MIXER_VOL(DIGITAL1), MIXER_VOL(DIGITAL2), MIXER_VOL(DIGITAL3), MIXER_VOL(PHONEIN), MIXER_VOL(PHONEOUT), MIXER_VOL(VIDEO), MIXER_VOL(RADIO), MIXER_VOL(MONITOR),}; /* * /proc interface */static void snd_mixer_oss_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ snd_mixer_oss_t *mixer = entry->private_data; int i; down(&mixer->reg_mutex); for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { struct slot *p; if (! oss_mixer_names[i]) continue; p = (struct slot *)mixer->slots[i].private_data; snd_iprintf(buffer, "%s ", oss_mixer_names[i]); if (p && p->assigned) snd_iprintf(buffer, "\"%s\" %d\n", p->assigned->name, p->assigned->index); else snd_iprintf(buffer, "\"\" 0\n"); } up(&mixer->reg_mutex);}static void snd_mixer_oss_proc_write(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ snd_mixer_oss_t *mixer = entry->private_data; char line[128], str[32], idxstr[16], *cptr; int ch, idx; struct snd_mixer_oss_assign_table *tbl; struct slot *slot; while (!snd_info_get_line(buffer, line, sizeof(line))) { cptr = snd_info_get_str(str, line, sizeof(str)); for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++) if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0) break; if (ch >= SNDRV_OSS_MAX_MIXERS) { snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str); continue; } cptr = snd_info_get_str(str, cptr, sizeof(str)); if (! *str) { /* remove the entry */ down(&mixer->reg_mutex); mixer_slot_clear(&mixer->slots[ch]); up(&mixer->reg_mutex); continue; } snd_info_get_str(idxstr, cptr, sizeof(idxstr)); idx = simple_strtoul(idxstr, NULL, 10); if (idx >= 0x4000) { /* too big */ snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx); continue; } down(&mixer->reg_mutex); slot = (struct slot *)mixer->slots[ch].private_data; if (slot && slot->assigned && slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) /* not changed */ goto __unlock; tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); if (! tbl) { snd_printk(KERN_ERR "mixer_oss: no memory\n"); goto __unlock; } tbl->oss_id = ch; tbl->name = kstrdup(str, GFP_KERNEL); if (! tbl->name) { kfree(tbl); goto __unlock; } tbl->index = idx; if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { kfree(tbl->name); kfree(tbl); } __unlock: up(&mixer->reg_mutex); }}static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer){ snd_info_entry_t *entry; entry = snd_info_create_card_entry(mixer->card, "oss_mixer", mixer->card->proc_root); if (! entry) return; entry->content = SNDRV_INFO_CONTENT_TEXT; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; entry->c.text.read_size = 8192; entry->c.text.read = snd_mixer_oss_proc_read; entry->c.text.write_size = 8192; entry->c.text.write = snd_mixer_oss_proc_write; entry->private_data = mixer; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } mixer->proc_entry = entry;}static void snd_mixer_oss_proc_done(snd_mixer_oss_t *mixer){ if (mixer->proc_entry) { snd_info_unregister(mixer->proc_entry); mixer->proc_entry = NULL; }}static void snd_mixer_oss_build(snd_mixer_oss_t *mixer){ static struct snd_mixer_oss_assign_table table[] = { { SOUND_MIXER_VOLUME, "Master", 0 }, { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, { SOUND_MIXER_SYNTH, "Synth", 0 }, { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ { SOUND_MIXER_PCM, "PCM", 0 }, { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, { SOUND_MIXER_LINE, "Line", 0 }, { SOUND_MIXER_MIC, "Mic", 0 }, { SOUND_MIXER_CD, "CD", 0 }, { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, { SOUND_MIXER_ALTPCM, "PCM", 1 }, { SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */ { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, { SOUND_MIXER_IGAIN, "Capture", 0 }, { SOUND_MIXER_OGAIN, "Playback", 0 }, { SOUND_MIXER_LINE1, "Aux", 0 }, { SOUND_MIXER_LINE2, "Aux", 1 }, { SOUND_MIXER_LINE3, "Aux", 2 }, { SOUND_MIXER_DIGITAL1, "Digital", 0 }, { SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */ { SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */ { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */ { SOUND_MIXER_DIGITAL2, "Digital", 1 }, { SOUND_MIXER_DIGITAL3, "Digital", 2 }, { SOUND_MIXER_PHONEIN, "Phone", 0 }, { SOUND_MIXER_PHONEOUT, "Master Mono", 0 }, { SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */ { SOUND_MIXER_VIDEO, "Video", 0 }, { SOUND_MIXER_RADIO, "Radio", 0 }, { SOUND_MIXER_MONITOR, "Monitor", 0 } }; unsigned int idx; for (idx = 0; idx < ARRAY_SIZE(table); idx++) snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); if (mixer->mask_recsrc) { mixer->get_recsrc = snd_mixer_oss_get_recsrc2; mixer->put_recsrc = snd_mixer_oss_put_recsrc2; }}/* * */static int snd_mixer_oss_free1(void *private){ snd_mixer_oss_t *mixer = private; snd_card_t * card; int idx; snd_assert(mixer != NULL, return -ENXIO); card = mixer->card; snd_assert(mixer == card->mixer_oss, return -ENXIO); card->mixer_oss = NULL; for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) { snd_mixer_oss_slot_t *chn = &mixer->slots[idx]; if (chn->private_free) chn->private_free(chn); } kfree(mixer); return 0;}static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd){ snd_mixer_oss_t *mixer; if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) { char name[128]; int idx, err; mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL); if (mixer == NULL) return -ENOMEM; init_MUTEX(&mixer->reg_mutex); sprintf(name, "mixer%i%i", card->number, 0); if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, card, 0, &snd_mixer_oss_reg, name)) < 0) { snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n", card->number, 0); kfree(mixer); return err; } mixer->oss_dev_alloc = 1; mixer->card = card; if (*card->mixername) strlcpy(mixer->name, card->mixername, sizeof(mixer->name)); else strlcpy(mixer->name, name, sizeof(mixer->name));#ifdef SNDRV_OSS_INFO_DEV_MIXERS snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS, card->number, mixer->name);#endif for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) mixer->slots[idx].number = idx; card->mixer_oss = mixer; snd_mixer_oss_build(mixer); snd_mixer_oss_proc_init(mixer); } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) { mixer = card->mixer_oss; if (mixer == NULL || !mixer->oss_dev_alloc) return 0; snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); mixer->oss_dev_alloc = 0; } else { /* free */ mixer = card->mixer_oss; if (mixer == NULL) return 0;#ifdef SNDRV_OSS_INFO_DEV_MIXERS snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);#endif if (mixer->oss_dev_alloc) snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0); snd_mixer_oss_proc_done(mixer); return snd_mixer_oss_free1(mixer); } return 0;}static int __init alsa_mixer_oss_init(void){ int idx; snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler; for (idx = 0; idx < SNDRV_CARDS; idx++) { if (snd_cards[idx]) snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER); } return 0;}static void __exit alsa_mixer_oss_exit(void){ int idx; snd_mixer_oss_notify_callback = NULL; for (idx = 0; idx < SNDRV_CARDS; idx++) { if (snd_cards[idx]) snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE); }}module_init(alsa_mixer_oss_init)module_exit(alsa_mixer_oss_exit)EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -