/*
* atusb.c - Driver for the ATUSB IEEE 802.15.4 dongle
*
* Written 2013 by Werner Almesberger <werner@almesberger.net>
*
* Copyright (c) 2015 - 2016 Stefan Schmidt <stefan@datenfreihafen.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2
*
* Based on at86rf230.c and spi_atusb.c.
* at86rf230.c is
* Copyright (C) 2009 Siemens AG
* Written by: Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
*
* spi_atusb.c is
* Copyright (c) 2011 Richard Sharpe <realrichardsharpe@gmail.com>
* Copyright (c) 2011 Stefan Schmidt <stefan@datenfreihafen.org>
* Copyright (c) 2011 Werner Almesberger <werner@almesberger.net>
*
* USB initialization is
* Copyright (c) 2013 Alexander Aring <alex.aring@gmail.com>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/usb.h>
#include <linux/skbuff.h>
#include <net/cfg802154.h>
#include <net/mac802154.h>
#include "at86rf230.h"
#include "atusb.h"
#define ATUSB_JEDEC_ATMEL 0x1f /* JEDEC manufacturer ID */
#define ATUSB_NUM_RX_URBS 4 /* allow for a bit of local latency */
#define ATUSB_ALLOC_DELAY_MS 100 /* delay after failed allocation */
#define ATUSB_TX_TIMEOUT_MS 200 /* on the air timeout */
struct atusb {
struct ieee802154_hw *hw;
struct usb_device *usb_dev;
int shutdown; /* non-zero if shutting down */
int err; /* set by first error */
/* RX variables */
struct delayed_work work; /* memory allocations */
struct usb_anchor idle_urbs; /* URBs waiting to be submitted */
struct usb_anchor rx_urbs; /* URBs waiting for reception */
/* TX variables */
struct usb_ctrlrequest tx_dr;
struct urb *tx_urb;
struct sk_buff *tx_skb;
uint8_t tx_ack_seq; /* current TX ACK sequence number */
/* Firmware variable */
unsigned char fw_ver_maj; /* Firmware major version number */
unsigned char fw_ver_min; /* Firmware minor version number */
unsigned char fw_hw_type; /* Firmware hardware type */
};
/* ----- USB commands without data ----------------------------------------- */
/* To reduce the number of error checks in the code, we record the first error
* in atusb->err and reject all subsequent requests until the error is cleared.
*/
static int atusb_control_msg(struct atusb *atusb, unsigned int pipe,
__u8 request, __u8 requesttype,
__u16 value, __u16 index,
void *data, __u16 size, int timeout)
{
struct usb_device *usb_dev = atusb->usb_dev;
int ret;
if (atusb->err)
return atusb->err;
ret = usb_control_msg(usb_dev, pipe, request, requesttype,
value, index, data, size, timeout);
if (ret < 0) {
atusb->err = ret;
dev_err(&usb_dev->dev,
"atusb_control_msg: req 0x%02x val 0x%x idx 0x%x, error %d\n",
request, value, index, ret);
}
return ret;
}
static int atusb_command(struct atusb *atusb, uint8_t cmd, uint8_t arg)
{
struct usb_device *usb_dev = atusb->usb_dev;
dev_dbg(&usb_dev->dev, "atusb_command: cmd = 0x%x\n", cmd);
return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0),
cmd, ATUSB_REQ_TO_DEV, arg, 0, NULL, 0, 1000);
}
static int atusb_write_reg(struct atusb *atusb, uint8_t reg, uint8_t value)
{
struct usb_device *usb_dev = atusb->usb_dev;
dev_dbg(&usb_dev->dev, "atusb_write_reg: 0x%02x <- 0x%02x\n",
reg, value);
return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0),
ATUSB_REG_WRITE, ATUSB_REQ_TO_DEV,
value, reg, NULL, 0, 1000);
}
static int atusb_read_reg(struct atusb *atusb, uint8_t reg)
{
struct usb_device *usb_dev = atusb->usb_dev;
int ret;
uint8_t *buffer;
uint8_t value;
buffer = kmalloc(1, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
dev_dbg(&usb_dev->dev, "atusb: reg = 0x%x\n", reg);
ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
ATUSB_REG_READ, ATUSB_REQ_FROM_DEV,
0, reg, buffer, 1, 1000);
if (ret >= 0) {
value = buffer[0];
kfree(buffer);
return value;
} else {
kfree(buffer);
return ret;
}
}
static int atusb_write_subreg(struct atusb *atusb, uint8_t reg, uint8_t mask,
uint8_t shift, uint8_t value)
{
struct usb_device *usb_dev = atusb->usb_dev;
uint8_t orig, tmp;
int ret = 0;
dev_dbg(&usb_dev->dev, "atusb_write_subreg: 0x%02x <- 0x%02x\n",
reg, value);
orig = atusb_read_reg(atusb, reg);
/* Write the value only into that part of the register which is allowed
* by the mask. All other bits stay as before.
*/
tmp = orig & ~mask;
tmp |= (value << shift) & mask