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