/* * We can only handle 16 cables on one single endpoint, as cable numbers are * stored in 4-bit fields. And as the interface currently only holds one * single endpoint, this is the maximum number of ports we can allow.
*/ #define MAX_PORTS 16
/* MIDI message states */ enum {
STATE_INITIAL = 0, /* pseudo state */
STATE_1PARAM,
STATE_2PARAM_1,
STATE_2PARAM_2,
STATE_SYSEX_0,
STATE_SYSEX_1,
STATE_SYSEX_2,
STATE_REAL_TIME,
STATE_FINISHED, /* pseudo state */
};
/* * This is a gadget, and the IN/OUT naming is from the host's perspective. * USB -> OUT endpoint -> rawmidi * USB <- IN endpoint <- rawmidi
*/ struct gmidi_in_port { struct snd_rawmidi_substream *substream; int active;
uint8_t cable;
uint8_t state;
uint8_t data[2];
};
unsignedlong out_triggered; struct work_struct work; unsignedint in_ports; unsignedint out_ports; int index; char *id; unsignedint buflen, qlen; /* This fifo is used as a buffer ring for pre-allocated IN usb_requests */
DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);
spinlock_t transmit_lock; unsignedint in_last_port; unsignedchar free_ref;
switch (status) { case 0: /* normal completion */ if (ep == midi->out_ep) { /* We received stuff. req is queued again, below */
f_midi_handle_out_data(ep, req);
} elseif (ep == midi->in_ep) { /* Our transmit completed. See if there's more to go.
* f_midi_transmit eats req, don't queue it again. */
req->length = 0;
queue_work(system_highpri_wq, &midi->work); return;
} break;
/* this endpoint is normally active while we're configured */ case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */
VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length); if (ep == midi->out_ep) {
f_midi_handle_out_data(ep, req); /* We don't need to free IN requests because it's handled
* by the midi->in_req_fifo. */
free_ep_req(ep, req);
} return;
case -EOVERFLOW: /* buffer overrun on read means that * we didn't provide a big enough buffer.
*/ default:
DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length); break; case -EREMOTEIO: /* short read */ break;
}
status = usb_ep_queue(ep, req, GFP_ATOMIC); if (status) {
ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n",
ep->name, req->length, status);
usb_ep_set_halt(ep); /* FIXME recover later ... somehow */
}
}
/* we only set alt for MIDIStreaming interface */ if (intf != midi->ms_id) return 0;
err = f_midi_start_ep(midi, f, midi->in_ep); if (err) return err;
err = f_midi_start_ep(midi, f, midi->out_ep); if (err) return err;
/* pre-allocate write usb requests to use on f_midi_transmit. */ while (kfifo_avail(&midi->in_req_fifo)) { struct usb_request *req =
midi_alloc_ep_req(midi->in_ep, midi->buflen);
if (req == NULL) return -ENOMEM;
req->length = 0;
req->complete = f_midi_complete;
kfifo_put(&midi->in_req_fifo, req);
}
/* allocate a bunch of read buffers and queue them all at once. */ for (i = 0; i < midi->qlen && err == 0; i++) { struct usb_request *req =
midi_alloc_ep_req(midi->out_ep, midi->buflen);
/* * just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case.
*/
usb_ep_disable(midi->in_ep);
usb_ep_disable(midi->out_ep);
/* release IN requests */ while (kfifo_get(&midi->in_req_fifo, &req))
free_ep_req(midi->in_ep, req);
case 0xf0 ... 0xf6: /* System Common Messages */
port->data[0] = port->data[1] = 0;
port->state = STATE_INITIAL; switch (b) { case 0xf0:
port->data[0] = b;
port->data[1] = 0;
next_state = STATE_SYSEX_1; break; case 0xf1: case 0xf3:
port->data[0] = b;
next_state = STATE_1PARAM; break; case 0xf2:
port->data[0] = b;
next_state = STATE_2PARAM_1; break; case 0xf4: case 0xf5:
next_state = STATE_INITIAL; break; case 0xf6:
p[0] |= 0x05;
p[1] = 0xf6;
next_state = STATE_FINISHED; break;
} break;
case 0x80 ... 0xef: /* * Channel Voice Messages, Channel Mode Messages * and Control Change Messages.
*/
port->data[0] = b;
port->data[1] = 0;
port->state = STATE_INITIAL; if (b >= 0xc0 && b <= 0xdf)
next_state = STATE_1PARAM; else
next_state = STATE_2PARAM_1; break;
case 0x00 ... 0x7f: /* Message parameters */ switch (port->state) { case STATE_1PARAM: if (port->data[0] < 0xf0)
p[0] |= port->data[0] >> 4; else
p[0] |= 0x02;
p[1] = port->data[0];
p[2] = b; /* This is to allow Running State Messages */
next_state = STATE_1PARAM; break; case STATE_2PARAM_1:
port->data[1] = b;
next_state = STATE_2PARAM_2; break; case STATE_2PARAM_2: if (port->data[0] < 0xf0)
p[0] |= port->data[0] >> 4; else
p[0] |= 0x03;
p[1] = port->data[0];
p[2] = port->data[1];
p[3] = b; /* This is to allow Running State Messages */
next_state = STATE_2PARAM_1; break; case STATE_SYSEX_0:
port->data[0] = b;
next_state = STATE_SYSEX_1; break; case STATE_SYSEX_1:
port->data[1] = b;
next_state = STATE_SYSEX_2; break; case STATE_SYSEX_2:
p[0] |= 0x04;
p[1] = port->data[0];
p[2] = port->data[1];
p[3] = b;
next_state = STATE_SYSEX_0; break;
} break;
}
/* States where we have to write into the USB request */ if (next_state == STATE_FINISHED ||
port->state == STATE_SYSEX_2 ||
port->state == STATE_1PARAM ||
port->state == STATE_2PARAM_2 ||
port->state == STATE_REAL_TIME) {
/* * We peek the request in order to reuse it if it fails to enqueue on * its endpoint
*/
len = kfifo_peek(&midi->in_req_fifo, &req); if (len != 1) {
ERROR(midi, "%s: Couldn't get usb request\n", __func__); return -1;
}
/* * If buffer overrun, then we ignore this transmission. * IMPORTANT: This will cause the user-space rawmidi device to block * until a) usb requests have been completed or b) snd_rawmidi_write() * times out.
*/ if (req->length > 0) return 0;
for (i = midi->in_last_port; i < midi->in_ports; ++i) { struct gmidi_in_port *port = midi->in_ports_array + i; struct snd_rawmidi_substream *substream = port->substream;
if (!port->active || !substream) continue;
while (req->length + 3 < midi->buflen) {
uint8_t b;
active = !!port->active; if (active) break;
}
midi->in_last_port = active ? i : 0;
if (req->length <= 0) goto done;
err = usb_ep_queue(ep, req, GFP_ATOMIC); if (err < 0) {
ERROR(midi, "%s failed to queue req: %d\n",
midi->in_ep->name, err);
req->length = 0; /* Re-use request next time. */
} else { /* Upon success, put request at the back of the queue. */
kfifo_skip(&midi->in_req_fifo);
kfifo_put(&midi->in_req_fifo, req);
}
/* * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. * It's an upside-down world being a gadget.
*/
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
/* register it - we're ready to go */
err = snd_card_register(card); if (err < 0) {
ERROR(midi, "snd_card_register() failed\n"); goto fail;
}
midi->gadget = cdev->gadget;
INIT_WORK(&midi->work, f_midi_in_work);
status = f_midi_register_card(midi); if (status < 0) goto fail_register;
/* maybe allocate device-global string ID */
us = usb_gstrings_attach(c->cdev, midi_strings,
ARRAY_SIZE(midi_string_defs)); if (IS_ERR(us)) {
status = PTR_ERR(us); goto fail;
}
ac_interface_desc.iInterface = us[STRING_FUNC_IDX].id;
/* We have two interfaces, AudioControl and MIDIStreaming */
status = usb_interface_id(c, f); if (status < 0) goto fail;
ac_interface_desc.bInterfaceNumber = status;
status = usb_interface_id(c, f); if (status < 0) goto fail;
ms_interface_desc.bInterfaceNumber = status;
ac_header_desc.baInterfaceNr[0] = status;
midi->ms_id = status;
status = -ENODEV;
/* * Reset wMaxPacketSize with maximum packet size of FS bulk transfer before * endpoint claim. This ensures that the wMaxPacketSize does not exceed the * limit during bind retries where configured dwc3 TX/RX FIFO's maxpacket * size of 512 bytes for IN/OUT endpoints in support HS speed only.
*/
bulk_in_desc.wMaxPacketSize = cpu_to_le16(64);
bulk_out_desc.wMaxPacketSize = cpu_to_le16(64);
/* configure the external IN jacks, each linked to an embedded OUT jack */ for (n = 0; n < midi->in_ports; n++) { struct usb_midi_in_jack_descriptor *in_ext = &jack_in_ext_desc[n]; struct usb_midi_out_jack_descriptor_1 *out_emb = &jack_out_emb_desc[n];
/* link it to the endpoint */
ms_in_desc.baAssocJackID[n] = out_emb->bJackID;
}
/* configure the external OUT jacks, each linked to an embedded IN jack */ for (n = 0; n < midi->out_ports; n++) { struct usb_midi_in_jack_descriptor *in_emb = &jack_in_emb_desc[n]; struct usb_midi_out_jack_descriptor_1 *out_ext = &jack_out_ext_desc[n];
/* ... and add them to the list */
endpoint_descriptor_index = i;
midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc;
midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc;
midi_function[i++] = NULL;
/* * support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds
*/ /* copy descriptors, and track endpoint copies */
f->fs_descriptors = usb_copy_descriptors(midi_function); if (!f->fs_descriptors) goto fail_f_midi;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.