]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/vt6656/usbpipe.c
e9b6b21f742217ca8d289021ca582d7409a6e64d
[karo-tx-linux.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
51         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
52                 return STATUS_FAILURE;
53
54         mutex_lock(&priv->usb_lock);
55
56         status = usb_control_msg(priv->usb,
57                 usb_sndctrlpipe(priv->usb, 0), request, 0x40, value,
58                         index, buffer, length, USB_CTL_WAIT);
59
60         mutex_unlock(&priv->usb_lock);
61
62         if (status < (int)length)
63                 return STATUS_FAILURE;
64
65         return STATUS_SUCCESS;
66 }
67
68 void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
69 {
70         vnt_control_out(priv, MESSAGE_TYPE_WRITE,
71                                         reg_off, reg, sizeof(u8), &data);
72 }
73
74 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
75                 u16 index, u16 length, u8 *buffer)
76 {
77         int status;
78
79         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
80                 return STATUS_FAILURE;
81
82         mutex_lock(&priv->usb_lock);
83
84         status = usb_control_msg(priv->usb,
85                 usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value,
86                         index, buffer, length, USB_CTL_WAIT);
87
88         mutex_unlock(&priv->usb_lock);
89
90         if (status < (int)length)
91                 return STATUS_FAILURE;
92
93         return STATUS_SUCCESS;
94 }
95
96 void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
97 {
98         vnt_control_in(priv, MESSAGE_TYPE_READ,
99                         reg_off, reg, sizeof(u8), data);
100 }
101
102 static void vnt_start_interrupt_urb_complete(struct urb *urb)
103 {
104         struct vnt_private *priv = urb->context;
105         int status = urb->status;
106
107         switch (status) {
108         case 0:
109         case -ETIMEDOUT:
110                 break;
111         case -ECONNRESET:
112         case -ENOENT:
113         case -ESHUTDOWN:
114                 priv->int_buf.in_use = false;
115                 return;
116         default:
117                 break;
118         }
119
120         if (status) {
121                 priv->int_buf.in_use = false;
122
123                 dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
124         } else {
125                 vnt_int_process_data(priv);
126         }
127
128         status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
129         if (status)
130                 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
131         else
132                 priv->int_buf.in_use = true;
133 }
134
135 int vnt_start_interrupt_urb(struct vnt_private *priv)
136 {
137         int status = STATUS_FAILURE;
138
139         if (priv->int_buf.in_use)
140                 return STATUS_FAILURE;
141
142         priv->int_buf.in_use = true;
143
144         usb_fill_int_urb(priv->interrupt_urb,
145                          priv->usb,
146                          usb_rcvintpipe(priv->usb, 1),
147                          priv->int_buf.data_buf,
148                          MAX_INTERRUPT_SIZE,
149                          vnt_start_interrupt_urb_complete,
150                          priv,
151                          priv->int_interval);
152
153         status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
154         if (status) {
155                 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
156                 priv->int_buf.in_use = false;
157         }
158
159         return status;
160 }
161
162 static void vnt_submit_rx_urb_complete(struct urb *urb)
163 {
164         struct vnt_rcb *rcb = urb->context;
165         struct vnt_private *priv = rcb->priv;
166
167         switch (urb->status) {
168         case 0:
169                 break;
170         case -ECONNRESET:
171         case -ENOENT:
172         case -ESHUTDOWN:
173                 return;
174         case -ETIMEDOUT:
175         default:
176                 dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
177                 break;
178         }
179
180         if (urb->actual_length) {
181                 if (vnt_rx_data(priv, rcb, urb->actual_length)) {
182                         rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
183                         if (!rcb->skb) {
184                                 dev_dbg(&priv->usb->dev,
185                                         "Failed to re-alloc rx skb\n");
186
187                                 rcb->in_use = false;
188                                 return;
189                         }
190                 } else {
191                         skb_push(rcb->skb, skb_headroom(rcb->skb));
192                         skb_trim(rcb->skb, 0);
193                 }
194
195                 urb->transfer_buffer = skb_put(rcb->skb,
196                                                 skb_tailroom(rcb->skb));
197         }
198
199         if (usb_submit_urb(urb, GFP_ATOMIC)) {
200                 dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
201
202                 rcb->in_use = false;
203         }
204 }
205
206 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
207 {
208         int status = 0;
209         struct urb *urb = rcb->urb;
210
211         if (!rcb->skb) {
212                 dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
213                 return status;
214         }
215
216         usb_fill_bulk_urb(urb,
217                           priv->usb,
218                           usb_rcvbulkpipe(priv->usb, 2),
219                           skb_put(rcb->skb, skb_tailroom(rcb->skb)),
220                           MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
221                           vnt_submit_rx_urb_complete,
222                           rcb);
223
224         status = usb_submit_urb(urb, GFP_ATOMIC);
225         if (status) {
226                 dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
227                 return STATUS_FAILURE;
228         }
229
230         rcb->in_use = true;
231
232         return status;
233 }
234
235 static void vnt_tx_context_complete(struct urb *urb)
236 {
237         struct vnt_usb_send_context *context = urb->context;
238         struct vnt_private *priv = context->priv;
239
240         switch (urb->status) {
241         case 0:
242                 dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
243                 break;
244         case -ECONNRESET:
245         case -ENOENT:
246         case -ESHUTDOWN:
247                 context->in_use = false;
248                 return;
249         case -ETIMEDOUT:
250         default:
251                 dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
252                 break;
253         }
254
255         if (context->type == CONTEXT_DATA_PACKET)
256                 ieee80211_wake_queues(priv->hw);
257
258         if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
259                 if (context->skb)
260                         ieee80211_free_txskb(priv->hw, context->skb);
261
262                 context->in_use = false;
263         }
264 }
265
266 int vnt_tx_context(struct vnt_private *priv,
267                    struct vnt_usb_send_context *context)
268 {
269         int status;
270         struct urb *urb = context->urb;
271
272         if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
273                 context->in_use = false;
274                 return STATUS_RESOURCES;
275         }
276
277         usb_fill_bulk_urb(urb,
278                           priv->usb,
279                           usb_sndbulkpipe(priv->usb, 3),
280                           context->data,
281                           context->buf_len,
282                           vnt_tx_context_complete,
283                           context);
284
285         status = usb_submit_urb(urb, GFP_ATOMIC);
286         if (status) {
287                 dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
288
289                 context->in_use = false;
290                 return STATUS_FAILURE;
291         }
292
293         return STATUS_PENDING;
294 }