blob: 161215d78d9520a98026574489095b47e6c95f85 [file] [log] [blame]
Torsten Schenkc6d43ba2011-01-24 18:45:30 +01001/*
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
Torsten Schenkc6d43ba2011-01-24 18:45:30 +01008 * 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)
Takashi Iwaie3b37572014-02-26 15:51:04 +010054 dev_warn(&urb->dev->dev,
Torsten Schenkc6d43ba2011-01-24 18:45:30 +010055 "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{
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300113 u8 *buffer;
114 int ret;
115
116 /* 13: maximum length of message */
117 buffer = kmalloc(13, GFP_KERNEL);
118 if (!buffer)
119 return -ENOMEM;
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100120
121 usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300122 ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
123
124 kfree(buffer);
125 return ret;
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100126}
127
128static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
129 u8 reg, u8 vl, u8 vh)
130{
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300131 u8 *buffer;
132 int ret;
133
134 /* 13: maximum length of message */
135 buffer = kmalloc(13, GFP_KERNEL);
136 if (!buffer)
137 return -ENOMEM;
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100138
139 usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300140 ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
141
142 kfree(buffer);
143 return ret;
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100144}
145
Bill Pemberton87f97962012-12-06 12:35:28 -0500146int usb6fire_comm_init(struct sfire_chip *chip)
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100147{
148 struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
149 GFP_KERNEL);
Sachin Kamat27b2a222012-11-21 14:36:57 +0530150 struct urb *urb;
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100151 int ret;
152
153 if (!rt)
154 return -ENOMEM;
155
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300156 rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
157 if (!rt->receiver_buffer) {
158 kfree(rt);
159 return -ENOMEM;
160 }
161
Sachin Kamat27b2a222012-11-21 14:36:57 +0530162 urb = &rt->receiver;
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100163 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) {
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300180 kfree(rt->receiver_buffer);
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100181 kfree(rt);
Takashi Iwaie3b37572014-02-26 15:51:04 +0100182 dev_err(&chip->dev->dev, "cannot create comm data receiver.");
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100183 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{
Jussi Kivilinnaddb6b5a92013-08-06 14:53:24 +0300199 struct comm_runtime *rt = chip->comm;
200
201 kfree(rt->receiver_buffer);
202 kfree(rt);
Torsten Schenkc6d43ba2011-01-24 18:45:30 +0100203 chip->comm = NULL;
204}