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