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 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * 20 * File: usbpipe.c 21 * 22 * Purpose: Handle USB control endpoint 23 * 24 * Author: Warren Hsu 25 * 26 * Date: Mar. 29, 2005 27 * 28 * Functions: 29 * vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM 30 * vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM 31 * vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM 32 * vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM 33 * 34 * Revision History: 35 * 04-05-2004 Jerry Chen: Initial release 36 * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,ControlvMaskByte 37 * 38 */ 39 40#include "int.h" 41#include "rxtx.h" 42#include "dpc.h" 43#include "desc.h" 44#include "device.h" 45#include "usbpipe.h" 46 47#define USB_CTL_WAIT 500 /* ms */ 48 49int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, 50 u16 index, u16 length, u8 *buffer) 51{ 52 int status = 0; 53 54 if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) 55 return STATUS_FAILURE; 56 57 mutex_lock(&priv->usb_lock); 58 59 status = usb_control_msg(priv->usb, 60 usb_sndctrlpipe(priv->usb, 0), request, 0x40, value, 61 index, buffer, length, USB_CTL_WAIT); 62 63 mutex_unlock(&priv->usb_lock); 64 65 if (status < (int)length) 66 return STATUS_FAILURE; 67 68 return STATUS_SUCCESS; 69} 70 71void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data) 72{ 73 vnt_control_out(priv, MESSAGE_TYPE_WRITE, 74 reg_off, reg, sizeof(u8), &data); 75} 76 77int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, 78 u16 index, u16 length, u8 *buffer) 79{ 80 int status; 81 82 if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) 83 return STATUS_FAILURE; 84 85 mutex_lock(&priv->usb_lock); 86 87 status = usb_control_msg(priv->usb, 88 usb_rcvctrlpipe(priv->usb, 0), request, 0xc0, value, 89 index, buffer, length, USB_CTL_WAIT); 90 91 mutex_unlock(&priv->usb_lock); 92 93 if (status < (int)length) 94 return STATUS_FAILURE; 95 96 return STATUS_SUCCESS; 97} 98 99void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data) 100{ 101 vnt_control_in(priv, MESSAGE_TYPE_READ, 102 reg_off, reg, sizeof(u8), data); 103} 104 105static void vnt_start_interrupt_urb_complete(struct urb *urb) 106{ 107 struct vnt_private *priv = urb->context; 108 int status; 109 110 switch (urb->status) { 111 case 0: 112 case -ETIMEDOUT: 113 break; 114 case -ECONNRESET: 115 case -ENOENT: 116 case -ESHUTDOWN: 117 priv->int_buf.in_use = false; 118 return; 119 default: 120 break; 121 } 122 123 status = urb->status; 124 125 if (status != STATUS_SUCCESS) { 126 priv->int_buf.in_use = false; 127 128 dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status); 129 } else { 130 vnt_int_process_data(priv); 131 } 132 133 status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); 134 if (status) 135 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); 136 else 137 priv->int_buf.in_use = true; 138} 139 140int vnt_start_interrupt_urb(struct vnt_private *priv) 141{ 142 int status = STATUS_FAILURE; 143 144 if (priv->int_buf.in_use == true) 145 return STATUS_FAILURE; 146 147 priv->int_buf.in_use = true; 148 149 usb_fill_int_urb(priv->interrupt_urb, 150 priv->usb, 151 usb_rcvintpipe(priv->usb, 1), 152 priv->int_buf.data_buf, 153 MAX_INTERRUPT_SIZE, 154 vnt_start_interrupt_urb_complete, 155 priv, 156 priv->int_interval); 157 158 status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); 159 if (status) { 160 dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); 161 priv->int_buf.in_use = false; 162 } 163 164 return status; 165} 166 167static void vnt_submit_rx_urb_complete(struct urb *urb) 168{ 169 struct vnt_rcb *rcb = urb->context; 170 struct vnt_private *priv = rcb->priv; 171 unsigned long flags; 172 173 switch (urb->status) { 174 case 0: 175 break; 176 case -ECONNRESET: 177 case -ENOENT: 178 case -ESHUTDOWN: 179 return; 180 case -ETIMEDOUT: 181 default: 182 dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status); 183 break; 184 } 185 186 if (urb->actual_length) { 187 spin_lock_irqsave(&priv->lock, flags); 188 189 if (vnt_rx_data(priv, rcb, urb->actual_length)) { 190 rcb->skb = dev_alloc_skb(priv->rx_buf_sz); 191 if (!rcb->skb) { 192 dev_dbg(&priv->usb->dev, 193 "Failed to re-alloc rx skb\n"); 194 195 rcb->in_use = false; 196 spin_unlock_irqrestore(&priv->lock, flags); 197 return; 198 } 199 } else { 200 skb_push(rcb->skb, skb_headroom(rcb->skb)); 201 skb_trim(rcb->skb, 0); 202 } 203 204 urb->transfer_buffer = skb_put(rcb->skb, 205 skb_tailroom(rcb->skb)); 206 207 spin_unlock_irqrestore(&priv->lock, flags); 208 } 209 210 if (usb_submit_urb(urb, GFP_ATOMIC)) { 211 dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n"); 212 213 rcb->in_use = false; 214 } 215} 216 217int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb) 218{ 219 int status = 0; 220 struct urb *urb; 221 222 urb = rcb->urb; 223 if (rcb->skb == NULL) { 224 dev_dbg(&priv->usb->dev, "rcb->skb is null\n"); 225 return status; 226 } 227 228 usb_fill_bulk_urb(urb, 229 priv->usb, 230 usb_rcvbulkpipe(priv->usb, 2), 231 skb_put(rcb->skb, skb_tailroom(rcb->skb)), 232 MAX_TOTAL_SIZE_WITH_ALL_HEADERS, 233 vnt_submit_rx_urb_complete, 234 rcb); 235 236 status = usb_submit_urb(urb, GFP_ATOMIC); 237 if (status != 0) { 238 dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status); 239 return STATUS_FAILURE; 240 } 241 242 rcb->in_use = true; 243 244 return status; 245} 246 247static void vnt_tx_context_complete(struct urb *urb) 248{ 249 struct vnt_usb_send_context *context = urb->context; 250 struct vnt_private *priv = context->priv; 251 252 switch (urb->status) { 253 case 0: 254 dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len); 255 break; 256 case -ECONNRESET: 257 case -ENOENT: 258 case -ESHUTDOWN: 259 context->in_use = false; 260 return; 261 case -ETIMEDOUT: 262 default: 263 dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status); 264 break; 265 } 266 267 if (context->type == CONTEXT_DATA_PACKET) 268 ieee80211_wake_queues(priv->hw); 269 270 if (urb->status || context->type == CONTEXT_BEACON_PACKET) { 271 if (context->skb) 272 ieee80211_free_txskb(priv->hw, context->skb); 273 274 context->in_use = false; 275 } 276} 277 278int vnt_tx_context(struct vnt_private *priv, 279 struct vnt_usb_send_context *context) 280{ 281 int status; 282 struct urb *urb; 283 284 if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { 285 context->in_use = false; 286 return STATUS_RESOURCES; 287 } 288 289 urb = context->urb; 290 291 usb_fill_bulk_urb(urb, 292 priv->usb, 293 usb_sndbulkpipe(priv->usb, 3), 294 context->data, 295 context->buf_len, 296 vnt_tx_context_complete, 297 context); 298 299 status = usb_submit_urb(urb, GFP_ATOMIC); 300 if (status != 0) { 301 dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status); 302 303 context->in_use = false; 304 return STATUS_FAILURE; 305 } 306 307 return STATUS_PENDING; 308} 309