linux/sound/usb/6fire/comm.c
<<
>>
Prefs
   1/*
   2 * Linux driver for TerraTec DMX 6Fire USB
   3 *
   4 * Device communications
   5 *
   6 * Author:      Torsten Schenk <torsten.schenk@zoho.com>
   7 * Created:     Jan 01, 2011
   8 * Version:     0.3.0
   9 * Copyright:   (C) Torsten Schenk
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 */
  16
  17#include "comm.h"
  18#include "chip.h"
  19#include "midi.h"
  20
  21enum {
  22        COMM_EP = 1,
  23        COMM_FPGA_EP = 2
  24};
  25
  26static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb,
  27                u8 *buffer, void *context, void(*handler)(struct urb *urb))
  28{
  29        usb_init_urb(urb);
  30        urb->transfer_buffer = buffer;
  31        urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);
  32        urb->complete = handler;
  33        urb->context = context;
  34        urb->interval = 1;
  35        urb->dev = rt->chip->dev;
  36}
  37
  38static void usb6fire_comm_receiver_handler(struct urb *urb)
  39{
  40        struct comm_runtime *rt = urb->context;
  41        struct midi_runtime *midi_rt = rt->chip->midi;
  42
  43        if (!urb->status) {
  44                if (rt->receiver_buffer[0] == 0x10) /* midi in event */
  45                        if (midi_rt)
  46                                midi_rt->in_received(midi_rt,
  47                                                rt->receiver_buffer + 2,
  48                                                rt->receiver_buffer[1]);
  49        }
  50
  51        if (!rt->chip->shutdown) {
  52                urb->status = 0;
  53                urb->actual_length = 0;
  54                if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
  55                        snd_printk(KERN_WARNING PREFIX
  56                                        "comm data receiver aborted.\n");
  57        }
  58}
  59
  60static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request,
  61                u8 reg, u8 vl, u8 vh)
  62{
  63        buffer[0] = 0x01;
  64        buffer[2] = request;
  65        buffer[3] = id;
  66        switch (request) {
  67        case 0x02:
  68                buffer[1] = 0x05; /* length (starting at buffer[2]) */
  69                buffer[4] = reg;
  70                buffer[5] = vl;
  71                buffer[6] = vh;
  72                break;
  73
  74        case 0x12:
  75                buffer[1] = 0x0b; /* length (starting at buffer[2]) */
  76                buffer[4] = 0x00;
  77                buffer[5] = 0x18;
  78                buffer[6] = 0x05;
  79                buffer[7] = 0x00;
  80                buffer[8] = 0x01;
  81                buffer[9] = 0x00;
  82                buffer[10] = 0x9e;
  83                buffer[11] = reg;
  84                buffer[12] = vl;
  85                break;
  86
  87        case 0x20:
  88        case 0x21:
  89        case 0x22:
  90                buffer[1] = 0x04;
  91                buffer[4] = reg;
  92                buffer[5] = vl;
  93                break;
  94        }
  95}
  96
  97static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
  98{
  99        int ret;
 100        int actual_len;
 101
 102        ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),
 103                        buffer, buffer[1] + 2, &actual_len, HZ);
 104        if (ret < 0)
 105                return ret;
 106        else if (actual_len != buffer[1] + 2)
 107                return -EIO;
 108        return 0;
 109}
 110
 111static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
 112                u8 reg, u8 value)
 113{
 114        u8 buffer[13]; /* 13: maximum length of message */
 115
 116        usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
 117        return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
 118}
 119
 120static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
 121                u8 reg, u8 vl, u8 vh)
 122{
 123        u8 buffer[13]; /* 13: maximum length of message */
 124
 125        usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
 126        return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
 127}
 128
 129int __devinit usb6fire_comm_init(struct sfire_chip *chip)
 130{
 131        struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
 132                        GFP_KERNEL);
 133        struct urb *urb = &rt->receiver;
 134        int ret;
 135
 136        if (!rt)
 137                return -ENOMEM;
 138
 139        rt->serial = 1;
 140        rt->chip = chip;
 141        usb_init_urb(urb);
 142        rt->init_urb = usb6fire_comm_init_urb;
 143        rt->write8 = usb6fire_comm_write8;
 144        rt->write16 = usb6fire_comm_write16;
 145
 146        /* submit an urb that receives communication data from device */
 147        urb->transfer_buffer = rt->receiver_buffer;
 148        urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE;
 149        urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP);
 150        urb->dev = chip->dev;
 151        urb->complete = usb6fire_comm_receiver_handler;
 152        urb->context = rt;
 153        urb->interval = 1;
 154        ret = usb_submit_urb(urb, GFP_KERNEL);
 155        if (ret < 0) {
 156                kfree(rt);
 157                snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
 158                return ret;
 159        }
 160        chip->comm = rt;
 161        return 0;
 162}
 163
 164void usb6fire_comm_abort(struct sfire_chip *chip)
 165{
 166        struct comm_runtime *rt = chip->comm;
 167
 168        if (rt)
 169                usb_poison_urb(&rt->receiver);
 170}
 171
 172void usb6fire_comm_destroy(struct sfire_chip *chip)
 173{
 174        kfree(chip->comm);
 175        chip->comm = NULL;
 176}
 177