123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /*
- * Linux driver for TerraTec DMX 6Fire USB
- *
- * Device communications
- *
- * Author: Torsten Schenk <torsten.schenk@zoho.com>
- * Created: Jan 01, 2011
- * Copyright: (C) Torsten Schenk
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
- #include "comm.h"
- #include "chip.h"
- #include "midi.h"
- enum {
- COMM_EP = 1,
- COMM_FPGA_EP = 2
- };
- static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb,
- u8 *buffer, void *context, void(*handler)(struct urb *urb))
- {
- usb_init_urb(urb);
- urb->transfer_buffer = buffer;
- urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);
- urb->complete = handler;
- urb->context = context;
- urb->interval = 1;
- urb->dev = rt->chip->dev;
- }
- static void usb6fire_comm_receiver_handler(struct urb *urb)
- {
- struct comm_runtime *rt = urb->context;
- struct midi_runtime *midi_rt = rt->chip->midi;
- if (!urb->status) {
- if (rt->receiver_buffer[0] == 0x10) /* midi in event */
- if (midi_rt)
- midi_rt->in_received(midi_rt,
- rt->receiver_buffer + 2,
- rt->receiver_buffer[1]);
- }
- if (!rt->chip->shutdown) {
- urb->status = 0;
- urb->actual_length = 0;
- if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
- snd_printk(KERN_WARNING PREFIX
- "comm data receiver aborted.\n");
- }
- }
- static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request,
- u8 reg, u8 vl, u8 vh)
- {
- buffer[0] = 0x01;
- buffer[2] = request;
- buffer[3] = id;
- switch (request) {
- case 0x02:
- buffer[1] = 0x05; /* length (starting at buffer[2]) */
- buffer[4] = reg;
- buffer[5] = vl;
- buffer[6] = vh;
- break;
- case 0x12:
- buffer[1] = 0x0b; /* length (starting at buffer[2]) */
- buffer[4] = 0x00;
- buffer[5] = 0x18;
- buffer[6] = 0x05;
- buffer[7] = 0x00;
- buffer[8] = 0x01;
- buffer[9] = 0x00;
- buffer[10] = 0x9e;
- buffer[11] = reg;
- buffer[12] = vl;
- break;
- case 0x20:
- case 0x21:
- case 0x22:
- buffer[1] = 0x04;
- buffer[4] = reg;
- buffer[5] = vl;
- break;
- }
- }
- static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
- {
- int ret;
- int actual_len;
- ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),
- buffer, buffer[1] + 2, &actual_len, HZ);
- if (ret < 0)
- return ret;
- else if (actual_len != buffer[1] + 2)
- return -EIO;
- return 0;
- }
- static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
- u8 reg, u8 value)
- {
- u8 *buffer;
- int ret;
- /* 13: maximum length of message */
- buffer = kmalloc(13, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
- usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
- ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
- kfree(buffer);
- return ret;
- }
- static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
- u8 reg, u8 vl, u8 vh)
- {
- u8 *buffer;
- int ret;
- /* 13: maximum length of message */
- buffer = kmalloc(13, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
- usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
- ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
- kfree(buffer);
- return ret;
- }
- int __devinit usb6fire_comm_init(struct sfire_chip *chip)
- {
- struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
- GFP_KERNEL);
- struct urb *urb = &rt->receiver;
- int ret;
- if (!rt)
- return -ENOMEM;
- rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
- if (!rt->receiver_buffer) {
- kfree(rt);
- return -ENOMEM;
- }
- rt->serial = 1;
- rt->chip = chip;
- usb_init_urb(urb);
- rt->init_urb = usb6fire_comm_init_urb;
- rt->write8 = usb6fire_comm_write8;
- rt->write16 = usb6fire_comm_write16;
- /* submit an urb that receives communication data from device */
- urb->transfer_buffer = rt->receiver_buffer;
- urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE;
- urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP);
- urb->dev = chip->dev;
- urb->complete = usb6fire_comm_receiver_handler;
- urb->context = rt;
- urb->interval = 1;
- ret = usb_submit_urb(urb, GFP_KERNEL);
- if (ret < 0) {
- kfree(rt->receiver_buffer);
- kfree(rt);
- snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
- return ret;
- }
- chip->comm = rt;
- return 0;
- }
- void usb6fire_comm_abort(struct sfire_chip *chip)
- {
- struct comm_runtime *rt = chip->comm;
- if (rt)
- usb_poison_urb(&rt->receiver);
- }
- void usb6fire_comm_destroy(struct sfire_chip *chip)
- {
- struct comm_runtime *rt = chip->comm;
- kfree(rt->receiver_buffer);
- kfree(rt);
- chip->comm = NULL;
- }
|