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