Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/6fire/comm.c
26425 views
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 <[email protected]>
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
16
enum {
17
COMM_EP = 1,
18
COMM_FPGA_EP = 2
19
};
20
21
static 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
33
static 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
55
static 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
92
static 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, 1000);
99
if (ret < 0)
100
return ret;
101
else if (actual_len != buffer[1] + 2)
102
return -EIO;
103
return 0;
104
}
105
106
static 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
124
static 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
142
int 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
185
void 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
193
void 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
202