Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/usb/6fire/comm.c
10817 views
1
/*
2
* Linux driver for TerraTec DMX 6Fire USB
3
*
4
* Device communications
5
*
6
* Author: Torsten Schenk <[email protected]>
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
21
enum {
22
COMM_EP = 1,
23
COMM_FPGA_EP = 2
24
};
25
26
static 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
38
static 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
60
static 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
97
static 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
111
static 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
120
static 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
129
int __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
164
void 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
172
void usb6fire_comm_destroy(struct sfire_chip *chip)
173
{
174
kfree(chip->comm);
175
chip->comm = NULL;
176
}
177
178