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

📄 usbmidi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		    (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)			continue;		ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra;		if (hostep->extralen < 4 ||		    ms_ep->bLength < 4 ||		    ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||		    ms_ep->bDescriptorSubtype != MS_GENERAL)			continue;		if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {			if (endpoints[epidx].out_ep) {				if (++epidx >= MIDI_MAX_ENDPOINTS) {					snd_printk(KERN_WARNING "too many endpoints\n");					break;				}			}			endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;			if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)				endpoints[epidx].out_interval = ep->bInterval;			else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)				/*				 * Low speed bulk transfers don't exist, so				 * force interrupt transfers for devices like				 * ESI MIDI Mate that try to use them anyway.				 */				endpoints[epidx].out_interval = 1;			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);		} else {			if (endpoints[epidx].in_ep) {				if (++epidx >= MIDI_MAX_ENDPOINTS) {					snd_printk(KERN_WARNING "too many endpoints\n");					break;				}			}			endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;			if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)				endpoints[epidx].in_interval = ep->bInterval;			else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)				endpoints[epidx].in_interval = 1;			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;			snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",				    ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);		}	}	return 0;}/* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. */static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi){	struct usb_interface* intf;	struct usb_host_interface *hostif;	struct usb_interface_descriptor* intfd;	intf = umidi->iface;	if (!intf || intf->num_altsetting != 2)		return;	hostif = &intf->altsetting[1];	intfd = get_iface_desc(hostif);	if (intfd->bNumEndpoints != 2 ||	    (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)		return;	snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n",		    intfd->bAlternateSetting);	usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,			  intfd->bAlternateSetting);}/* * Try to find any usable endpoints in the interface. */static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi,					struct snd_usb_midi_endpoint_info* endpoint,					int max_endpoints){	struct usb_interface* intf;	struct usb_host_interface *hostif;	struct usb_interface_descriptor* intfd;	struct usb_endpoint_descriptor* epd;	int i, out_eps = 0, in_eps = 0;	if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582)		snd_usbmidi_switch_roland_altsetting(umidi);	if (endpoint[0].out_ep || endpoint[0].in_ep)		return 0;		intf = umidi->iface;	if (!intf || intf->num_altsetting < 1)		return -ENOENT;	hostif = intf->cur_altsetting;	intfd = get_iface_desc(hostif);	for (i = 0; i < intfd->bNumEndpoints; ++i) {		epd = get_endpoint(hostif, i);		if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK &&		    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)			continue;		if (out_eps < max_endpoints &&		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {			endpoint[out_eps].out_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;			if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)				endpoint[out_eps].out_interval = epd->bInterval;			++out_eps;		}		if (in_eps < max_endpoints &&		    (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {			endpoint[in_eps].in_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;			if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)				endpoint[in_eps].in_interval = epd->bInterval;			++in_eps;		}	}	return (out_eps || in_eps) ? 0 : -ENOENT;}/* * Detects the endpoints for one-port-per-endpoint protocols. */static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi* umidi,						 struct snd_usb_midi_endpoint_info* endpoints){	int err, i;		err = snd_usbmidi_detect_endpoints(umidi, endpoints, MIDI_MAX_ENDPOINTS);	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {		if (endpoints[i].out_ep)			endpoints[i].out_cables = 0x0001;		if (endpoints[i].in_ep)			endpoints[i].in_cables = 0x0001;	}	return err;}/* * Detects the endpoints and ports of Yamaha devices. */static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,				     struct snd_usb_midi_endpoint_info* endpoint){	struct usb_interface* intf;	struct usb_host_interface *hostif;	struct usb_interface_descriptor* intfd;	uint8_t* cs_desc;	intf = umidi->iface;	if (!intf)		return -ENOENT;	hostif = intf->altsetting;	intfd = get_iface_desc(hostif);	if (intfd->bNumEndpoints < 1)		return -ENOENT;	/*	 * For each port there is one MIDI_IN/OUT_JACK descriptor, not	 * necessarily with any useful contents.  So simply count 'em.	 */	for (cs_desc = hostif->extra;	     cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;	     cs_desc += cs_desc[0]) {		if (cs_desc[1] == USB_DT_CS_INTERFACE) {			if (cs_desc[2] == MIDI_IN_JACK)				endpoint->in_cables = (endpoint->in_cables << 1) | 1;			else if (cs_desc[2] == MIDI_OUT_JACK)				endpoint->out_cables = (endpoint->out_cables << 1) | 1;		}	}	if (!endpoint->in_cables && !endpoint->out_cables)		return -ENOENT;	return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);}/* * Creates the endpoints and their ports for Midiman devices. */static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,						struct snd_usb_midi_endpoint_info* endpoint){	struct snd_usb_midi_endpoint_info ep_info;	struct usb_interface* intf;	struct usb_host_interface *hostif;	struct usb_interface_descriptor* intfd;	struct usb_endpoint_descriptor* epd;	int cable, err;	intf = umidi->iface;	if (!intf)		return -ENOENT;	hostif = intf->altsetting;	intfd = get_iface_desc(hostif);	/*	 * The various MidiSport devices have more or less random endpoint	 * numbers, so we have to identify the endpoints by their index in	 * the descriptor array, like the driver for that other OS does.	 *	 * There is one interrupt input endpoint for all input ports, one	 * bulk output endpoint for even-numbered ports, and one for odd-	 * numbered ports.  Both bulk output endpoints have corresponding	 * input bulk endpoints (at indices 1 and 3) which aren't used.	 */	if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) {		snd_printdd(KERN_ERR "not enough endpoints\n");		return -ENOENT;	}	epd = get_endpoint(hostif, 0);	if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ||	    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {		snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n");		return -ENXIO;	}	epd = get_endpoint(hostif, 2);	if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||	    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {		snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");		return -ENXIO;	}	if (endpoint->out_cables > 0x0001) {		epd = get_endpoint(hostif, 4);		if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||		    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {			snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n");			return -ENXIO;		}	}	ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;	ep_info.out_cables = endpoint->out_cables & 0x5555;	err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);	if (err < 0)		return err;	ep_info.in_ep = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;	ep_info.in_interval = get_endpoint(hostif, 0)->bInterval;	ep_info.in_cables = endpoint->in_cables;	err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);	if (err < 0)		return err;	if (endpoint->out_cables > 0x0001) {		ep_info.out_ep = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;		ep_info.out_cables = endpoint->out_cables & 0xaaaa;		err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]);		if (err < 0)			return err;	}	for (cable = 0; cable < 0x10; ++cable) {		if (endpoint->out_cables & (1 << cable))			snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable,						   &umidi->endpoints[cable & 1].out->ports[cable].substream);		if (endpoint->in_cables & (1 << cable))			snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable,						   &umidi->endpoints[0].in->ports[cable].substream);	}	return 0;}static struct snd_rawmidi_global_ops snd_usbmidi_ops = {	.get_port_info = snd_usbmidi_get_port_info,};static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi,				      int out_ports, int in_ports){	struct snd_rawmidi *rmidi;	int err;	err = snd_rawmidi_new(umidi->chip->card, "USB MIDI",			      umidi->chip->next_midi_device++,			      out_ports, in_ports, &rmidi);	if (err < 0)		return err;	strcpy(rmidi->name, umidi->chip->card->shortname);	rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |			    SNDRV_RAWMIDI_INFO_INPUT |			    SNDRV_RAWMIDI_INFO_DUPLEX;	rmidi->ops = &snd_usbmidi_ops;	rmidi->private_data = umidi;	rmidi->private_free = snd_usbmidi_rawmidi_free;	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops);	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input_ops);	umidi->rmidi = rmidi;	return 0;}/* * Temporarily stop input. */void snd_usbmidi_input_stop(struct list_head* p){	struct snd_usb_midi* umidi;	int i;	umidi = list_entry(p, struct snd_usb_midi, list);	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {		struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];		if (ep->in)			usb_kill_urb(ep->in->urb);	}}static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep){	if (ep) {		struct urb* urb = ep->urb;		urb->dev = ep->umidi->chip->dev;		snd_usbmidi_submit_urb(urb, GFP_KERNEL);	}}/* * Resume input after a call to snd_usbmidi_input_stop(). */void snd_usbmidi_input_start(struct list_head* p){	struct snd_usb_midi* umidi;	int i;	umidi = list_entry(p, struct snd_usb_midi, list);	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)		snd_usbmidi_input_start_ep(umidi->endpoints[i].in);}/* * Creates and registers everything needed for a MIDI streaming interface. */int snd_usb_create_midi_interface(struct snd_usb_audio* chip,				  struct usb_interface* iface,				  const struct snd_usb_audio_quirk* quirk){	struct snd_usb_midi* umidi;	struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS];	int out_ports, in_ports;	int i, err;	umidi = kzalloc(sizeof(*umidi), GFP_KERNEL);	if (!umidi)		return -ENOMEM;	umidi->chip = chip;	umidi->iface = iface;	umidi->quirk = quirk;	umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;	init_timer(&umidi->error_timer);	umidi->error_timer.function = snd_usbmidi_error_timer;	umidi->error_timer.data = (unsigned long)umidi;	/* detect the endpoint(s) to use */	memset(endpoints, 0, sizeof(endpoints));	switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) {	case QUIRK_MIDI_STANDARD_INTERFACE:		err = snd_usbmidi_get_ms_info(umidi, endpoints);		if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */			umidi->usb_protocol_ops =				&snd_usbmidi_maudio_broken_running_status_ops;		break;	case QUIRK_MIDI_FIXED_ENDPOINT:		memcpy(&endpoints[0], quirk->data,		       sizeof(struct snd_usb_midi_endpoint_info));		err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);		break;	case QUIRK_MIDI_YAMAHA:		err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);		break;	case QUIRK_MIDI_MIDIMAN:		umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;		memcpy(&endpoints[0], quirk->data,		       sizeof(struct snd_usb_midi_endpoint_info));		err = 0;		break;	case QUIRK_MIDI_NOVATION:		umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);		break;	case QUIRK_MIDI_RAW:		umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);		break;	case QUIRK_MIDI_EMAGIC:		umidi->usb_protocol_ops = &snd_usbmidi_emagic_ops;		memcpy(&endpoints[0], quirk->data,		       sizeof(struct snd_usb_midi_endpoint_info));		err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);		break;	case QUIRK_MIDI_CME:		umidi->usb_protocol_ops = &snd_usbmidi_cme_ops;		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);		break;	default:		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);		err = -ENXIO;		break;	}	if (err < 0) {		kfree(umidi);		return err;	}	/* create rawmidi device */	out_ports = 0;	in_ports = 0;	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {		out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables);		in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables);	}	err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports);	if (err < 0) {		kfree(umidi);		return err;	}	/* create endpoint/port structures */	if (quirk && quirk->type == QUIRK_MIDI_MIDIMAN)		err = snd_usbmidi_create_endpoints_midiman(umidi, &endpoints[0]);	else		err = snd_usbmidi_create_endpoints(umidi, endpoints);	if (err < 0) {		snd_usbmidi_free(umidi);		return err;	}	list_add(&umidi->list, &umidi->chip->midi_list);	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)		snd_usbmidi_input_start_ep(umidi->endpoints[i].in);	return 0;}EXPORT_SYMBOL(snd_usb_create_midi_interface);EXPORT_SYMBOL(snd_usbmidi_input_stop);EXPORT_SYMBOL(snd_usbmidi_input_start);EXPORT_SYMBOL(snd_usbmidi_disconnect);

⌨️ 快捷键说明

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