📄 gmidi.c
字号:
struct gmidi_device *dev = ep->driver_data; /* cable is ignored, because for now we only have one. */ if (!dev->out_substream) { /* Nobody is listening - throw it on the floor. */ return; } if (!test_bit(dev->out_substream->number, &dev->out_triggered)) { return; } snd_rawmidi_receive(dev->out_substream, data, length);}static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req){ unsigned i; u8 *buf = req->buf; for (i = 0; i + 3 < req->actual; i += 4) { if (buf[i] != 0) { int cable = buf[i] >> 4; int length = gmidi_cin_length[buf[i] & 0x0f]; gmidi_read_data(ep, cable, &buf[i + 1], length); } }}static void gmidi_complete(struct usb_ep *ep, struct usb_request *req){ struct gmidi_device *dev = ep->driver_data; int status = req->status; switch (status) { case 0: /* normal completion */ if (ep == dev->out_ep) { /* we received stuff. req is queued again, below */ gmidi_handle_out_data(ep, req); } else if (ep == dev->in_ep) { /* our transmit completed. see if there's more to go. gmidi_transmit eats req, don't queue it again. */ gmidi_transmit(dev, req); 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(dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); if (ep == dev->out_ep) { gmidi_handle_out_data(ep, req); } free_ep_req(ep, req); return; case -EOVERFLOW: /* buffer overrun on read means that * we didn't provide a big enough * buffer. */ default: DBG(dev, "%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(dev, "kill %s: resubmit %d bytes --> %d\n", ep->name, req->length, status); usb_ep_set_halt(ep); /* FIXME recover later ... somehow */ }}static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags){ int err = 0; struct usb_request *req; struct usb_ep *ep; unsigned i; err = usb_ep_enable(dev->in_ep, &bulk_in_desc); if (err) { ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err); goto fail; } dev->in_ep->driver_data = dev; err = usb_ep_enable(dev->out_ep, &bulk_out_desc); if (err) { ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err); goto fail; } dev->out_ep->driver_data = dev; /* allocate a bunch of read buffers and queue them all at once. */ ep = dev->out_ep; for (i = 0; i < qlen && err == 0; i++) { req = alloc_ep_req(ep, buflen); if (req) { req->complete = gmidi_complete; err = usb_ep_queue(ep, req, GFP_ATOMIC); if (err) { DBG(dev, "%s queue req: %d\n", ep->name, err); } } else { err = -ENOMEM; } }fail: /* caller is responsible for cleanup on error */ return err;}static void gmidi_reset_config(struct gmidi_device *dev){ if (dev->config == 0) { return; } DBG(dev, "reset config\n"); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. */ usb_ep_disable(dev->in_ep); usb_ep_disable(dev->out_ep); dev->config = 0;}/* change our operational config. this code must agree with the code * that returns config descriptors, and altsetting code. * * it's also responsible for power management interactions. some * configurations might not work with our current power sources. * * note that some device controller hardware will constrain what this * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */static intgmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags){ int result = 0; struct usb_gadget *gadget = dev->gadget;#if 0 /* FIXME */ /* Hacking this bit out fixes a bug where on receipt of two USB_REQ_SET_CONFIGURATION messages, we end up with no buffered OUT requests waiting for data. This is clearly hiding a bug elsewhere, because if the config didn't change then we really shouldn't do anything. */ /* Having said that, when we do "change" from config 1 to config 1, we at least gmidi_reset_config() which clears out any requests on endpoints, so it's not like we leak or anything. */ if (number == dev->config) { return 0; }#endif if (gadget_is_sa1100(gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ ERROR(dev, "can't change configurations\n"); return -ESPIPE; } gmidi_reset_config(dev); switch (number) { case GMIDI_CONFIG: result = set_gmidi_config(dev, gfp_flags); break; default: result = -EINVAL; /* FALL THROUGH */ case 0: return result; } if (!result && (!dev->in_ep || !dev->out_ep)) { result = -ENODEV; } if (result) { gmidi_reset_config(dev); } else { char *speed; switch (gadget->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; default: speed = "?"; break; } dev->config = number; INFO(dev, "%s speed\n", speed); } return result;}static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req){ if (req->status || req->actual != req->length) { DBG((struct gmidi_device *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); }}/* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver (like * device and endpoint feature flags, and their status). It's all * housekeeping for the gadget function we're implementing. Most of * the work is in config-specific setup. */static int gmidi_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl){ struct gmidi_device *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ req->zero = 0; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) { goto unknown; } switch (w_value >> 8) { case USB_DT_DEVICE: value = min(w_length, (u16) sizeof(device_desc)); memcpy(req->buf, &device_desc, value); break; case USB_DT_CONFIG: value = config_buf(gadget, req->buf, w_value >> 8, w_value & 0xff); if (value >= 0) { value = min(w_length, (u16)value); } break; case USB_DT_STRING: /* wIndex == language code. * this driver only handles one language, you can * add string tables for other languages, using * any UTF-8 characters */ value = usb_gadget_get_string(&stringtab, w_value & 0xff, req->buf); if (value >= 0) { value = min(w_length, (u16)value); } break; } break; /* currently two configs, two speeds */ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) { goto unknown; } if (gadget->a_hnp_support) { DBG(dev, "HNP available\n"); } else if (gadget->a_alt_hnp_support) { DBG(dev, "HNP needs a different root port\n"); } else { VDBG(dev, "HNP inactive\n"); } spin_lock(&dev->lock); value = gmidi_set_config(dev, w_value, GFP_ATOMIC); spin_unlock(&dev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) { goto unknown; } *(u8 *)req->buf = dev->config; value = min(w_length, (u16)1); break; /* until we add altsetting support, or other interfaces, * only 0/0 are possible. pxa2xx only supports 0/0 (poorly) * and already killed pending endpoint I/O. */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) { goto unknown; } spin_lock(&dev->lock); if (dev->config && w_index < GMIDI_NUM_INTERFACES && w_value == 0) { u8 config = dev->config; /* resets interface configuration, forgets about * previous transaction state (queued bufs, etc) * and re-inits endpoint state (toggle etc) * no response queued, just zero status == success. * if we had more than one interface we couldn't * use this "reset the config" shortcut. */ gmidi_reset_config(dev); gmidi_set_config(dev, config, GFP_ATOMIC); value = 0; } spin_unlock(&dev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) { goto unknown; } if (!dev->config) { break; } if (w_index >= GMIDI_NUM_INTERFACES) { value = -EDOM; break; } *(u8 *)req->buf = 0; value = min(w_length, (u16)1); break; default:unknown: VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; req->zero = value < w_length; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG(dev, "ep_queue --> %d\n", value); req->status = 0; gmidi_setup_complete(gadget->ep0, req); } } /* device either stalls (value < 0) or reports success */ return value;}static void gmidi_disconnect(struct usb_gadget *gadget){ struct gmidi_device *dev = get_gadget_data(gadget); unsigned long flags; spin_lock_irqsave(&dev->lock, flags); gmidi_reset_config(dev); /* a more significant application might have some non-usb * activities to quiesce here, saving resources like power * or pushing the notification up a network stack. */ spin_unlock_irqrestore(&dev->lock, flags); /* next we may get setup() calls to enumerate new connections; * or an unbind() during shutdown (including removing module). */}static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget){ struct gmidi_device *dev = get_gadget_data(gadget); struct snd_card *card; DBG(dev, "unbind\n"); card = dev->card; dev->card = NULL; if (card) { snd_card_free(card); } /* we've already been disconnected ... no i/o is active */ if (dev->req) { dev->req->length = USB_BUFSIZ; free_ep_req(gadget->ep0, dev->req); } kfree(dev); set_gadget_data(gadget, NULL);}static int gmidi_snd_free(struct snd_device *device){ return 0;}static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0, uint8_t p1, uint8_t p2, uint8_t p3){ unsigned length = req->length; u8 *buf = (u8 *)req->buf + length; buf[0] = p0; buf[1] = p1; buf[2] = p2; buf[3] = p3; req->length = length + 4;}/* * Converts MIDI commands to USB MIDI packets. */static void gmidi_transmit_byte(struct usb_request *req, struct gmidi_in_port *port, uint8_t b){ uint8_t p0 = port->cable; if (b >= 0xf8) { gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0); } else if (b >= 0xf0) { switch (b) { case 0xf0: port->data[0] = b; port->state = STATE_SYSEX_1; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -