Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / sound / usb / 6fire / comm.c
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  * 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
20 enum {
21         COMM_EP = 1,
22         COMM_FPGA_EP = 2
23 };
24
25 static 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
37 static 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)
54                         dev_warn(&urb->dev->dev,
55                                         "comm data receiver aborted.\n");
56         }
57 }
58
59 static 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
96 static 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
110 static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
111                 u8 reg, u8 value)
112 {
113         u8 *buffer;
114         int ret;
115
116         /* 13: maximum length of message */
117         buffer = kmalloc(13, GFP_KERNEL);
118         if (!buffer)
119                 return -ENOMEM;
120
121         usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
122         ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
123
124         kfree(buffer);
125         return ret;
126 }
127
128 static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
129                 u8 reg, u8 vl, u8 vh)
130 {
131         u8 *buffer;
132         int ret;
133
134         /* 13: maximum length of message */
135         buffer = kmalloc(13, GFP_KERNEL);
136         if (!buffer)
137                 return -ENOMEM;
138
139         usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
140         ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
141
142         kfree(buffer);
143         return ret;
144 }
145
146 int usb6fire_comm_init(struct sfire_chip *chip)
147 {
148         struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
149                         GFP_KERNEL);
150         struct urb *urb;
151         int ret;
152
153         if (!rt)
154                 return -ENOMEM;
155
156         rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
157         if (!rt->receiver_buffer) {
158                 kfree(rt);
159                 return -ENOMEM;
160         }
161
162         urb = &rt->receiver;
163         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) {
180                 kfree(rt->receiver_buffer);
181                 kfree(rt);
182                 dev_err(&chip->dev->dev, "cannot create comm data receiver.");
183                 return ret;
184         }
185         chip->comm = rt;
186         return 0;
187 }
188
189 void 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
197 void usb6fire_comm_destroy(struct sfire_chip *chip)
198 {
199         struct comm_runtime *rt = chip->comm;
200
201         kfree(rt->receiver_buffer);
202         kfree(rt);
203         chip->comm = NULL;
204 }