]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/vt6656/usbpipe.c
net: aquantia: correctly handle macvlan and multicast coexistence
[linux.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, 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 >= 0 && ret < (int)length)
63                 ret = -EIO;
64
65 end_unlock:
66         mutex_unlock(&priv->usb_lock);
67 end:
68         return ret;
69 }
70
71 int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
72 {
73         return vnt_control_out(priv, MESSAGE_TYPE_WRITE,
74                                reg_off, reg, sizeof(u8), &data);
75 }
76
77 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
78                    u16 index, u16 length, u8 *buffer)
79 {
80         int ret = 0;
81         u8 *usb_buffer;
82
83         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
84                 ret = -EINVAL;
85                 goto end;
86         }
87
88         mutex_lock(&priv->usb_lock);
89
90         usb_buffer = kmalloc(length, GFP_KERNEL);
91         if (!usb_buffer) {
92                 ret = -ENOMEM;
93                 goto end_unlock;
94         }
95
96         ret = usb_control_msg(priv->usb,
97                               usb_rcvctrlpipe(priv->usb, 0),
98                               request, 0xc0, value,
99                               index, usb_buffer, length, USB_CTL_WAIT);
100
101         if (ret == length)
102                 memcpy(buffer, usb_buffer, length);
103
104         kfree(usb_buffer);
105
106         if (ret >= 0 && ret < (int)length)
107                 ret = -EIO;
108
109 end_unlock:
110         mutex_unlock(&priv->usb_lock);
111 end:
112         return ret;
113 }
114
115 int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
116 {
117         return vnt_control_in(priv, MESSAGE_TYPE_READ,
118                               reg_off, reg, sizeof(u8), data);
119 }
120
121 static void vnt_start_interrupt_urb_complete(struct urb *urb)
122 {
123         struct vnt_private *priv = urb->context;
124         int status = urb->status;
125
126         switch (status) {
127         case 0:
128         case -ETIMEDOUT:
129                 break;
130         case -ECONNRESET:
131         case -ENOENT:
132         case -ESHUTDOWN:
133                 priv->int_buf.in_use = false;
134                 return;
135         default:
136                 break;
137         }
138
139         if (status) {
140                 priv->int_buf.in_use = false;
141
142                 dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
143         } else {
144                 vnt_int_process_data(priv);
145         }
146
147         status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
148         if (status)
149                 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
150         else
151                 priv->int_buf.in_use = true;
152 }
153
154 int vnt_start_interrupt_urb(struct vnt_private *priv)
155 {
156         int ret = 0;
157
158         if (priv->int_buf.in_use) {
159                 ret = -EBUSY;
160                 goto err;
161         }
162
163         priv->int_buf.in_use = true;
164
165         usb_fill_int_urb(priv->interrupt_urb,
166                          priv->usb,
167                          usb_rcvintpipe(priv->usb, 1),
168                          priv->int_buf.data_buf,
169                          MAX_INTERRUPT_SIZE,
170                          vnt_start_interrupt_urb_complete,
171                          priv,
172                          priv->int_interval);
173
174         ret = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
175         if (ret) {
176                 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", ret);
177                 goto err_submit;
178         }
179
180         return 0;
181
182 err_submit:
183         priv->int_buf.in_use = false;
184 err:
185         return ret;
186 }
187
188 static void vnt_submit_rx_urb_complete(struct urb *urb)
189 {
190         struct vnt_rcb *rcb = urb->context;
191         struct vnt_private *priv = rcb->priv;
192
193         switch (urb->status) {
194         case 0:
195                 break;
196         case -ECONNRESET:
197         case -ENOENT:
198         case -ESHUTDOWN:
199                 return;
200         case -ETIMEDOUT:
201         default:
202                 dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
203                 break;
204         }
205
206         if (urb->actual_length) {
207                 if (vnt_rx_data(priv, rcb, urb->actual_length)) {
208                         rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
209                         if (!rcb->skb) {
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 ret = 0;
232         struct urb *urb = rcb->urb;
233
234         if (!rcb->skb) {
235                 dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
236                 ret = -EINVAL;
237                 goto end;
238         }
239
240         usb_fill_bulk_urb(urb,
241                           priv->usb,
242                           usb_rcvbulkpipe(priv->usb, 2),
243                           skb_put(rcb->skb, skb_tailroom(rcb->skb)),
244                           MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
245                           vnt_submit_rx_urb_complete,
246                           rcb);
247
248         ret = usb_submit_urb(urb, GFP_ATOMIC);
249         if (ret) {
250                 dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", ret);
251                 goto end;
252         }
253
254         rcb->in_use = true;
255
256 end:
257         return ret;
258 }
259
260 static void vnt_tx_context_complete(struct urb *urb)
261 {
262         struct vnt_usb_send_context *context = urb->context;
263         struct vnt_private *priv = context->priv;
264
265         switch (urb->status) {
266         case 0:
267                 dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
268                 break;
269         case -ECONNRESET:
270         case -ENOENT:
271         case -ESHUTDOWN:
272                 context->in_use = false;
273                 return;
274         case -ETIMEDOUT:
275         default:
276                 dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
277                 break;
278         }
279
280         if (context->type == CONTEXT_DATA_PACKET)
281                 ieee80211_wake_queues(priv->hw);
282
283         if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
284                 if (context->skb)
285                         ieee80211_free_txskb(priv->hw, context->skb);
286
287                 context->in_use = false;
288         }
289 }
290
291 int vnt_tx_context(struct vnt_private *priv,
292                    struct vnt_usb_send_context *context)
293 {
294         int status;
295         struct urb *urb = context->urb;
296
297         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
298                 context->in_use = false;
299                 return STATUS_RESOURCES;
300         }
301
302         usb_fill_bulk_urb(urb,
303                           priv->usb,
304                           usb_sndbulkpipe(priv->usb, 3),
305                           context->data,
306                           context->buf_len,
307                           vnt_tx_context_complete,
308                           context);
309
310         status = usb_submit_urb(urb, GFP_ATOMIC);
311         if (status) {
312                 dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
313
314                 context->in_use = false;
315                 return STATUS_FAILURE;
316         }
317
318         return STATUS_PENDING;
319 }