Commit | Line | Data |
---|---|---|
92b96797 FB |
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 | * | |
92b96797 FB |
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: | |
1390b02a | 25 | * vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM |
441c21c3 | 26 | * vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM |
285d58c4 | 27 | * vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM |
53742906 | 28 | * vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM |
92b96797 FB |
29 | * |
30 | * Revision History: | |
3b1d7533 AJ |
31 | * 04-05-2004 Jerry Chen: Initial release |
32 | * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte, | |
33 | * ControlvMaskByte | |
92b96797 FB |
34 | * |
35 | */ | |
36 | ||
92b96797 | 37 | #include "int.h" |
92b96797 | 38 | #include "rxtx.h" |
92b96797 | 39 | #include "dpc.h" |
92b96797 | 40 | #include "desc.h" |
92b96797 | 41 | #include "device.h" |
62c8526d | 42 | #include "usbpipe.h" |
92b96797 | 43 | |
b2435179 | 44 | #define USB_CTL_WAIT 500 /* ms */ |
92b96797 | 45 | |
1390b02a | 46 | int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, |
0f06a739 | 47 | u16 index, u16 length, u8 *buffer) |
92b96797 | 48 | { |
0f06a739 | 49 | int status = 0; |
92b96797 | 50 | |
cbcc9a36 | 51 | if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) |
e1feda13 MP |
52 | return STATUS_FAILURE; |
53 | ||
0f06a739 | 54 | mutex_lock(&priv->usb_lock); |
c91b1869 | 55 | |
0f06a739 MP |
56 | status = usb_control_msg(priv->usb, |
57 | usb_sndctrlpipe(priv->usb, 0), request, 0x40, value, | |
58 | index, buffer, length, USB_CTL_WAIT); | |
ae5943de | 59 | |
0f06a739 | 60 | mutex_unlock(&priv->usb_lock); |
92b96797 | 61 | |
0f06a739 | 62 | if (status < (int)length) |
92b96797 | 63 | return STATUS_FAILURE; |
ae5943de | 64 | |
7021b684 | 65 | return STATUS_SUCCESS; |
92b96797 FB |
66 | } |
67 | ||
285d58c4 MP |
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 | ||
441c21c3 | 74 | int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, |
9af49fdb | 75 | u16 index, u16 length, u8 *buffer) |
92b96797 | 76 | { |
9af49fdb | 77 | int status; |
731047f9 | 78 | |
cbcc9a36 | 79 | if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) |
e1feda13 | 80 | return STATUS_FAILURE; |
ae5943de | 81 | |
9af49fdb | 82 | mutex_lock(&priv->usb_lock); |
c91b1869 | 83 | |
9af49fdb MP |
84 | status = usb_control_msg(priv->usb, |
85 | usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value, | |
86 | index, buffer, length, USB_CTL_WAIT); | |
92b96797 | 87 | |
9af49fdb | 88 | mutex_unlock(&priv->usb_lock); |
c91b1869 | 89 | |
9af49fdb | 90 | if (status < (int)length) |
0fb2af35 | 91 | return STATUS_FAILURE; |
fe5d00eb | 92 | |
0fb2af35 | 93 | return STATUS_SUCCESS; |
92b96797 FB |
94 | } |
95 | ||
53742906 MP |
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 | ||
34f98e3f | 102 | static void vnt_start_interrupt_urb_complete(struct urb *urb) |
92b96797 | 103 | { |
599e4b5c | 104 | struct vnt_private *priv = urb->context; |
b9183fdd | 105 | int status = urb->status; |
92b96797 | 106 | |
b9183fdd | 107 | switch (status) { |
c98fbf90 MP |
108 | case 0: |
109 | case -ETIMEDOUT: | |
110 | break; | |
111 | case -ECONNRESET: | |
112 | case -ENOENT: | |
113 | case -ESHUTDOWN: | |
f764e00d | 114 | priv->int_buf.in_use = false; |
c98fbf90 MP |
115 | return; |
116 | default: | |
117 | break; | |
118 | } | |
119 | ||
7aa47db9 | 120 | if (status) { |
f764e00d | 121 | priv->int_buf.in_use = false; |
92b96797 | 122 | |
8a660261 | 123 | dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status); |
d9ad7a98 | 124 | } else { |
e360d2b8 | 125 | vnt_int_process_data(priv); |
d9ad7a98 | 126 | } |
92b96797 | 127 | |
3d582487 | 128 | status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); |
86140346 | 129 | if (status) |
8a660261 | 130 | dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); |
86140346 | 131 | else |
f764e00d | 132 | priv->int_buf.in_use = true; |
92b96797 FB |
133 | } |
134 | ||
eaa56792 MP |
135 | int vnt_start_interrupt_urb(struct vnt_private *priv) |
136 | { | |
137 | int status = STATUS_FAILURE; | |
138 | ||
5699c0f4 | 139 | if (priv->int_buf.in_use) |
eaa56792 MP |
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 | ||
08823af4 | 162 | static void vnt_submit_rx_urb_complete(struct urb *urb) |
92b96797 | 163 | { |
599e4b5c | 164 | struct vnt_rcb *rcb = urb->context; |
325de984 | 165 | struct vnt_private *priv = rcb->priv; |
92b96797 | 166 | |
67638980 MP |
167 | switch (urb->status) { |
168 | case 0: | |
67638980 MP |
169 | break; |
170 | case -ECONNRESET: | |
171 | case -ENOENT: | |
172 | case -ESHUTDOWN: | |
173 | return; | |
174 | case -ETIMEDOUT: | |
175 | default: | |
8a660261 | 176 | dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status); |
67638980 MP |
177 | break; |
178 | } | |
92b96797 | 179 | |
d4fa2ab0 | 180 | if (urb->actual_length) { |
f5283274 MP |
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"); | |
d4fa2ab0 | 186 | |
325de984 | 187 | rcb->in_use = false; |
f5283274 MP |
188 | return; |
189 | } | |
618ff9ce MP |
190 | } else { |
191 | skb_push(rcb->skb, skb_headroom(rcb->skb)); | |
192 | skb_trim(rcb->skb, 0); | |
8cffb3cf | 193 | } |
d4fa2ab0 | 194 | |
8cffb3cf MP |
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 | ||
325de984 | 202 | rcb->in_use = false; |
d4fa2ab0 | 203 | } |
92b96797 FB |
204 | } |
205 | ||
93eac3b1 MP |
206 | int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb) |
207 | { | |
208 | int status = 0; | |
b9183fdd | 209 | struct urb *urb = rcb->urb; |
93eac3b1 | 210 | |
27f31cf9 | 211 | if (!rcb->skb) { |
93eac3b1 MP |
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); | |
7aa47db9 | 225 | if (status) { |
93eac3b1 MP |
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 | ||
ceebd903 | 235 | static void vnt_tx_context_complete(struct urb *urb) |
92b96797 | 236 | { |
599e4b5c | 237 | struct vnt_usb_send_context *context = urb->context; |
30a05b39 | 238 | struct vnt_private *priv = context->priv; |
92b96797 | 239 | |
e8152bfb MP |
240 | switch (urb->status) { |
241 | case 0: | |
8a660261 | 242 | dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len); |
e8152bfb MP |
243 | break; |
244 | case -ECONNRESET: | |
245 | case -ENOENT: | |
246 | case -ESHUTDOWN: | |
30a05b39 | 247 | context->in_use = false; |
e8152bfb | 248 | return; |
d1b2a11d | 249 | case -ETIMEDOUT: |
e8152bfb | 250 | default: |
8a660261 | 251 | dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status); |
e8152bfb MP |
252 | break; |
253 | } | |
254 | ||
d38b13aa MP |
255 | if (context->type == CONTEXT_DATA_PACKET) |
256 | ieee80211_wake_queues(priv->hw); | |
21aa212c | 257 | |
71d764ae MP |
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 | } | |
92b96797 | 264 | } |
664b044b MP |
265 | |
266 | int vnt_tx_context(struct vnt_private *priv, | |
267 | struct vnt_usb_send_context *context) | |
268 | { | |
269 | int status; | |
b9183fdd | 270 | struct urb *urb = context->urb; |
664b044b | 271 | |
cbcc9a36 | 272 | if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { |
664b044b MP |
273 | context->in_use = false; |
274 | return STATUS_RESOURCES; | |
275 | } | |
276 | ||
664b044b MP |
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); | |
7aa47db9 | 286 | if (status) { |
664b044b MP |
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 | } |