Linux-libre 4.9.46-gnu
[librecmc/linux-libre.git] / drivers / staging / vt6656 / usbpipe.c
1 /*
2  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  *
16  * File: usbpipe.c
17  *
18  * Purpose: Handle USB control endpoint
19  *
20  * Author: Warren Hsu
21  *
22  * Date: Mar. 29, 2005
23  *
24  * Functions:
25  *      vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM
26  *      vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM
27  *      vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM
28  *      vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM
29  *
30  * Revision History:
31  *      04-05-2004 Jerry Chen: Initial release
32  *      11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,
33  *                             ControlvMaskByte
34  *
35  */
36
37 #include "int.h"
38 #include "rxtx.h"
39 #include "dpc.h"
40 #include "desc.h"
41 #include "device.h"
42 #include "usbpipe.h"
43
44 #define USB_CTL_WAIT    500 /* ms */
45
46 int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
47                 u16 index, u16 length, u8 *buffer)
48 {
49         int status = 0;
50         u8 *usb_buffer;
51
52         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
53                 return STATUS_FAILURE;
54
55         mutex_lock(&priv->usb_lock);
56
57         usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
58         if (!usb_buffer) {
59                 mutex_unlock(&priv->usb_lock);
60                 return -ENOMEM;
61         }
62
63         status = usb_control_msg(priv->usb,
64                                  usb_sndctrlpipe(priv->usb, 0),
65                                  request, 0x40, value,
66                                  index, usb_buffer, length, USB_CTL_WAIT);
67
68         kfree(usb_buffer);
69
70         mutex_unlock(&priv->usb_lock);
71
72         if (status < (int)length)
73                 return STATUS_FAILURE;
74
75         return STATUS_SUCCESS;
76 }
77
78 void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
79 {
80         vnt_control_out(priv, MESSAGE_TYPE_WRITE,
81                                         reg_off, reg, sizeof(u8), &data);
82 }
83
84 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
85                 u16 index, u16 length, u8 *buffer)
86 {
87         int status;
88         u8 *usb_buffer;
89
90         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
91                 return STATUS_FAILURE;
92
93         mutex_lock(&priv->usb_lock);
94
95         usb_buffer = kmalloc(length, GFP_KERNEL);
96         if (!usb_buffer) {
97                 mutex_unlock(&priv->usb_lock);
98                 return -ENOMEM;
99         }
100
101         status = usb_control_msg(priv->usb,
102                                  usb_rcvctrlpipe(priv->usb, 0),
103                                  request, 0xc0, value,
104                                  index, usb_buffer, length, USB_CTL_WAIT);
105
106         if (status == length)
107                 memcpy(buffer, usb_buffer, length);
108
109         kfree(usb_buffer);
110
111         mutex_unlock(&priv->usb_lock);
112
113         if (status < (int)length)
114                 return STATUS_FAILURE;
115
116         return STATUS_SUCCESS;
117 }
118
119 void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
120 {
121         vnt_control_in(priv, MESSAGE_TYPE_READ,
122                         reg_off, reg, sizeof(u8), data);
123 }
124
125 static void vnt_start_interrupt_urb_complete(struct urb *urb)
126 {
127         struct vnt_private *priv = urb->context;
128         int status = urb->status;
129
130         switch (status) {
131         case 0:
132         case -ETIMEDOUT:
133                 break;
134         case -ECONNRESET:
135         case -ENOENT:
136         case -ESHUTDOWN:
137                 priv->int_buf.in_use = false;
138                 return;
139         default:
140                 break;
141         }
142
143         if (status) {
144                 priv->int_buf.in_use = false;
145
146                 dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
147         } else {
148                 vnt_int_process_data(priv);
149         }
150
151         status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
152         if (status)
153                 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
154         else
155                 priv->int_buf.in_use = true;
156 }
157
158 int vnt_start_interrupt_urb(struct vnt_private *priv)
159 {
160         int status = STATUS_FAILURE;
161
162         if (priv->int_buf.in_use)
163                 return STATUS_FAILURE;
164
165         priv->int_buf.in_use = true;
166
167         usb_fill_int_urb(priv->interrupt_urb,
168                          priv->usb,
169                          usb_rcvintpipe(priv->usb, 1),
170                          priv->int_buf.data_buf,
171                          MAX_INTERRUPT_SIZE,
172                          vnt_start_interrupt_urb_complete,
173                          priv,
174                          priv->int_interval);
175
176         status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
177         if (status) {
178                 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
179                 priv->int_buf.in_use = false;
180         }
181
182         return status;
183 }
184
185 static void vnt_submit_rx_urb_complete(struct urb *urb)
186 {
187         struct vnt_rcb *rcb = urb->context;
188         struct vnt_private *priv = rcb->priv;
189
190         switch (urb->status) {
191         case 0:
192                 break;
193         case -ECONNRESET:
194         case -ENOENT:
195         case -ESHUTDOWN:
196                 return;
197         case -ETIMEDOUT:
198         default:
199                 dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
200                 break;
201         }
202
203         if (urb->actual_length) {
204                 if (vnt_rx_data(priv, rcb, urb->actual_length)) {
205                         rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
206                         if (!rcb->skb) {
207                                 dev_dbg(&priv->usb->dev,
208                                         "Failed to re-alloc rx skb\n");
209
210                                 rcb->in_use = false;
211                                 return;
212                         }
213                 } else {
214                         skb_push(rcb->skb, skb_headroom(rcb->skb));
215                         skb_trim(rcb->skb, 0);
216                 }
217
218                 urb->transfer_buffer = skb_put(rcb->skb,
219                                                 skb_tailroom(rcb->skb));
220         }
221
222         if (usb_submit_urb(urb, GFP_ATOMIC)) {
223                 dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
224
225                 rcb->in_use = false;
226         }
227 }
228
229 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
230 {
231         int status = 0;
232         struct urb *urb = rcb->urb;
233
234         if (!rcb->skb) {
235                 dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
236                 return status;
237         }
238
239         usb_fill_bulk_urb(urb,
240                           priv->usb,
241                           usb_rcvbulkpipe(priv->usb, 2),
242                           skb_put(rcb->skb, skb_tailroom(rcb->skb)),
243                           MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
244                           vnt_submit_rx_urb_complete,
245                           rcb);
246
247         status = usb_submit_urb(urb, GFP_ATOMIC);
248         if (status) {
249                 dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
250                 return STATUS_FAILURE;
251         }
252
253         rcb->in_use = true;
254
255         return status;
256 }
257
258 static void vnt_tx_context_complete(struct urb *urb)
259 {
260         struct vnt_usb_send_context *context = urb->context;
261         struct vnt_private *priv = context->priv;
262
263         switch (urb->status) {
264         case 0:
265                 dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
266                 break;
267         case -ECONNRESET:
268         case -ENOENT:
269         case -ESHUTDOWN:
270                 context->in_use = false;
271                 return;
272         case -ETIMEDOUT:
273         default:
274                 dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
275                 break;
276         }
277
278         if (context->type == CONTEXT_DATA_PACKET)
279                 ieee80211_wake_queues(priv->hw);
280
281         if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
282                 if (context->skb)
283                         ieee80211_free_txskb(priv->hw, context->skb);
284
285                 context->in_use = false;
286         }
287 }
288
289 int vnt_tx_context(struct vnt_private *priv,
290                    struct vnt_usb_send_context *context)
291 {
292         int status;
293         struct urb *urb = context->urb;
294
295         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
296                 context->in_use = false;
297                 return STATUS_RESOURCES;
298         }
299
300         usb_fill_bulk_urb(urb,
301                           priv->usb,
302                           usb_sndbulkpipe(priv->usb, 3),
303                           context->data,
304                           context->buf_len,
305                           vnt_tx_context_complete,
306                           context);
307
308         status = usb_submit_urb(urb, GFP_ATOMIC);
309         if (status) {
310                 dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
311
312                 context->in_use = false;
313                 return STATUS_FAILURE;
314         }
315
316         return STATUS_PENDING;
317 }