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