aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/6fire/comm.c
diff options
context:
space:
mode:
authorTorsten Schenk <torsten.schenk@zoho.com>2011-01-24 12:45:30 -0500
committerTakashi Iwai <tiwai@suse.de>2011-01-24 12:45:30 -0500
commitc6d43ba816d1cf1d125bfbfc938f2a28a87facf9 (patch)
tree6f9c73ddae1efbda97869cc07dac62dc52b75e8f /sound/usb/6fire/comm.c
parent49c6ad430d74fb7995990be0f66165e4b94a6bc5 (diff)
ALSA: usb/6fire - Driver for TerraTec DMX 6Fire USB
What is working: Everything except SPDIF - Hardware Master volume - PCM 44-192kHz@24 bits, 6 channels out, 4 channels in (analog) - MIDI in/out - firmware loading after cold start - phono/line switching Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/6fire/comm.c')
-rw-r--r--sound/usb/6fire/comm.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
new file mode 100644
index 000000000000..c994daa57af2
--- /dev/null
+++ b/sound/usb/6fire/comm.c
@@ -0,0 +1,176 @@
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 * 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
21enum {
22 COMM_EP = 1,
23 COMM_FPGA_EP = 2
24};
25
26static 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
38static 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
60static 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
97static 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
111static 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
120static 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
129int __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
164void 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
172void usb6fire_comm_destroy(struct sfire_chip *chip)
173{
174 kfree(chip->comm);
175 chip->comm = NULL;
176}