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: | |
31 | * 04-05-2004 Jerry Chen: Initial release | |
32 | * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,ControlvMaskByte | |
33 | * | |
34 | */ | |
35 | ||
92b96797 | 36 | #include "int.h" |
92b96797 | 37 | #include "rxtx.h" |
92b96797 | 38 | #include "dpc.h" |
92b96797 | 39 | #include "desc.h" |
92b96797 | 40 | #include "device.h" |
62c8526d | 41 | #include "usbpipe.h" |
92b96797 | 42 | |
b2435179 | 43 | #define USB_CTL_WAIT 500 /* ms */ |
92b96797 | 44 | |
1390b02a | 45 | int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, |
0f06a739 | 46 | u16 index, u16 length, u8 *buffer) |
92b96797 | 47 | { |
0f06a739 | 48 | int status = 0; |
92b96797 | 49 | |
cbcc9a36 | 50 | if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) |
e1feda13 MP |
51 | return STATUS_FAILURE; |
52 | ||
0f06a739 | 53 | mutex_lock(&priv->usb_lock); |
c91b1869 | 54 | |
0f06a739 MP |
55 | status = usb_control_msg(priv->usb, |
56 | usb_sndctrlpipe(priv->usb, 0), request, 0x40, value, | |
57 | index, buffer, length, USB_CTL_WAIT); | |
ae5943de | 58 | |
0f06a739 | 59 | mutex_unlock(&priv->usb_lock); |
92b96797 | 60 | |
0f06a739 | 61 | if (status < (int)length) |
92b96797 | 62 | return STATUS_FAILURE; |
ae5943de | 63 | |
7021b684 | 64 | return STATUS_SUCCESS; |
92b96797 FB |
65 | } |
66 | ||
285d58c4 MP |
67 | void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data) |
68 | { | |
69 | vnt_control_out(priv, MESSAGE_TYPE_WRITE, | |
70 | reg_off, reg, sizeof(u8), &data); | |
71 | } | |
72 | ||
441c21c3 | 73 | int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, |
9af49fdb | 74 | u16 index, u16 length, u8 *buffer) |
92b96797 | 75 | { |
9af49fdb | 76 | int status; |
731047f9 | 77 | |
cbcc9a36 | 78 | if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) |
e1feda13 | 79 | return STATUS_FAILURE; |
ae5943de | 80 | |
9af49fdb | 81 | mutex_lock(&priv->usb_lock); |
c91b1869 | 82 | |
9af49fdb MP |
83 | status = usb_control_msg(priv->usb, |
84 | usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value, | |
85 | index, buffer, length, USB_CTL_WAIT); | |
92b96797 | 86 | |
9af49fdb | 87 | mutex_unlock(&priv->usb_lock); |
c91b1869 | 88 | |
9af49fdb | 89 | if (status < (int)length) |
0fb2af35 | 90 | return STATUS_FAILURE; |
fe5d00eb | 91 | |
0fb2af35 | 92 | return STATUS_SUCCESS; |
92b96797 FB |
93 | } |
94 | ||
53742906 MP |
95 | void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data) |
96 | { | |
97 | vnt_control_in(priv, MESSAGE_TYPE_READ, | |
98 | reg_off, reg, sizeof(u8), data); | |
99 | } | |
100 | ||
34f98e3f | 101 | static void vnt_start_interrupt_urb_complete(struct urb *urb) |
92b96797 | 102 | { |
599e4b5c | 103 | struct vnt_private *priv = urb->context; |
b9183fdd | 104 | int status = urb->status; |
92b96797 | 105 | |
b9183fdd | 106 | switch (status) { |
c98fbf90 MP |
107 | case 0: |
108 | case -ETIMEDOUT: | |
109 | break; | |
110 | case -ECONNRESET: | |
111 | case -ENOENT: | |
112 | case -ESHUTDOWN: | |
f764e00d | 113 | priv->int_buf.in_use = false; |
c98fbf90 MP |
114 | return; |
115 | default: | |
116 | break; | |
117 | } | |
118 | ||
7aa47db9 | 119 | if (status) { |
f764e00d | 120 | priv->int_buf.in_use = false; |
92b96797 | 121 | |
8a660261 | 122 | dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status); |
d9ad7a98 | 123 | } else { |
e360d2b8 | 124 | vnt_int_process_data(priv); |
d9ad7a98 | 125 | } |
92b96797 | 126 | |
3d582487 | 127 | status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); |
86140346 | 128 | if (status) |
8a660261 | 129 | dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); |
86140346 | 130 | else |
f764e00d | 131 | priv->int_buf.in_use = true; |
92b96797 FB |
132 | } |
133 | ||
eaa56792 MP |
134 | int vnt_start_interrupt_urb(struct vnt_private *priv) |
135 | { | |
136 | int status = STATUS_FAILURE; | |
137 | ||
5699c0f4 | 138 | if (priv->int_buf.in_use) |
eaa56792 MP |
139 | return STATUS_FAILURE; |
140 | ||
141 | priv->int_buf.in_use = true; | |
142 | ||
143 | usb_fill_int_urb(priv->interrupt_urb, | |
144 | priv->usb, | |
145 | usb_rcvintpipe(priv->usb, 1), | |
146 | priv->int_buf.data_buf, | |
147 | MAX_INTERRUPT_SIZE, | |
148 | vnt_start_interrupt_urb_complete, | |
149 | priv, | |
150 | priv->int_interval); | |
151 | ||
152 | status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); | |
153 | if (status) { | |
154 | dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); | |
155 | priv->int_buf.in_use = false; | |
156 | } | |
157 | ||
158 | return status; | |
159 | } | |
160 | ||
08823af4 | 161 | static void vnt_submit_rx_urb_complete(struct urb *urb) |
92b96797 | 162 | { |
599e4b5c | 163 | struct vnt_rcb *rcb = urb->context; |
325de984 | 164 | struct vnt_private *priv = rcb->priv; |
92b96797 | 165 | |
67638980 MP |
166 | switch (urb->status) { |
167 | case 0: | |
67638980 MP |
168 | break; |
169 | case -ECONNRESET: | |
170 | case -ENOENT: | |
171 | case -ESHUTDOWN: | |
172 | return; | |
173 | case -ETIMEDOUT: | |
174 | default: | |
8a660261 | 175 | dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status); |
67638980 MP |
176 | break; |
177 | } | |
92b96797 | 178 | |
d4fa2ab0 | 179 | if (urb->actual_length) { |
f5283274 MP |
180 | if (vnt_rx_data(priv, rcb, urb->actual_length)) { |
181 | rcb->skb = dev_alloc_skb(priv->rx_buf_sz); | |
182 | if (!rcb->skb) { | |
183 | dev_dbg(&priv->usb->dev, | |
184 | "Failed to re-alloc rx skb\n"); | |
d4fa2ab0 | 185 | |
325de984 | 186 | rcb->in_use = false; |
f5283274 MP |
187 | return; |
188 | } | |
618ff9ce MP |
189 | } else { |
190 | skb_push(rcb->skb, skb_headroom(rcb->skb)); | |
191 | skb_trim(rcb->skb, 0); | |
8cffb3cf | 192 | } |
d4fa2ab0 | 193 | |
8cffb3cf MP |
194 | urb->transfer_buffer = skb_put(rcb->skb, |
195 | skb_tailroom(rcb->skb)); | |
196 | } | |
197 | ||
198 | if (usb_submit_urb(urb, GFP_ATOMIC)) { | |
199 | dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n"); | |
200 | ||
325de984 | 201 | rcb->in_use = false; |
d4fa2ab0 | 202 | } |
92b96797 FB |
203 | } |
204 | ||
93eac3b1 MP |
205 | int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb) |
206 | { | |
207 | int status = 0; | |
b9183fdd | 208 | struct urb *urb = rcb->urb; |
93eac3b1 | 209 | |
27f31cf9 | 210 | if (!rcb->skb) { |
93eac3b1 MP |
211 | dev_dbg(&priv->usb->dev, "rcb->skb is null\n"); |
212 | return status; | |
213 | } | |
214 | ||
215 | usb_fill_bulk_urb(urb, | |
216 | priv->usb, | |
217 | usb_rcvbulkpipe(priv->usb, 2), | |
218 | skb_put(rcb->skb, skb_tailroom(rcb->skb)), | |
219 | MAX_TOTAL_SIZE_WITH_ALL_HEADERS, | |
220 | vnt_submit_rx_urb_complete, | |
221 | rcb); | |
222 | ||
223 | status = usb_submit_urb(urb, GFP_ATOMIC); | |
7aa47db9 | 224 | if (status) { |
93eac3b1 MP |
225 | dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status); |
226 | return STATUS_FAILURE; | |
227 | } | |
228 | ||
229 | rcb->in_use = true; | |
230 | ||
231 | return status; | |
232 | } | |
233 | ||
ceebd903 | 234 | static void vnt_tx_context_complete(struct urb *urb) |
92b96797 | 235 | { |
599e4b5c | 236 | struct vnt_usb_send_context *context = urb->context; |
30a05b39 | 237 | struct vnt_private *priv = context->priv; |
92b96797 | 238 | |
e8152bfb MP |
239 | switch (urb->status) { |
240 | case 0: | |
8a660261 | 241 | dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len); |
e8152bfb MP |
242 | break; |
243 | case -ECONNRESET: | |
244 | case -ENOENT: | |
245 | case -ESHUTDOWN: | |
30a05b39 | 246 | context->in_use = false; |
e8152bfb | 247 | return; |
d1b2a11d | 248 | case -ETIMEDOUT: |
e8152bfb | 249 | default: |
8a660261 | 250 | dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status); |
e8152bfb MP |
251 | break; |
252 | } | |
253 | ||
d38b13aa MP |
254 | if (context->type == CONTEXT_DATA_PACKET) |
255 | ieee80211_wake_queues(priv->hw); | |
21aa212c | 256 | |
71d764ae MP |
257 | if (urb->status || context->type == CONTEXT_BEACON_PACKET) { |
258 | if (context->skb) | |
259 | ieee80211_free_txskb(priv->hw, context->skb); | |
260 | ||
261 | context->in_use = false; | |
262 | } | |
92b96797 | 263 | } |
664b044b MP |
264 | |
265 | int vnt_tx_context(struct vnt_private *priv, | |
266 | struct vnt_usb_send_context *context) | |
267 | { | |
268 | int status; | |
b9183fdd | 269 | struct urb *urb = context->urb; |
664b044b | 270 | |
cbcc9a36 | 271 | if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { |
664b044b MP |
272 | context->in_use = false; |
273 | return STATUS_RESOURCES; | |
274 | } | |
275 | ||
664b044b MP |
276 | usb_fill_bulk_urb(urb, |
277 | priv->usb, | |
278 | usb_sndbulkpipe(priv->usb, 3), | |
279 | context->data, | |
280 | context->buf_len, | |
281 | vnt_tx_context_complete, | |
282 | context); | |
283 | ||
284 | status = usb_submit_urb(urb, GFP_ATOMIC); | |
7aa47db9 | 285 | if (status) { |
664b044b MP |
286 | dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status); |
287 | ||
288 | context->in_use = false; | |
289 | return STATUS_FAILURE; | |
290 | } | |
291 | ||
292 | return STATUS_PENDING; | |
293 | } |