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