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 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
  68void 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
  74int 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
 109void 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
 115static 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
 148int 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
 175static 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                                rcb->in_use = false;
 198                                return;
 199                        }
 200                } else {
 201                        skb_push(rcb->skb, skb_headroom(rcb->skb));
 202                        skb_trim(rcb->skb, 0);
 203                }
 204
 205                urb->transfer_buffer = skb_put(rcb->skb,
 206                                                skb_tailroom(rcb->skb));
 207        }
 208
 209        if (usb_submit_urb(urb, GFP_ATOMIC)) {
 210                dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
 211
 212                rcb->in_use = false;
 213        }
 214}
 215
 216int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
 217{
 218        int status = 0;
 219        struct urb *urb = rcb->urb;
 220
 221        if (!rcb->skb) {
 222                dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
 223                return status;
 224        }
 225
 226        usb_fill_bulk_urb(urb,
 227                          priv->usb,
 228                          usb_rcvbulkpipe(priv->usb, 2),
 229                          skb_put(rcb->skb, skb_tailroom(rcb->skb)),
 230                          MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
 231                          vnt_submit_rx_urb_complete,
 232                          rcb);
 233
 234        status = usb_submit_urb(urb, GFP_ATOMIC);
 235        if (status) {
 236                dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
 237                return STATUS_FAILURE;
 238        }
 239
 240        rcb->in_use = true;
 241
 242        return status;
 243}
 244
 245static void vnt_tx_context_complete(struct urb *urb)
 246{
 247        struct vnt_usb_send_context *context = urb->context;
 248        struct vnt_private *priv = context->priv;
 249
 250        switch (urb->status) {
 251        case 0:
 252                dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
 253                break;
 254        case -ECONNRESET:
 255        case -ENOENT:
 256        case -ESHUTDOWN:
 257                context->in_use = false;
 258                return;
 259        case -ETIMEDOUT:
 260        default:
 261                dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
 262                break;
 263        }
 264
 265        if (context->type == CONTEXT_DATA_PACKET)
 266                ieee80211_wake_queues(priv->hw);
 267
 268        if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
 269                if (context->skb)
 270                        ieee80211_free_txskb(priv->hw, context->skb);
 271
 272                context->in_use = false;
 273        }
 274}
 275
 276int vnt_tx_context(struct vnt_private *priv,
 277                   struct vnt_usb_send_context *context)
 278{
 279        int status;
 280        struct urb *urb = context->urb;
 281
 282        if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
 283                context->in_use = false;
 284                return STATUS_RESOURCES;
 285        }
 286
 287        usb_fill_bulk_urb(urb,
 288                          priv->usb,
 289                          usb_sndbulkpipe(priv->usb, 3),
 290                          context->data,
 291                          context->buf_len,
 292                          vnt_tx_context_complete,
 293                          context);
 294
 295        status = usb_submit_urb(urb, GFP_ATOMIC);
 296        if (status) {
 297                dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
 298
 299                context->in_use = false;
 300                return STATUS_FAILURE;
 301        }
 302
 303        return STATUS_PENDING;
 304}
 305