📄 gmidi.c
字号:
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: gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0); port->state = STATE_UNKNOWN; break; case 0xf7: switch (port->state) { case STATE_SYSEX_0: gmidi_transmit_packet(req, p0 | 0x05, 0xf7, 0, 0); break; case STATE_SYSEX_1: gmidi_transmit_packet(req, p0 | 0x06, port->data[0], 0xf7, 0); break; case STATE_SYSEX_2: gmidi_transmit_packet(req, 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; } gmidi_transmit_packet(req, 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; } gmidi_transmit_packet(req, 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: gmidi_transmit_packet(req, p0 | 0x04, port->data[0], port->data[1], b); port->state = STATE_SYSEX_0; break; } }}static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req){ struct usb_ep *ep = dev->in_ep; struct gmidi_in_port *port = &dev->in_port; if (!ep) { return; } if (!req) { req = alloc_ep_req(ep, buflen); } if (!req) { ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n"); return; } req->length = 0; req->complete = gmidi_complete; if (port->active) { while (req->length + 3 < buflen) { uint8_t b; if (snd_rawmidi_transmit(dev->in_substream, &b, 1) != 1) { port->active = 0; break; } gmidi_transmit_byte(req, port, b); } } if (req->length > 0) { usb_ep_queue(ep, req, GFP_ATOMIC); } else { free_ep_req(ep, req); }}static void gmidi_in_tasklet(unsigned long data){ struct gmidi_device *dev = (struct gmidi_device *)data; gmidi_transmit(dev, NULL);}static int gmidi_in_open(struct snd_rawmidi_substream *substream){ struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_open\n"); dev->in_substream = substream; dev->in_port.state = STATE_UNKNOWN; return 0;}static int gmidi_in_close(struct snd_rawmidi_substream *substream){ struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_close\n"); return 0;}static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up){ struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_in_trigger %d\n", up); dev->in_port.active = up; if (up) { tasklet_hi_schedule(&dev->tasklet); }}static int gmidi_out_open(struct snd_rawmidi_substream *substream){ struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_open\n"); dev->out_substream = substream; return 0;}static int gmidi_out_close(struct snd_rawmidi_substream *substream){ struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_close\n"); return 0;}static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up){ struct gmidi_device *dev = substream->rmidi->private_data; VDBG(dev, "gmidi_out_trigger %d\n", up); if (up) { set_bit(substream->number, &dev->out_triggered); } else { clear_bit(substream->number, &dev->out_triggered); }}static struct snd_rawmidi_ops gmidi_in_ops = { .open = gmidi_in_open, .close = gmidi_in_close, .trigger = gmidi_in_trigger,};static struct snd_rawmidi_ops gmidi_out_ops = { .open = gmidi_out_open, .close = gmidi_out_close, .trigger = gmidi_out_trigger};/* register as a sound "card" */static int gmidi_register_card(struct gmidi_device *dev){ struct snd_card *card; struct snd_rawmidi *rmidi; int err; int out_ports = 1; int in_ports = 1; static struct snd_device_ops ops = { .dev_free = gmidi_snd_free, }; card = snd_card_new(index, id, THIS_MODULE, 0); if (!card) { ERROR(dev, "snd_card_new failed\n"); err = -ENOMEM; goto fail; } dev->card = card; err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops); if (err < 0) { ERROR(dev, "snd_device_new failed: error %d\n", err); goto fail; } strcpy(card->driver, longname); strcpy(card->longname, longname); strcpy(card->shortname, shortname); /* Set up rawmidi */ dev->in_port.dev = dev; dev->in_port.active = 0; snd_component_add(card, "MIDI"); err = snd_rawmidi_new(card, "USB MIDI Gadget", 0, out_ports, in_ports, &rmidi); if (err < 0) { ERROR(dev, "snd_rawmidi_new failed: error %d\n", err); goto fail; } dev->rmidi = rmidi; strcpy(rmidi->name, card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = dev; /* 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); snd_card_set_dev(card, &dev->gadget->dev); /* register it - we're ready to go */ err = snd_card_register(card); if (err < 0) { ERROR(dev, "snd_card_register failed\n"); goto fail; } VDBG(dev, "gmidi_register_card finished ok\n"); return 0;fail: if (dev->card) { snd_card_free(dev->card); dev->card = NULL; } return err;}/* * Creates an output endpoint, and initializes output ports. */static int __devinit gmidi_bind(struct usb_gadget *gadget){ struct gmidi_device *dev; struct usb_ep *in_ep, *out_ep; int gcnum, err = 0; /* support optional vendor/distro customization */ if (idVendor) { if (!idProduct) { printk(KERN_ERR "idVendor needs idProduct!\n"); return -ENODEV; } device_desc.idVendor = cpu_to_le16(idVendor); device_desc.idProduct = cpu_to_le16(idProduct); if (bcdDevice) { device_desc.bcdDevice = cpu_to_le16(bcdDevice); } } if (iManufacturer) { strlcpy(manufacturer, iManufacturer, sizeof(manufacturer)); } else { snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", init_utsname()->sysname, init_utsname()->release, gadget->name); } if (iProduct) { strlcpy(product_desc, iProduct, sizeof(product_desc)); } if (iSerialNumber) { device_desc.iSerialNumber = STRING_SERIAL, strlcpy(serial_number, iSerialNumber, sizeof(serial_number)); } /* Bulk-only drivers like this one SHOULD be able to * autoconfigure on any sane usb controller driver, * but there may also be important quirks to address. */ usb_ep_autoconfig_reset(gadget); in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc); if (!in_ep) {autoconf_fail: printk(KERN_ERR "%s: can't autoconfigure on %s\n", shortname, gadget->name); return -ENODEV; } EP_IN_NAME = in_ep->name; in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc); if (!out_ep) { goto autoconf_fail; } EP_OUT_NAME = out_ep->name; out_ep->driver_data = out_ep; /* claim */ gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) { device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); } else { /* gmidi is so simple (no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. * so warn about unrecognized controllers, don't panic. */ printk(KERN_WARNING "%s: controller '%s' not recognized\n", shortname, gadget->name); device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } /* ok, we made sense of the hardware ... */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { return -ENOMEM; } spin_lock_init(&dev->lock); dev->gadget = gadget; dev->in_ep = in_ep; dev->out_ep = out_ep; set_gadget_data(gadget, dev); tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev); /* preallocate control response and buffer */ dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ); if (!dev->req) { err = -ENOMEM; goto fail; } dev->req->complete = gmidi_setup_complete; device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; gadget->ep0->driver_data = dev; INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname); INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, EP_OUT_NAME, EP_IN_NAME); /* register as an ALSA sound card */ err = gmidi_register_card(dev); if (err < 0) { goto fail; } VDBG(dev, "gmidi_bind finished ok\n"); return 0;fail: gmidi_unbind(gadget); return err;}static void gmidi_suspend(struct usb_gadget *gadget){ struct gmidi_device *dev = get_gadget_data(gadget); if (gadget->speed == USB_SPEED_UNKNOWN) { return; } DBG(dev, "suspend\n");}static void gmidi_resume(struct usb_gadget *gadget){ struct gmidi_device *dev = get_gadget_data(gadget); DBG(dev, "resume\n");}static struct usb_gadget_driver gmidi_driver = { .speed = USB_SPEED_FULL, .function = (char *)longname, .bind = gmidi_bind, .unbind = gmidi_unbind, .setup = gmidi_setup, .disconnect = gmidi_disconnect, .suspend = gmidi_suspend, .resume = gmidi_resume, .driver = { .name = (char *)shortname, .owner = THIS_MODULE, },};static int __init gmidi_init(void){ return usb_gadget_register_driver(&gmidi_driver);}module_init(gmidi_init);static void __exit gmidi_cleanup(void){ usb_gadget_unregister_driver(&gmidi_driver);}module_exit(gmidi_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -