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

📄 usbmidi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	buf[0] = p1;	buf[1] = p2;	buf[2] = p3;	buf[3] = (p0 & 0xf0) | snd_usbmidi_cin_length[p0 & 0x0f];	urb->transfer_buffer_length += 4;}/* * Converts MIDI commands to USB MIDI packets. */static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port,				      uint8_t b, struct urb* urb){	uint8_t p0 = port->cable;	void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t) =		port->ep->umidi->usb_protocol_ops->output_packet;	if (b >= 0xf8) {		output_packet(urb, p0 | 0x0f, b, 0, 0);	} else if (b >= 0xf0) {		switch (b) {		case 0xf0:			port->data[0] = b;			port->state = STATE_SYSEX_1;			break;		case 0xf1:		case 0xf3:			port->data[0] = b;			port->state = STATE_1PARAM;			break;		case 0xf2:			port->data[0] = b;			port->state = STATE_2PARAM_1;			break;		case 0xf4:		case 0xf5:			port->state = STATE_UNKNOWN;			break;		case 0xf6:			output_packet(urb, p0 | 0x05, 0xf6, 0, 0);			port->state = STATE_UNKNOWN;			break;		case 0xf7:			switch (port->state) {			case STATE_SYSEX_0:				output_packet(urb, p0 | 0x05, 0xf7, 0, 0);				break;			case STATE_SYSEX_1:				output_packet(urb, p0 | 0x06, port->data[0], 0xf7, 0);				break;			case STATE_SYSEX_2:				output_packet(urb, p0 | 0x07, port->data[0], port->data[1], 0xf7);				break;			}			port->state = STATE_UNKNOWN;			break;		}	} else if (b >= 0x80) {		port->data[0] = b;		if (b >= 0xc0 && b <= 0xdf)			port->state = STATE_1PARAM;		else			port->state = STATE_2PARAM_1;	} else { /* b < 0x80 */		switch (port->state) {		case STATE_1PARAM:			if (port->data[0] < 0xf0) {				p0 |= port->data[0] >> 4;			} else {				p0 |= 0x02;				port->state = STATE_UNKNOWN;			}			output_packet(urb, p0, port->data[0], b, 0);			break;		case STATE_2PARAM_1:			port->data[1] = b;			port->state = STATE_2PARAM_2;			break;		case STATE_2PARAM_2:			if (port->data[0] < 0xf0) {				p0 |= port->data[0] >> 4;				port->state = STATE_2PARAM_1;			} else {				p0 |= 0x03;				port->state = STATE_UNKNOWN;			}			output_packet(urb, p0, port->data[0], port->data[1], b);			break;		case STATE_SYSEX_0:			port->data[0] = b;			port->state = STATE_SYSEX_1;			break;		case STATE_SYSEX_1:			port->data[1] = b;			port->state = STATE_SYSEX_2;			break;		case STATE_SYSEX_2:			output_packet(urb, p0 | 0x04, port->data[0], port->data[1], b);			port->state = STATE_SYSEX_0;			break;		}	}}static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep){	struct urb* urb = ep->urb;	int p;	/* FIXME: lower-numbered ports can starve higher-numbered ports */	for (p = 0; p < 0x10; ++p) {		struct usbmidi_out_port* port = &ep->ports[p];		if (!port->active)			continue;		while (urb->transfer_buffer_length + 3 < ep->max_transfer) {			uint8_t b;			if (snd_rawmidi_transmit(port->substream, &b, 1) != 1) {				port->active = 0;				break;			}			snd_usbmidi_transmit_byte(port, b, urb);		}	}}static struct usb_protocol_ops snd_usbmidi_standard_ops = {	.input = snd_usbmidi_standard_input,	.output = snd_usbmidi_standard_output,	.output_packet = snd_usbmidi_output_standard_packet,};static struct usb_protocol_ops snd_usbmidi_midiman_ops = {	.input = snd_usbmidi_midiman_input,	.output = snd_usbmidi_standard_output, 	.output_packet = snd_usbmidi_output_midiman_packet,};static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = {	.input = snd_usbmidi_maudio_broken_running_status_input,	.output = snd_usbmidi_standard_output, 	.output_packet = snd_usbmidi_output_standard_packet,};static struct usb_protocol_ops snd_usbmidi_cme_ops = {	.input = snd_usbmidi_cme_input,	.output = snd_usbmidi_standard_output,	.output_packet = snd_usbmidi_output_standard_packet,};/* * Novation USB MIDI protocol: number of data bytes is in the first byte * (when receiving) (+1!) or in the second byte (when sending); data begins * at the third byte. */static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint* ep,				       uint8_t* buffer, int buffer_length){	if (buffer_length < 2 || !buffer[0] || buffer_length < buffer[0] + 1)		return;	snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1);}static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep){	uint8_t* transfer_buffer;	int count;	if (!ep->ports[0].active)		return;	transfer_buffer = ep->urb->transfer_buffer;	count = snd_rawmidi_transmit(ep->ports[0].substream,				     &transfer_buffer[2],				     ep->max_transfer - 2);	if (count < 1) {		ep->ports[0].active = 0;		return;	}	transfer_buffer[0] = 0;	transfer_buffer[1] = count;	ep->urb->transfer_buffer_length = 2 + count;}static struct usb_protocol_ops snd_usbmidi_novation_ops = {	.input = snd_usbmidi_novation_input,	.output = snd_usbmidi_novation_output,};/* * "raw" protocol: used by the MOTU FastLane. */static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep,				  uint8_t* buffer, int buffer_length){	snd_usbmidi_input_data(ep, 0, buffer, buffer_length);}static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep){	int count;	if (!ep->ports[0].active)		return;	count = snd_rawmidi_transmit(ep->ports[0].substream,				     ep->urb->transfer_buffer,				     ep->max_transfer);	if (count < 1) {		ep->ports[0].active = 0;		return;	}	ep->urb->transfer_buffer_length = count;}static struct usb_protocol_ops snd_usbmidi_raw_ops = {	.input = snd_usbmidi_raw_input,	.output = snd_usbmidi_raw_output,};/* * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching. */static void snd_usbmidi_emagic_init_out(struct snd_usb_midi_out_endpoint* ep){	static const u8 init_data[] = {		/* initialization magic: "get version" */		0xf0,		0x00, 0x20, 0x31,	/* Emagic */		0x64,			/* Unitor8 */		0x0b,			/* version number request */		0x00,			/* command version */		0x00,			/* EEPROM, box 0 */		0xf7	};	send_bulk_static_data(ep, init_data, sizeof(init_data));	/* while we're at it, pour on more magic */	send_bulk_static_data(ep, init_data, sizeof(init_data));}static void snd_usbmidi_emagic_finish_out(struct snd_usb_midi_out_endpoint* ep){	static const u8 finish_data[] = {		/* switch to patch mode with last preset */		0xf0,		0x00, 0x20, 0x31,	/* Emagic */		0x64,			/* Unitor8 */		0x10,			/* patch switch command */		0x00,			/* command version */		0x7f,			/* to all boxes */		0x40,			/* last preset in EEPROM */		0xf7	};	send_bulk_static_data(ep, finish_data, sizeof(finish_data));}static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint* ep,				     uint8_t* buffer, int buffer_length){	int i;	/* FF indicates end of valid data */	for (i = 0; i < buffer_length; ++i)		if (buffer[i] == 0xff) {			buffer_length = i;			break;		}	/* handle F5 at end of last buffer */	if (ep->seen_f5)		goto switch_port;	while (buffer_length > 0) {		/* determine size of data until next F5 */		for (i = 0; i < buffer_length; ++i)			if (buffer[i] == 0xf5)				break;		snd_usbmidi_input_data(ep, ep->current_port, buffer, i);		buffer += i;		buffer_length -= i;		if (buffer_length <= 0)			break;		/* assert(buffer[0] == 0xf5); */		ep->seen_f5 = 1;		++buffer;		--buffer_length;	switch_port:		if (buffer_length <= 0)			break;		if (buffer[0] < 0x80) {			ep->current_port = (buffer[0] - 1) & 15;			++buffer;			--buffer_length;		}		ep->seen_f5 = 0;	}}static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep){	int port0 = ep->current_port;	uint8_t* buf = ep->urb->transfer_buffer;	int buf_free = ep->max_transfer;	int length, i;	for (i = 0; i < 0x10; ++i) {		/* round-robin, starting at the last current port */		int portnum = (port0 + i) & 15;		struct usbmidi_out_port* port = &ep->ports[portnum];		if (!port->active)			continue;		if (snd_rawmidi_transmit_peek(port->substream, buf, 1) != 1) {			port->active = 0;			continue;		}		if (portnum != ep->current_port) {			if (buf_free < 2)				break;			ep->current_port = portnum;			buf[0] = 0xf5;			buf[1] = (portnum + 1) & 15;			buf += 2;			buf_free -= 2;		}		if (buf_free < 1)			break;		length = snd_rawmidi_transmit(port->substream, buf, buf_free);		if (length > 0) {			buf += length;			buf_free -= length;			if (buf_free < 1)				break;		}	}	if (buf_free < ep->max_transfer && buf_free > 0) {		*buf = 0xff;		--buf_free;	}	ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;}static struct usb_protocol_ops snd_usbmidi_emagic_ops = {	.input = snd_usbmidi_emagic_input,	.output = snd_usbmidi_emagic_output,	.init_out_endpoint = snd_usbmidi_emagic_init_out,	.finish_out_endpoint = snd_usbmidi_emagic_finish_out,};static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream){	struct snd_usb_midi* umidi = substream->rmidi->private_data;	struct usbmidi_out_port* port = NULL;	int i, j;	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)		if (umidi->endpoints[i].out)			for (j = 0; j < 0x10; ++j)				if (umidi->endpoints[i].out->ports[j].substream == substream) {					port = &umidi->endpoints[i].out->ports[j];					break;				}	if (!port) {		snd_BUG();		return -ENXIO;	}	substream->runtime->private_data = port;	port->state = STATE_UNKNOWN;	return 0;}static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream){	return 0;}static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up){	struct usbmidi_out_port* port = (struct usbmidi_out_port*)substream->runtime->private_data;	port->active = up;	if (up) {		if (port->ep->umidi->chip->shutdown) {			/* gobble up remaining bytes to prevent wait in			 * snd_rawmidi_drain_output */			while (!snd_rawmidi_transmit_empty(substream))				snd_rawmidi_transmit_ack(substream, 1);			return;		}		tasklet_hi_schedule(&port->ep->tasklet);	}}static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream){	return 0;}static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream){	return 0;}static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up){	struct snd_usb_midi* umidi = substream->rmidi->private_data;	if (up)		set_bit(substream->number, &umidi->input_triggered);	else		clear_bit(substream->number, &umidi->input_triggered);}static struct snd_rawmidi_ops snd_usbmidi_output_ops = {	.open = snd_usbmidi_output_open,	.close = snd_usbmidi_output_close,	.trigger = snd_usbmidi_output_trigger,};static struct snd_rawmidi_ops snd_usbmidi_input_ops = {	.open = snd_usbmidi_input_open,	.close = snd_usbmidi_input_close,	.trigger = snd_usbmidi_input_trigger};/* * Frees an input endpoint. * May be called when ep hasn't been initialized completely. */static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep){	if (ep->urb) {		usb_buffer_free(ep->umidi->chip->dev,				ep->urb->transfer_buffer_length,				ep->urb->transfer_buffer,				ep->urb->transfer_dma);		usb_free_urb(ep->urb);	}	kfree(ep);}

⌨️ 快捷键说明

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