⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbmixer.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);	if (! kctl) {		snd_printk(KERN_ERR "cannot malloc kcontrol\n");		kfree(namelist);		kfree(cval);		return -ENOMEM;	}	kctl->private_value = (unsigned long)namelist;	kctl->private_free = usb_mixer_selector_elem_free;	nameid = desc[desc[0] - 1];	len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name));	if (len)		;	else if (nameid)		snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));	else {		len = get_term_name(state, &state->oterm,				    kctl->id.name, sizeof(kctl->id.name), 0);		if (! len)			strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));		if ((state->oterm.type & 0xff00) == 0x0100)			strlcat(kctl->id.name, " Capture Source", sizeof(kctl->id.name));		else			strlcat(kctl->id.name, " Playback Source", sizeof(kctl->id.name));	}	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",		    cval->id, kctl->id.name, num_ins);	if ((err = add_control_to_empty(state, kctl)) < 0)		return err;	return 0;}/* * parse an audio unit recursively */static int parse_audio_unit(struct mixer_build *state, int unitid){	unsigned char *p1;	if (test_and_set_bit(unitid, state->unitbitmap))		return 0; /* the unit already visited */	p1 = find_audio_control_unit(state, unitid);	if (!p1) {		snd_printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);		return -EINVAL;	}	switch (p1[2]) {	case INPUT_TERMINAL:		return 0; /* NOP */	case MIXER_UNIT:		return parse_audio_mixer_unit(state, unitid, p1);	case SELECTOR_UNIT:		return parse_audio_selector_unit(state, unitid, p1);	case FEATURE_UNIT:		return parse_audio_feature_unit(state, unitid, p1);	case PROCESSING_UNIT:		return parse_audio_processing_unit(state, unitid, p1);	case EXTENSION_UNIT:		return parse_audio_extension_unit(state, unitid, p1);	default:		snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);		return -EINVAL;	}}static void snd_usb_mixer_free(struct usb_mixer_interface *mixer){	kfree(mixer->id_elems);	if (mixer->urb) {		kfree(mixer->urb->transfer_buffer);		usb_free_urb(mixer->urb);	}	usb_free_urb(mixer->rc_urb);	kfree(mixer->rc_setup_packet);	kfree(mixer);}static int snd_usb_mixer_dev_free(struct snd_device *device){	struct usb_mixer_interface *mixer = device->device_data;	snd_usb_mixer_free(mixer);	return 0;}/* * create mixer controls * * walk through all OUTPUT_TERMINAL descriptors to search for mixers */static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer){	unsigned char *desc;	struct mixer_build state;	int err;	const struct usbmix_ctl_map *map;	struct usb_host_interface *hostif;	hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];	memset(&state, 0, sizeof(state));	state.chip = mixer->chip;	state.mixer = mixer;	state.buffer = hostif->extra;	state.buflen = hostif->extralen;	/* check the mapping table */	for (map = usbmix_ctl_maps; map->id; map++) {		if (map->id == state.chip->usb_id) {			state.map = map->map;			state.selector_map = map->selector_map;			mixer->ignore_ctl_error = map->ignore_ctl_error;			break;		}	}	desc = NULL;	while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) {		if (desc[0] < 9)			continue; /* invalid descriptor? */		set_bit(desc[3], state.unitbitmap);  /* mark terminal ID as visited */		state.oterm.id = desc[3];		state.oterm.type = combine_word(&desc[4]);		state.oterm.name = desc[8];		err = parse_audio_unit(&state, desc[7]);		if (err < 0)			return err;	}	return 0;}static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer,				    int unitid){	struct usb_mixer_elem_info *info;	for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)		snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,			       info->elem_id);}static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,					int unitid){	if (!mixer->rc_cfg)		return;	/* unit ids specific to Extigy/Audigy 2 NX: */	switch (unitid) {	case 0: /* remote control */		mixer->rc_urb->dev = mixer->chip->dev;		usb_submit_urb(mixer->rc_urb, GFP_ATOMIC);		break;	case 4: /* digital in jack */	case 7: /* line in jacks */	case 19: /* speaker out jacks */	case 20: /* headphones out jack */		break;	default:		snd_printd(KERN_DEBUG "memory change in unknown unit %d\n", unitid);		break;	}}static void snd_usb_mixer_status_complete(struct urb *urb){	struct usb_mixer_interface *mixer = urb->context;	if (urb->status == 0) {		u8 *buf = urb->transfer_buffer;		int i;		for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) {			snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",				   buf[0], buf[1]);			/* ignore any notifications not from the control interface */			if ((buf[0] & 0x0f) != 0)				continue;			if (!(buf[0] & 0x40))				snd_usb_mixer_notify_id(mixer, buf[1]);			else				snd_usb_mixer_memory_change(mixer, buf[1]);		}	}	if (urb->status != -ENOENT && urb->status != -ECONNRESET) {		urb->dev = mixer->chip->dev;		usb_submit_urb(urb, GFP_ATOMIC);	}}/* create the handler for the optional status interrupt endpoint */static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer){	struct usb_host_interface *hostif;	struct usb_endpoint_descriptor *ep;	void *transfer_buffer;	int buffer_length;	unsigned int epnum;	hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0];	/* we need one interrupt input endpoint */	if (get_iface_desc(hostif)->bNumEndpoints < 1)		return 0;	ep = get_endpoint(hostif, 0);	if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ||	    (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)		return 0;	epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;	buffer_length = le16_to_cpu(ep->wMaxPacketSize);	transfer_buffer = kmalloc(buffer_length, GFP_KERNEL);	if (!transfer_buffer)		return -ENOMEM;	mixer->urb = usb_alloc_urb(0, GFP_KERNEL);	if (!mixer->urb) {		kfree(transfer_buffer);		return -ENOMEM;	}	usb_fill_int_urb(mixer->urb, mixer->chip->dev,			 usb_rcvintpipe(mixer->chip->dev, epnum),			 transfer_buffer, buffer_length,			 snd_usb_mixer_status_complete, mixer, ep->bInterval);	usb_submit_urb(mixer->urb, GFP_KERNEL);	return 0;}static void snd_usb_soundblaster_remote_complete(struct urb *urb){	struct usb_mixer_interface *mixer = urb->context;	const struct rc_config *rc = mixer->rc_cfg;	u32 code;	if (urb->status < 0 || urb->actual_length < rc->packet_length)		return;	code = mixer->rc_buffer[rc->offset];	if (rc->length == 2)		code |= mixer->rc_buffer[rc->offset + 1] << 8;	/* the Mute button actually changes the mixer control */	if (code == rc->mute_code)		snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id);	mixer->rc_code = code;	wmb();	wake_up(&mixer->rc_waitq);}static int snd_usb_sbrc_hwdep_open(struct snd_hwdep *hw, struct file *file){	struct usb_mixer_interface *mixer = hw->private_data;	if (test_and_set_bit(0, &mixer->rc_hwdep_open))		return -EBUSY;	return 0;}static int snd_usb_sbrc_hwdep_release(struct snd_hwdep *hw, struct file *file){	struct usb_mixer_interface *mixer = hw->private_data;	clear_bit(0, &mixer->rc_hwdep_open);	smp_mb__after_clear_bit();	return 0;}static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf,				     long count, loff_t *offset){	struct usb_mixer_interface *mixer = hw->private_data;	int err;	u32 rc_code;	if (count != 1 && count != 4)		return -EINVAL;	err = wait_event_interruptible(mixer->rc_waitq,				       (rc_code = xchg(&mixer->rc_code, 0)) != 0);	if (err == 0) {		if (count == 1)			err = put_user(rc_code, buf);		else			err = put_user(rc_code, (u32 __user *)buf);	}	return err < 0 ? err : count;}static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *file,					    poll_table *wait){	struct usb_mixer_interface *mixer = hw->private_data;	poll_wait(file, &mixer->rc_waitq, wait);	return mixer->rc_code ? POLLIN | POLLRDNORM : 0;}static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer){	struct snd_hwdep *hwdep;	int err, len, i;	for (i = 0; i < ARRAY_SIZE(rc_configs); ++i)		if (rc_configs[i].usb_id == mixer->chip->usb_id)			break;	if (i >= ARRAY_SIZE(rc_configs))		return 0;	mixer->rc_cfg = &rc_configs[i];	len = mixer->rc_cfg->packet_length;		init_waitqueue_head(&mixer->rc_waitq);	err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep);	if (err < 0)		return err;	snprintf(hwdep->name, sizeof(hwdep->name),		 "%s remote control", mixer->chip->card->shortname);	hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;	hwdep->private_data = mixer;	hwdep->ops.read = snd_usb_sbrc_hwdep_read;	hwdep->ops.open = snd_usb_sbrc_hwdep_open;	hwdep->ops.release = snd_usb_sbrc_hwdep_release;	hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;	mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!mixer->rc_urb)		return -ENOMEM;	mixer->rc_setup_packet = kmalloc(sizeof(*mixer->rc_setup_packet), GFP_KERNEL);	if (!mixer->rc_setup_packet) {		usb_free_urb(mixer->rc_urb);		mixer->rc_urb = NULL;		return -ENOMEM;	}	mixer->rc_setup_packet->bRequestType =		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;	mixer->rc_setup_packet->bRequest = GET_MEM;	mixer->rc_setup_packet->wValue = cpu_to_le16(0);	mixer->rc_setup_packet->wIndex = cpu_to_le16(0);	mixer->rc_setup_packet->wLength = cpu_to_le16(len);	usb_fill_control_urb(mixer->rc_urb, mixer->chip->dev,			     usb_rcvctrlpipe(mixer->chip->dev, 0),			     (u8*)mixer->rc_setup_packet, mixer->rc_buffer, len,			     snd_usb_soundblaster_remote_complete, mixer);	return 0;}#define snd_audigy2nx_led_info		snd_ctl_boolean_mono_infostatic int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index];	return 0;}static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){	struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);	int index = kcontrol->private_value;	int value = ucontrol->value.integer.value[0];	int err, changed;	if (value > 1)		return -EINVAL;	changed = value != mixer->audigy2nx_leds[index];	err = snd_usb_ctl_msg(mixer->chip->dev,			      usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,			      value, index + 2, NULL, 0, 100);	if (err < 0)		return err;	mixer->audigy2nx_leds[index] = value;	return changed;}static struct snd_kcontrol_new snd_audigy2nx_controls[] = {	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "CMSS LED Switch",		.info = snd_audigy2nx_led_info,		.get = snd_audigy2nx_led_get,		.put = snd_audigy2nx_led_put,		.private_value = 0,	},	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "Power LED Switch",		.info = snd_audigy2nx_led_info,		.get = snd_audigy2nx_led_get,		.put = snd_audigy2nx_led_put,		.private_value = 1,	},	{		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,		.name = "Dolby Digital LED Switch",		.info = snd_audigy2nx_led_info,		.get = snd_audigy2nx_led_get,		.put = snd_audigy2nx_led_put,		.private_value = 2,	},};static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer){	int i, err;	for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {		err = snd_ctl_add(mixer->chip->card,				  snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));		if (err < 0)			return err;	}	mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */	return 0;}static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,				    struct snd_info_buffer *buffer){	static const struct {		int unitid;		const char *name;	} jacks[] = {		{4,  "dig in "},		{7,  "line in"},		{19, "spk out"},		{20, "hph out"},	};	struct usb_mixer_interface *mixer = entry->private_data;	int i, err;	u8 buf[3];	snd_iprintf(buffer, "%s jacks\n\n", mixer->chip->card->shortname);	for (i = 0; i < ARRAY_SIZE(jacks); ++i) {		snd_iprintf(buffer, "%s: ", jacks[i].name);		err = snd_usb_ctl_msg(mixer->chip->dev,				      usb_rcvctrlpipe(mixer->chip->dev, 0),				      GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |				      USB_RECIP_INTERFACE, 0,				      jacks[i].unitid << 8, buf, 3, 100);		if (err == 3 && buf[0] == 3)			snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);		else			snd_iprintf(buffer, "?\n");	}}int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif){	static struct snd_device_ops dev_ops = {		.dev_free = snd_usb_mixer_dev_free	};	struct usb_mixer_interface *mixer;	int err;	strcpy(chip->card->mixername, "USB Mixer");	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);	if (!mixer)		return -ENOMEM;	mixer->chip = chip;	mixer->ctrlif = ctrlif;#ifdef IGNORE_CTL_ERROR	mixer->ignore_ctl_error = 1;#endif	mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL);	if (!mixer->id_elems) {		kfree(mixer);		return -ENOMEM;	}	if ((err = snd_usb_mixer_controls(mixer)) < 0 ||	    (err = snd_usb_mixer_status_create(mixer)) < 0)		goto _error;	if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0)		goto _error;	if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020)) {		struct snd_info_entry *entry;		if ((err = snd_audigy2nx_controls_create(mixer)) < 0)			goto _error;		if (!snd_card_proc_new(chip->card, "audigy2nx", &entry))			snd_info_set_text_ops(entry, mixer,					      snd_audigy2nx_proc_read);	}	err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);	if (err < 0)		goto _error;	list_add(&mixer->list, &chip->mixer_list);	return 0;_error:	snd_usb_mixer_free(mixer);	return err;}void snd_usb_mixer_disconnect(struct list_head *p){	struct usb_mixer_interface *mixer;		mixer = list_entry(p, struct usb_mixer_interface, list);	usb_kill_urb(mixer->urb);	usb_kill_urb(mixer->rc_urb);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -