18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * atusb.c - Driver for the ATUSB IEEE 802.15.4 dongle 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written 2013 by Werner Almesberger <werner@almesberger.net> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2015 - 2016 Stefan Schmidt <stefan@datenfreihafen.org> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on at86rf230.c and spi_atusb.c. 108c2ecf20Sopenharmony_ci * at86rf230.c is 118c2ecf20Sopenharmony_ci * Copyright (C) 2009 Siemens AG 128c2ecf20Sopenharmony_ci * Written by: Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * spi_atusb.c is 158c2ecf20Sopenharmony_ci * Copyright (c) 2011 Richard Sharpe <realrichardsharpe@gmail.com> 168c2ecf20Sopenharmony_ci * Copyright (c) 2011 Stefan Schmidt <stefan@datenfreihafen.org> 178c2ecf20Sopenharmony_ci * Copyright (c) 2011 Werner Almesberger <werner@almesberger.net> 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * USB initialization is 208c2ecf20Sopenharmony_ci * Copyright (c) 2013 Alexander Aring <alex.aring@gmail.com> 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Busware HUL support is 238c2ecf20Sopenharmony_ci * Copyright (c) 2017 Josef Filzmaier <j.filzmaier@gmx.at> 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 308c2ecf20Sopenharmony_ci#include <linux/usb.h> 318c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <net/cfg802154.h> 348c2ecf20Sopenharmony_ci#include <net/mac802154.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "at86rf230.h" 378c2ecf20Sopenharmony_ci#include "atusb.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define ATUSB_JEDEC_ATMEL 0x1f /* JEDEC manufacturer ID */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define ATUSB_NUM_RX_URBS 4 /* allow for a bit of local latency */ 428c2ecf20Sopenharmony_ci#define ATUSB_ALLOC_DELAY_MS 100 /* delay after failed allocation */ 438c2ecf20Sopenharmony_ci#define ATUSB_TX_TIMEOUT_MS 200 /* on the air timeout */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct atusb { 468c2ecf20Sopenharmony_ci struct ieee802154_hw *hw; 478c2ecf20Sopenharmony_ci struct usb_device *usb_dev; 488c2ecf20Sopenharmony_ci struct atusb_chip_data *data; 498c2ecf20Sopenharmony_ci int shutdown; /* non-zero if shutting down */ 508c2ecf20Sopenharmony_ci int err; /* set by first error */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* RX variables */ 538c2ecf20Sopenharmony_ci struct delayed_work work; /* memory allocations */ 548c2ecf20Sopenharmony_ci struct usb_anchor idle_urbs; /* URBs waiting to be submitted */ 558c2ecf20Sopenharmony_ci struct usb_anchor rx_urbs; /* URBs waiting for reception */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* TX variables */ 588c2ecf20Sopenharmony_ci struct usb_ctrlrequest tx_dr; 598c2ecf20Sopenharmony_ci struct urb *tx_urb; 608c2ecf20Sopenharmony_ci struct sk_buff *tx_skb; 618c2ecf20Sopenharmony_ci u8 tx_ack_seq; /* current TX ACK sequence number */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Firmware variable */ 648c2ecf20Sopenharmony_ci unsigned char fw_ver_maj; /* Firmware major version number */ 658c2ecf20Sopenharmony_ci unsigned char fw_ver_min; /* Firmware minor version number */ 668c2ecf20Sopenharmony_ci unsigned char fw_hw_type; /* Firmware hardware type */ 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct atusb_chip_data { 708c2ecf20Sopenharmony_ci u16 t_channel_switch; 718c2ecf20Sopenharmony_ci int rssi_base_val; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci int (*set_channel)(struct ieee802154_hw*, u8, u8); 748c2ecf20Sopenharmony_ci int (*set_txpower)(struct ieee802154_hw*, s32); 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* ----- USB commands without data ----------------------------------------- */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* To reduce the number of error checks in the code, we record the first error 808c2ecf20Sopenharmony_ci * in atusb->err and reject all subsequent requests until the error is cleared. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int atusb_control_msg(struct atusb *atusb, unsigned int pipe, 848c2ecf20Sopenharmony_ci __u8 request, __u8 requesttype, 858c2ecf20Sopenharmony_ci __u16 value, __u16 index, 868c2ecf20Sopenharmony_ci void *data, __u16 size, int timeout) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 898c2ecf20Sopenharmony_ci int ret; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (atusb->err) 928c2ecf20Sopenharmony_ci return atusb->err; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret = usb_control_msg(usb_dev, pipe, request, requesttype, 958c2ecf20Sopenharmony_ci value, index, data, size, timeout); 968c2ecf20Sopenharmony_ci if (ret < size) { 978c2ecf20Sopenharmony_ci ret = ret < 0 ? ret : -ENODATA; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci atusb->err = ret; 1008c2ecf20Sopenharmony_ci dev_err(&usb_dev->dev, 1018c2ecf20Sopenharmony_ci "%s: req 0x%02x val 0x%x idx 0x%x, error %d\n", 1028c2ecf20Sopenharmony_ci __func__, request, value, index, ret); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int atusb_command(struct atusb *atusb, u8 cmd, u8 arg) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s: cmd = 0x%x\n", __func__, cmd); 1128c2ecf20Sopenharmony_ci return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0), 1138c2ecf20Sopenharmony_ci cmd, ATUSB_REQ_TO_DEV, arg, 0, NULL, 0, 1000); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int atusb_write_reg(struct atusb *atusb, u8 reg, u8 value) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s: 0x%02x <- 0x%02x\n", __func__, reg, value); 1218c2ecf20Sopenharmony_ci return atusb_control_msg(atusb, usb_sndctrlpipe(usb_dev, 0), 1228c2ecf20Sopenharmony_ci ATUSB_REG_WRITE, ATUSB_REQ_TO_DEV, 1238c2ecf20Sopenharmony_ci value, reg, NULL, 0, 1000); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int atusb_read_reg(struct atusb *atusb, u8 reg) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 1298c2ecf20Sopenharmony_ci int ret; 1308c2ecf20Sopenharmony_ci u8 *buffer; 1318c2ecf20Sopenharmony_ci u8 value; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci buffer = kmalloc(1, GFP_KERNEL); 1348c2ecf20Sopenharmony_ci if (!buffer) 1358c2ecf20Sopenharmony_ci return -ENOMEM; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s: reg = 0x%x\n", __func__, reg); 1388c2ecf20Sopenharmony_ci ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), 1398c2ecf20Sopenharmony_ci ATUSB_REG_READ, ATUSB_REQ_FROM_DEV, 1408c2ecf20Sopenharmony_ci 0, reg, buffer, 1, 1000); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (ret >= 0) { 1438c2ecf20Sopenharmony_ci value = buffer[0]; 1448c2ecf20Sopenharmony_ci kfree(buffer); 1458c2ecf20Sopenharmony_ci return value; 1468c2ecf20Sopenharmony_ci } else { 1478c2ecf20Sopenharmony_ci kfree(buffer); 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int atusb_write_subreg(struct atusb *atusb, u8 reg, u8 mask, 1538c2ecf20Sopenharmony_ci u8 shift, u8 value) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 1568c2ecf20Sopenharmony_ci u8 orig, tmp; 1578c2ecf20Sopenharmony_ci int ret = 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s: 0x%02x <- 0x%02x\n", __func__, reg, value); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci orig = atusb_read_reg(atusb, reg); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Write the value only into that part of the register which is allowed 1648c2ecf20Sopenharmony_ci * by the mask. All other bits stay as before. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ci tmp = orig & ~mask; 1678c2ecf20Sopenharmony_ci tmp |= (value << shift) & mask; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (tmp != orig) 1708c2ecf20Sopenharmony_ci ret = atusb_write_reg(atusb, reg, tmp); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int atusb_read_subreg(struct atusb *lp, 1768c2ecf20Sopenharmony_ci unsigned int addr, unsigned int mask, 1778c2ecf20Sopenharmony_ci unsigned int shift) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int rc; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci rc = atusb_read_reg(lp, addr); 1828c2ecf20Sopenharmony_ci rc = (rc & mask) >> shift; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return rc; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int atusb_get_and_clear_error(struct atusb *atusb) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int err = atusb->err; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci atusb->err = 0; 1928c2ecf20Sopenharmony_ci return err; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* ----- skb allocation ---------------------------------------------------- */ 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define MAX_PSDU 127 1988c2ecf20Sopenharmony_ci#define MAX_RX_XFER (1 + MAX_PSDU + 2 + 1) /* PHR+PSDU+CRC+LQI */ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define SKB_ATUSB(skb) (*(struct atusb **)(skb)->cb) 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void atusb_in(struct urb *urb); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int atusb_submit_rx_urb(struct atusb *atusb, struct urb *urb) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 2078c2ecf20Sopenharmony_ci struct sk_buff *skb = urb->context; 2088c2ecf20Sopenharmony_ci int ret; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (!skb) { 2118c2ecf20Sopenharmony_ci skb = alloc_skb(MAX_RX_XFER, GFP_KERNEL); 2128c2ecf20Sopenharmony_ci if (!skb) { 2138c2ecf20Sopenharmony_ci dev_warn_ratelimited(&usb_dev->dev, 2148c2ecf20Sopenharmony_ci "atusb_in: can't allocate skb\n"); 2158c2ecf20Sopenharmony_ci return -ENOMEM; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci skb_put(skb, MAX_RX_XFER); 2188c2ecf20Sopenharmony_ci SKB_ATUSB(skb) = atusb; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci usb_fill_bulk_urb(urb, usb_dev, usb_rcvbulkpipe(usb_dev, 1), 2228c2ecf20Sopenharmony_ci skb->data, MAX_RX_XFER, atusb_in, skb); 2238c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &atusb->rx_urbs); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = usb_submit_urb(urb, GFP_KERNEL); 2268c2ecf20Sopenharmony_ci if (ret) { 2278c2ecf20Sopenharmony_ci usb_unanchor_urb(urb); 2288c2ecf20Sopenharmony_ci kfree_skb(skb); 2298c2ecf20Sopenharmony_ci urb->context = NULL; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void atusb_work_urbs(struct work_struct *work) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct atusb *atusb = 2378c2ecf20Sopenharmony_ci container_of(to_delayed_work(work), struct atusb, work); 2388c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 2398c2ecf20Sopenharmony_ci struct urb *urb; 2408c2ecf20Sopenharmony_ci int ret; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (atusb->shutdown) 2438c2ecf20Sopenharmony_ci return; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci do { 2468c2ecf20Sopenharmony_ci urb = usb_get_from_anchor(&atusb->idle_urbs); 2478c2ecf20Sopenharmony_ci if (!urb) 2488c2ecf20Sopenharmony_ci return; 2498c2ecf20Sopenharmony_ci ret = atusb_submit_rx_urb(atusb, urb); 2508c2ecf20Sopenharmony_ci } while (!ret); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &atusb->idle_urbs); 2538c2ecf20Sopenharmony_ci dev_warn_ratelimited(&usb_dev->dev, 2548c2ecf20Sopenharmony_ci "atusb_in: can't allocate/submit URB (%d)\n", ret); 2558c2ecf20Sopenharmony_ci schedule_delayed_work(&atusb->work, 2568c2ecf20Sopenharmony_ci msecs_to_jiffies(ATUSB_ALLOC_DELAY_MS) + 1); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/* ----- Asynchronous USB -------------------------------------------------- */ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic void atusb_tx_done(struct atusb *atusb, u8 seq) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 2648c2ecf20Sopenharmony_ci u8 expect = atusb->tx_ack_seq; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s (0x%02x/0x%02x)\n", __func__, seq, expect); 2678c2ecf20Sopenharmony_ci if (seq == expect) { 2688c2ecf20Sopenharmony_ci /* TODO check for ifs handling in firmware */ 2698c2ecf20Sopenharmony_ci ieee802154_xmit_complete(atusb->hw, atusb->tx_skb, false); 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci /* TODO I experience this case when atusb has a tx complete 2728c2ecf20Sopenharmony_ci * irq before probing, we should fix the firmware it's an 2738c2ecf20Sopenharmony_ci * unlikely case now that seq == expect is then true, but can 2748c2ecf20Sopenharmony_ci * happen and fail with a tx_skb = NULL; 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci ieee802154_wake_queue(atusb->hw); 2778c2ecf20Sopenharmony_ci if (atusb->tx_skb) 2788c2ecf20Sopenharmony_ci dev_kfree_skb_irq(atusb->tx_skb); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void atusb_in_good(struct urb *urb) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct usb_device *usb_dev = urb->dev; 2858c2ecf20Sopenharmony_ci struct sk_buff *skb = urb->context; 2868c2ecf20Sopenharmony_ci struct atusb *atusb = SKB_ATUSB(skb); 2878c2ecf20Sopenharmony_ci u8 len, lqi; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!urb->actual_length) { 2908c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "atusb_in: zero-sized URB ?\n"); 2918c2ecf20Sopenharmony_ci return; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci len = *skb->data; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (urb->actual_length == 1) { 2978c2ecf20Sopenharmony_ci atusb_tx_done(atusb, len); 2988c2ecf20Sopenharmony_ci return; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (len + 1 > urb->actual_length - 1) { 3028c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "atusb_in: frame len %d+1 > URB %u-1\n", 3038c2ecf20Sopenharmony_ci len, urb->actual_length); 3048c2ecf20Sopenharmony_ci return; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (!ieee802154_is_valid_psdu_len(len)) { 3088c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "atusb_in: frame corrupted\n"); 3098c2ecf20Sopenharmony_ci return; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci lqi = skb->data[len + 1]; 3138c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "atusb_in: rx len %d lqi 0x%02x\n", len, lqi); 3148c2ecf20Sopenharmony_ci skb_pull(skb, 1); /* remove PHR */ 3158c2ecf20Sopenharmony_ci skb_trim(skb, len); /* get payload only */ 3168c2ecf20Sopenharmony_ci ieee802154_rx_irqsafe(atusb->hw, skb, lqi); 3178c2ecf20Sopenharmony_ci urb->context = NULL; /* skb is gone */ 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void atusb_in(struct urb *urb) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct usb_device *usb_dev = urb->dev; 3238c2ecf20Sopenharmony_ci struct sk_buff *skb = urb->context; 3248c2ecf20Sopenharmony_ci struct atusb *atusb = SKB_ATUSB(skb); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s: status %d len %d\n", __func__, 3278c2ecf20Sopenharmony_ci urb->status, urb->actual_length); 3288c2ecf20Sopenharmony_ci if (urb->status) { 3298c2ecf20Sopenharmony_ci if (urb->status == -ENOENT) { /* being killed */ 3308c2ecf20Sopenharmony_ci kfree_skb(skb); 3318c2ecf20Sopenharmony_ci urb->context = NULL; 3328c2ecf20Sopenharmony_ci return; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s: URB error %d\n", __func__, urb->status); 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci atusb_in_good(urb); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &atusb->idle_urbs); 3408c2ecf20Sopenharmony_ci if (!atusb->shutdown) 3418c2ecf20Sopenharmony_ci schedule_delayed_work(&atusb->work, 0); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/* ----- URB allocation/deallocation --------------------------------------- */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic void atusb_free_urbs(struct atusb *atusb) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct urb *urb; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci while (1) { 3518c2ecf20Sopenharmony_ci urb = usb_get_from_anchor(&atusb->idle_urbs); 3528c2ecf20Sopenharmony_ci if (!urb) 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci kfree_skb(urb->context); 3558c2ecf20Sopenharmony_ci usb_free_urb(urb); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int atusb_alloc_urbs(struct atusb *atusb, int n) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct urb *urb; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci while (n) { 3648c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 3658c2ecf20Sopenharmony_ci if (!urb) { 3668c2ecf20Sopenharmony_ci atusb_free_urbs(atusb); 3678c2ecf20Sopenharmony_ci return -ENOMEM; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci usb_anchor_urb(urb, &atusb->idle_urbs); 3708c2ecf20Sopenharmony_ci usb_free_urb(urb); 3718c2ecf20Sopenharmony_ci n--; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* ----- IEEE 802.15.4 interface operations -------------------------------- */ 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic void atusb_xmit_complete(struct urb *urb) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "atusb_xmit urb completed"); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int atusb_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 3868c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 3878c2ecf20Sopenharmony_ci int ret; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s (%d)\n", __func__, skb->len); 3908c2ecf20Sopenharmony_ci atusb->tx_skb = skb; 3918c2ecf20Sopenharmony_ci atusb->tx_ack_seq++; 3928c2ecf20Sopenharmony_ci atusb->tx_dr.wIndex = cpu_to_le16(atusb->tx_ack_seq); 3938c2ecf20Sopenharmony_ci atusb->tx_dr.wLength = cpu_to_le16(skb->len); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci usb_fill_control_urb(atusb->tx_urb, usb_dev, 3968c2ecf20Sopenharmony_ci usb_sndctrlpipe(usb_dev, 0), 3978c2ecf20Sopenharmony_ci (unsigned char *)&atusb->tx_dr, skb->data, 3988c2ecf20Sopenharmony_ci skb->len, atusb_xmit_complete, NULL); 3998c2ecf20Sopenharmony_ci ret = usb_submit_urb(atusb->tx_urb, GFP_ATOMIC); 4008c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s done (%d)\n", __func__, ret); 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic int atusb_ed(struct ieee802154_hw *hw, u8 *level) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci WARN_ON(!level); 4078c2ecf20Sopenharmony_ci *level = 0xbe; 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int atusb_set_hw_addr_filt(struct ieee802154_hw *hw, 4128c2ecf20Sopenharmony_ci struct ieee802154_hw_addr_filt *filt, 4138c2ecf20Sopenharmony_ci unsigned long changed) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 4168c2ecf20Sopenharmony_ci struct device *dev = &atusb->usb_dev->dev; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (changed & IEEE802154_AFILT_SADDR_CHANGED) { 4198c2ecf20Sopenharmony_ci u16 addr = le16_to_cpu(filt->short_addr); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci dev_vdbg(dev, "%s called for saddr\n", __func__); 4228c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_SHORT_ADDR_0, addr); 4238c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_SHORT_ADDR_1, addr >> 8); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (changed & IEEE802154_AFILT_PANID_CHANGED) { 4278c2ecf20Sopenharmony_ci u16 pan = le16_to_cpu(filt->pan_id); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci dev_vdbg(dev, "%s called for pan id\n", __func__); 4308c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_PAN_ID_0, pan); 4318c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_PAN_ID_1, pan >> 8); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { 4358c2ecf20Sopenharmony_ci u8 i, addr[IEEE802154_EXTENDED_ADDR_LEN]; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci memcpy(addr, &filt->ieee_addr, IEEE802154_EXTENDED_ADDR_LEN); 4388c2ecf20Sopenharmony_ci dev_vdbg(dev, "%s called for IEEE addr\n", __func__); 4398c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 4408c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_IEEE_ADDR_0 + i, addr[i]); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (changed & IEEE802154_AFILT_PANC_CHANGED) { 4448c2ecf20Sopenharmony_ci dev_vdbg(dev, "%s called for panc change\n", __func__); 4458c2ecf20Sopenharmony_ci if (filt->pan_coord) 4468c2ecf20Sopenharmony_ci atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 1); 4478c2ecf20Sopenharmony_ci else 4488c2ecf20Sopenharmony_ci atusb_write_subreg(atusb, SR_AACK_I_AM_COORD, 0); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return atusb_get_and_clear_error(atusb); 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int atusb_start(struct ieee802154_hw *hw) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 4578c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 4588c2ecf20Sopenharmony_ci int ret; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s\n", __func__); 4618c2ecf20Sopenharmony_ci schedule_delayed_work(&atusb->work, 0); 4628c2ecf20Sopenharmony_ci atusb_command(atusb, ATUSB_RX_MODE, 1); 4638c2ecf20Sopenharmony_ci ret = atusb_get_and_clear_error(atusb); 4648c2ecf20Sopenharmony_ci if (ret < 0) 4658c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&atusb->idle_urbs); 4668c2ecf20Sopenharmony_ci return ret; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic void atusb_stop(struct ieee802154_hw *hw) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 4728c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci dev_dbg(&usb_dev->dev, "%s\n", __func__); 4758c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&atusb->idle_urbs); 4768c2ecf20Sopenharmony_ci atusb_command(atusb, ATUSB_RX_MODE, 0); 4778c2ecf20Sopenharmony_ci atusb_get_and_clear_error(atusb); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci#define ATUSB_MAX_TX_POWERS 0xF 4818c2ecf20Sopenharmony_cistatic const s32 atusb_powers[ATUSB_MAX_TX_POWERS + 1] = { 4828c2ecf20Sopenharmony_ci 300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700, 4838c2ecf20Sopenharmony_ci -900, -1200, -1700, 4848c2ecf20Sopenharmony_ci}; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int 4878c2ecf20Sopenharmony_ciatusb_txpower(struct ieee802154_hw *hw, s32 mbm) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (atusb->data) 4928c2ecf20Sopenharmony_ci return atusb->data->set_txpower(hw, mbm); 4938c2ecf20Sopenharmony_ci else 4948c2ecf20Sopenharmony_ci return -ENOTSUPP; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int 4988c2ecf20Sopenharmony_ciatusb_set_txpower(struct ieee802154_hw *hw, s32 mbm) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 5018c2ecf20Sopenharmony_ci u32 i; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci for (i = 0; i < hw->phy->supported.tx_powers_size; i++) { 5048c2ecf20Sopenharmony_ci if (hw->phy->supported.tx_powers[i] == mbm) 5058c2ecf20Sopenharmony_ci return atusb_write_subreg(atusb, SR_TX_PWR_23X, i); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int 5128c2ecf20Sopenharmony_cihulusb_set_txpower(struct ieee802154_hw *hw, s32 mbm) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci u32 i; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci for (i = 0; i < hw->phy->supported.tx_powers_size; i++) { 5178c2ecf20Sopenharmony_ci if (hw->phy->supported.tx_powers[i] == mbm) 5188c2ecf20Sopenharmony_ci return atusb_write_subreg(hw->priv, SR_TX_PWR_212, i); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return -EINVAL; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci#define ATUSB_MAX_ED_LEVELS 0xF 5258c2ecf20Sopenharmony_cistatic const s32 atusb_ed_levels[ATUSB_MAX_ED_LEVELS + 1] = { 5268c2ecf20Sopenharmony_ci -9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300, 5278c2ecf20Sopenharmony_ci -7100, -6900, -6700, -6500, -6300, -6100, 5288c2ecf20Sopenharmony_ci}; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci#define AT86RF212_MAX_TX_POWERS 0x1F 5318c2ecf20Sopenharmony_cistatic const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = { 5328c2ecf20Sopenharmony_ci 500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700, 5338c2ecf20Sopenharmony_ci -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700, 5348c2ecf20Sopenharmony_ci -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600, 5358c2ecf20Sopenharmony_ci}; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci#define AT86RF2XX_MAX_ED_LEVELS 0xF 5388c2ecf20Sopenharmony_cistatic const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = { 5398c2ecf20Sopenharmony_ci -10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, 5408c2ecf20Sopenharmony_ci -8000, -7800, -7600, -7400, -7200, -7000, 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = { 5448c2ecf20Sopenharmony_ci -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000, 5458c2ecf20Sopenharmony_ci -7800, -7600, -7400, -7200, -7000, -6800, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int 5498c2ecf20Sopenharmony_ciatusb_set_cca_mode(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 5528c2ecf20Sopenharmony_ci u8 val; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* mapping 802.15.4 to driver spec */ 5558c2ecf20Sopenharmony_ci switch (cca->mode) { 5568c2ecf20Sopenharmony_ci case NL802154_CCA_ENERGY: 5578c2ecf20Sopenharmony_ci val = 1; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case NL802154_CCA_CARRIER: 5608c2ecf20Sopenharmony_ci val = 2; 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case NL802154_CCA_ENERGY_CARRIER: 5638c2ecf20Sopenharmony_ci switch (cca->opt) { 5648c2ecf20Sopenharmony_ci case NL802154_CCA_OPT_ENERGY_CARRIER_AND: 5658c2ecf20Sopenharmony_ci val = 3; 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci case NL802154_CCA_OPT_ENERGY_CARRIER_OR: 5688c2ecf20Sopenharmony_ci val = 0; 5698c2ecf20Sopenharmony_ci break; 5708c2ecf20Sopenharmony_ci default: 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci default: 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return atusb_write_subreg(atusb, SR_CCA_MODE, val); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int hulusb_set_cca_ed_level(struct atusb *lp, int rssi_base_val) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci unsigned int cca_ed_thres; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci cca_ed_thres = atusb_read_subreg(lp, SR_CCA_ED_THRES); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci switch (rssi_base_val) { 5888c2ecf20Sopenharmony_ci case -98: 5898c2ecf20Sopenharmony_ci lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98; 5908c2ecf20Sopenharmony_ci lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98); 5918c2ecf20Sopenharmony_ci lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres]; 5928c2ecf20Sopenharmony_ci break; 5938c2ecf20Sopenharmony_ci case -100: 5948c2ecf20Sopenharmony_ci lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100; 5958c2ecf20Sopenharmony_ci lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100); 5968c2ecf20Sopenharmony_ci lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres]; 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci default: 5998c2ecf20Sopenharmony_ci WARN_ON(1); 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int 6068c2ecf20Sopenharmony_ciatusb_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 6098c2ecf20Sopenharmony_ci u32 i; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) { 6128c2ecf20Sopenharmony_ci if (hw->phy->supported.cca_ed_levels[i] == mbm) 6138c2ecf20Sopenharmony_ci return atusb_write_subreg(atusb, SR_CCA_ED_THRES, i); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return -EINVAL; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic int atusb_channel(struct ieee802154_hw *hw, u8 page, u8 channel) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 6228c2ecf20Sopenharmony_ci int ret = -ENOTSUPP; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (atusb->data) { 6258c2ecf20Sopenharmony_ci ret = atusb->data->set_channel(hw, page, channel); 6268c2ecf20Sopenharmony_ci /* @@@ ugly synchronization */ 6278c2ecf20Sopenharmony_ci msleep(atusb->data->t_channel_switch); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return ret; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int atusb_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 6368c2ecf20Sopenharmony_ci int ret; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_CHANNEL, channel); 6398c2ecf20Sopenharmony_ci if (ret < 0) 6408c2ecf20Sopenharmony_ci return ret; 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int hulusb_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci int rc; 6478c2ecf20Sopenharmony_ci int rssi_base_val; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci struct atusb *lp = hw->priv; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (channel == 0) 6528c2ecf20Sopenharmony_ci rc = atusb_write_subreg(lp, SR_SUB_MODE, 0); 6538c2ecf20Sopenharmony_ci else 6548c2ecf20Sopenharmony_ci rc = atusb_write_subreg(lp, SR_SUB_MODE, 1); 6558c2ecf20Sopenharmony_ci if (rc < 0) 6568c2ecf20Sopenharmony_ci return rc; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (page == 0) { 6598c2ecf20Sopenharmony_ci rc = atusb_write_subreg(lp, SR_BPSK_QPSK, 0); 6608c2ecf20Sopenharmony_ci rssi_base_val = -100; 6618c2ecf20Sopenharmony_ci } else { 6628c2ecf20Sopenharmony_ci rc = atusb_write_subreg(lp, SR_BPSK_QPSK, 1); 6638c2ecf20Sopenharmony_ci rssi_base_val = -98; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci if (rc < 0) 6668c2ecf20Sopenharmony_ci return rc; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci rc = hulusb_set_cca_ed_level(lp, rssi_base_val); 6698c2ecf20Sopenharmony_ci if (rc < 0) 6708c2ecf20Sopenharmony_ci return rc; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* This sets the symbol_duration according frequency on the 212. 6738c2ecf20Sopenharmony_ci * TODO move this handling while set channel and page in cfg802154. 6748c2ecf20Sopenharmony_ci * We can do that, this timings are according 802.15.4 standard. 6758c2ecf20Sopenharmony_ci * If we do that in cfg802154, this is a more generic calculation. 6768c2ecf20Sopenharmony_ci * 6778c2ecf20Sopenharmony_ci * This should also protected from ifs_timer. Means cancel timer and 6788c2ecf20Sopenharmony_ci * init with a new value. For now, this is okay. 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci if (channel == 0) { 6818c2ecf20Sopenharmony_ci if (page == 0) { 6828c2ecf20Sopenharmony_ci /* SUB:0 and BPSK:0 -> BPSK-20 */ 6838c2ecf20Sopenharmony_ci lp->hw->phy->symbol_duration = 50; 6848c2ecf20Sopenharmony_ci } else { 6858c2ecf20Sopenharmony_ci /* SUB:1 and BPSK:0 -> BPSK-40 */ 6868c2ecf20Sopenharmony_ci lp->hw->phy->symbol_duration = 25; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci } else { 6898c2ecf20Sopenharmony_ci if (page == 0) 6908c2ecf20Sopenharmony_ci /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */ 6918c2ecf20Sopenharmony_ci lp->hw->phy->symbol_duration = 40; 6928c2ecf20Sopenharmony_ci else 6938c2ecf20Sopenharmony_ci /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */ 6948c2ecf20Sopenharmony_ci lp->hw->phy->symbol_duration = 16; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD * 6988c2ecf20Sopenharmony_ci lp->hw->phy->symbol_duration; 6998c2ecf20Sopenharmony_ci lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD * 7008c2ecf20Sopenharmony_ci lp->hw->phy->symbol_duration; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci return atusb_write_subreg(lp, SR_CHANNEL, channel); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic int 7068c2ecf20Sopenharmony_ciatusb_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be, u8 retries) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 7098c2ecf20Sopenharmony_ci int ret; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_MIN_BE, min_be); 7128c2ecf20Sopenharmony_ci if (ret) 7138c2ecf20Sopenharmony_ci return ret; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_MAX_BE, max_be); 7168c2ecf20Sopenharmony_ci if (ret) 7178c2ecf20Sopenharmony_ci return ret; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci return atusb_write_subreg(atusb, SR_MAX_CSMA_RETRIES, retries); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int 7238c2ecf20Sopenharmony_cihulusb_set_lbt(struct ieee802154_hw *hw, bool on) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return atusb_write_subreg(atusb, SR_CSMA_LBT_MODE, on); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic int 7318c2ecf20Sopenharmony_ciatusb_set_frame_retries(struct ieee802154_hw *hw, s8 retries) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return atusb_write_subreg(atusb, SR_MAX_FRAME_RETRIES, retries); 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic int 7398c2ecf20Sopenharmony_ciatusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct atusb *atusb = hw->priv; 7428c2ecf20Sopenharmony_ci int ret; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (on) { 7458c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 1); 7468c2ecf20Sopenharmony_ci if (ret < 0) 7478c2ecf20Sopenharmony_ci return ret; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 1); 7508c2ecf20Sopenharmony_ci if (ret < 0) 7518c2ecf20Sopenharmony_ci return ret; 7528c2ecf20Sopenharmony_ci } else { 7538c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_AACK_PROM_MODE, 0); 7548c2ecf20Sopenharmony_ci if (ret < 0) 7558c2ecf20Sopenharmony_ci return ret; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci ret = atusb_write_subreg(atusb, SR_AACK_DIS_ACK, 0); 7588c2ecf20Sopenharmony_ci if (ret < 0) 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci return 0; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic struct atusb_chip_data atusb_chip_data = { 7668c2ecf20Sopenharmony_ci .t_channel_switch = 1, 7678c2ecf20Sopenharmony_ci .rssi_base_val = -91, 7688c2ecf20Sopenharmony_ci .set_txpower = atusb_set_txpower, 7698c2ecf20Sopenharmony_ci .set_channel = atusb_set_channel, 7708c2ecf20Sopenharmony_ci}; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic struct atusb_chip_data hulusb_chip_data = { 7738c2ecf20Sopenharmony_ci .t_channel_switch = 11, 7748c2ecf20Sopenharmony_ci .rssi_base_val = -100, 7758c2ecf20Sopenharmony_ci .set_txpower = hulusb_set_txpower, 7768c2ecf20Sopenharmony_ci .set_channel = hulusb_set_channel, 7778c2ecf20Sopenharmony_ci}; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic const struct ieee802154_ops atusb_ops = { 7808c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7818c2ecf20Sopenharmony_ci .xmit_async = atusb_xmit, 7828c2ecf20Sopenharmony_ci .ed = atusb_ed, 7838c2ecf20Sopenharmony_ci .set_channel = atusb_channel, 7848c2ecf20Sopenharmony_ci .start = atusb_start, 7858c2ecf20Sopenharmony_ci .stop = atusb_stop, 7868c2ecf20Sopenharmony_ci .set_hw_addr_filt = atusb_set_hw_addr_filt, 7878c2ecf20Sopenharmony_ci .set_txpower = atusb_txpower, 7888c2ecf20Sopenharmony_ci .set_lbt = hulusb_set_lbt, 7898c2ecf20Sopenharmony_ci .set_cca_mode = atusb_set_cca_mode, 7908c2ecf20Sopenharmony_ci .set_cca_ed_level = atusb_set_cca_ed_level, 7918c2ecf20Sopenharmony_ci .set_csma_params = atusb_set_csma_params, 7928c2ecf20Sopenharmony_ci .set_frame_retries = atusb_set_frame_retries, 7938c2ecf20Sopenharmony_ci .set_promiscuous_mode = atusb_set_promiscuous_mode, 7948c2ecf20Sopenharmony_ci}; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/* ----- Firmware and chip version information ----------------------------- */ 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int atusb_get_and_show_revision(struct atusb *atusb) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 8018c2ecf20Sopenharmony_ci char *hw_name; 8028c2ecf20Sopenharmony_ci unsigned char *buffer; 8038c2ecf20Sopenharmony_ci int ret; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci buffer = kmalloc(3, GFP_KERNEL); 8068c2ecf20Sopenharmony_ci if (!buffer) 8078c2ecf20Sopenharmony_ci return -ENOMEM; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* Get a couple of the ATMega Firmware values */ 8108c2ecf20Sopenharmony_ci ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), 8118c2ecf20Sopenharmony_ci ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0, 8128c2ecf20Sopenharmony_ci buffer, 3, 1000); 8138c2ecf20Sopenharmony_ci if (ret >= 0) { 8148c2ecf20Sopenharmony_ci atusb->fw_ver_maj = buffer[0]; 8158c2ecf20Sopenharmony_ci atusb->fw_ver_min = buffer[1]; 8168c2ecf20Sopenharmony_ci atusb->fw_hw_type = buffer[2]; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci switch (atusb->fw_hw_type) { 8198c2ecf20Sopenharmony_ci case ATUSB_HW_TYPE_100813: 8208c2ecf20Sopenharmony_ci case ATUSB_HW_TYPE_101216: 8218c2ecf20Sopenharmony_ci case ATUSB_HW_TYPE_110131: 8228c2ecf20Sopenharmony_ci hw_name = "ATUSB"; 8238c2ecf20Sopenharmony_ci atusb->data = &atusb_chip_data; 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case ATUSB_HW_TYPE_RZUSB: 8268c2ecf20Sopenharmony_ci hw_name = "RZUSB"; 8278c2ecf20Sopenharmony_ci atusb->data = &atusb_chip_data; 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci case ATUSB_HW_TYPE_HULUSB: 8308c2ecf20Sopenharmony_ci hw_name = "HULUSB"; 8318c2ecf20Sopenharmony_ci atusb->data = &hulusb_chip_data; 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci default: 8348c2ecf20Sopenharmony_ci hw_name = "UNKNOWN"; 8358c2ecf20Sopenharmony_ci atusb->err = -ENOTSUPP; 8368c2ecf20Sopenharmony_ci ret = -ENOTSUPP; 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, 8418c2ecf20Sopenharmony_ci "Firmware: major: %u, minor: %u, hardware type: %s (%d)\n", 8428c2ecf20Sopenharmony_ci atusb->fw_ver_maj, atusb->fw_ver_min, hw_name, 8438c2ecf20Sopenharmony_ci atusb->fw_hw_type); 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 2) { 8468c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, 8478c2ecf20Sopenharmony_ci "Firmware version (%u.%u) predates our first public release.", 8488c2ecf20Sopenharmony_ci atusb->fw_ver_maj, atusb->fw_ver_min); 8498c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, "Please update to version 0.2 or newer"); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci kfree(buffer); 8538c2ecf20Sopenharmony_ci return ret; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int atusb_get_and_show_build(struct atusb *atusb) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 8598c2ecf20Sopenharmony_ci char *build; 8608c2ecf20Sopenharmony_ci int ret; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci build = kmalloc(ATUSB_BUILD_SIZE + 1, GFP_KERNEL); 8638c2ecf20Sopenharmony_ci if (!build) 8648c2ecf20Sopenharmony_ci return -ENOMEM; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* We cannot call atusb_control_msg() here, since this request may read various length data */ 8678c2ecf20Sopenharmony_ci ret = usb_control_msg(atusb->usb_dev, usb_rcvctrlpipe(usb_dev, 0), ATUSB_BUILD, 8688c2ecf20Sopenharmony_ci ATUSB_REQ_FROM_DEV, 0, 0, build, ATUSB_BUILD_SIZE, 1000); 8698c2ecf20Sopenharmony_ci if (ret >= 0) { 8708c2ecf20Sopenharmony_ci build[ret] = 0; 8718c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, "Firmware: build %s\n", build); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci kfree(build); 8758c2ecf20Sopenharmony_ci return ret; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int atusb_get_and_conf_chip(struct atusb *atusb) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 8818c2ecf20Sopenharmony_ci u8 man_id_0, man_id_1, part_num, version_num; 8828c2ecf20Sopenharmony_ci const char *chip; 8838c2ecf20Sopenharmony_ci struct ieee802154_hw *hw = atusb->hw; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci man_id_0 = atusb_read_reg(atusb, RG_MAN_ID_0); 8868c2ecf20Sopenharmony_ci man_id_1 = atusb_read_reg(atusb, RG_MAN_ID_1); 8878c2ecf20Sopenharmony_ci part_num = atusb_read_reg(atusb, RG_PART_NUM); 8888c2ecf20Sopenharmony_ci version_num = atusb_read_reg(atusb, RG_VERSION_NUM); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (atusb->err) 8918c2ecf20Sopenharmony_ci return atusb->err; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | 8948c2ecf20Sopenharmony_ci IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL | 8978c2ecf20Sopenharmony_ci WPAN_PHY_FLAG_CCA_MODE; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) | 9008c2ecf20Sopenharmony_ci BIT(NL802154_CCA_CARRIER) | 9018c2ecf20Sopenharmony_ci BIT(NL802154_CCA_ENERGY_CARRIER); 9028c2ecf20Sopenharmony_ci hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) | 9038c2ecf20Sopenharmony_ci BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci hw->phy->cca.mode = NL802154_CCA_ENERGY; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci hw->phy->current_page = 0; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if ((man_id_1 << 8 | man_id_0) != ATUSB_JEDEC_ATMEL) { 9108c2ecf20Sopenharmony_ci dev_err(&usb_dev->dev, 9118c2ecf20Sopenharmony_ci "non-Atmel transceiver xxxx%02x%02x\n", 9128c2ecf20Sopenharmony_ci man_id_1, man_id_0); 9138c2ecf20Sopenharmony_ci goto fail; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci switch (part_num) { 9178c2ecf20Sopenharmony_ci case 2: 9188c2ecf20Sopenharmony_ci chip = "AT86RF230"; 9198c2ecf20Sopenharmony_ci atusb->hw->phy->supported.channels[0] = 0x7FFF800; 9208c2ecf20Sopenharmony_ci atusb->hw->phy->current_channel = 11; /* reset default */ 9218c2ecf20Sopenharmony_ci atusb->hw->phy->symbol_duration = 16; 9228c2ecf20Sopenharmony_ci atusb->hw->phy->supported.tx_powers = atusb_powers; 9238c2ecf20Sopenharmony_ci atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers); 9248c2ecf20Sopenharmony_ci hw->phy->supported.cca_ed_levels = atusb_ed_levels; 9258c2ecf20Sopenharmony_ci hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(atusb_ed_levels); 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci case 3: 9288c2ecf20Sopenharmony_ci chip = "AT86RF231"; 9298c2ecf20Sopenharmony_ci atusb->hw->phy->supported.channels[0] = 0x7FFF800; 9308c2ecf20Sopenharmony_ci atusb->hw->phy->current_channel = 11; /* reset default */ 9318c2ecf20Sopenharmony_ci atusb->hw->phy->symbol_duration = 16; 9328c2ecf20Sopenharmony_ci atusb->hw->phy->supported.tx_powers = atusb_powers; 9338c2ecf20Sopenharmony_ci atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers); 9348c2ecf20Sopenharmony_ci hw->phy->supported.cca_ed_levels = atusb_ed_levels; 9358c2ecf20Sopenharmony_ci hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(atusb_ed_levels); 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci case 7: 9388c2ecf20Sopenharmony_ci chip = "AT86RF212"; 9398c2ecf20Sopenharmony_ci atusb->hw->flags |= IEEE802154_HW_LBT; 9408c2ecf20Sopenharmony_ci atusb->hw->phy->supported.channels[0] = 0x00007FF; 9418c2ecf20Sopenharmony_ci atusb->hw->phy->supported.channels[2] = 0x00007FF; 9428c2ecf20Sopenharmony_ci atusb->hw->phy->current_channel = 5; 9438c2ecf20Sopenharmony_ci atusb->hw->phy->symbol_duration = 25; 9448c2ecf20Sopenharmony_ci atusb->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH; 9458c2ecf20Sopenharmony_ci atusb->hw->phy->supported.tx_powers = at86rf212_powers; 9468c2ecf20Sopenharmony_ci atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers); 9478c2ecf20Sopenharmony_ci atusb->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100; 9488c2ecf20Sopenharmony_ci atusb->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100); 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci default: 9518c2ecf20Sopenharmony_ci dev_err(&usb_dev->dev, 9528c2ecf20Sopenharmony_ci "unexpected transceiver, part 0x%02x version 0x%02x\n", 9538c2ecf20Sopenharmony_ci part_num, version_num); 9548c2ecf20Sopenharmony_ci goto fail; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci hw->phy->transmit_power = hw->phy->supported.tx_powers[0]; 9588c2ecf20Sopenharmony_ci hw->phy->cca_ed_level = hw->phy->supported.cca_ed_levels[7]; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, "ATUSB: %s version %d\n", chip, version_num); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci return 0; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cifail: 9658c2ecf20Sopenharmony_ci atusb->err = -ENODEV; 9668c2ecf20Sopenharmony_ci return -ENODEV; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic int atusb_set_extended_addr(struct atusb *atusb) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct usb_device *usb_dev = atusb->usb_dev; 9728c2ecf20Sopenharmony_ci unsigned char *buffer; 9738c2ecf20Sopenharmony_ci __le64 extended_addr; 9748c2ecf20Sopenharmony_ci u64 addr; 9758c2ecf20Sopenharmony_ci int ret; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* Firmware versions before 0.3 do not support the EUI64_READ command. 9788c2ecf20Sopenharmony_ci * Just use a random address and be done. 9798c2ecf20Sopenharmony_ci */ 9808c2ecf20Sopenharmony_ci if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) { 9818c2ecf20Sopenharmony_ci ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr); 9828c2ecf20Sopenharmony_ci return 0; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci buffer = kmalloc(IEEE802154_EXTENDED_ADDR_LEN, GFP_KERNEL); 9868c2ecf20Sopenharmony_ci if (!buffer) 9878c2ecf20Sopenharmony_ci return -ENOMEM; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* Firmware is new enough so we fetch the address from EEPROM */ 9908c2ecf20Sopenharmony_ci ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), 9918c2ecf20Sopenharmony_ci ATUSB_EUI64_READ, ATUSB_REQ_FROM_DEV, 0, 0, 9928c2ecf20Sopenharmony_ci buffer, IEEE802154_EXTENDED_ADDR_LEN, 1000); 9938c2ecf20Sopenharmony_ci if (ret < 0) { 9948c2ecf20Sopenharmony_ci dev_err(&usb_dev->dev, "failed to fetch extended address, random address set\n"); 9958c2ecf20Sopenharmony_ci ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr); 9968c2ecf20Sopenharmony_ci kfree(buffer); 9978c2ecf20Sopenharmony_ci return ret; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN); 10018c2ecf20Sopenharmony_ci /* Check if read address is not empty and the unicast bit is set correctly */ 10028c2ecf20Sopenharmony_ci if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) { 10038c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, "no permanent extended address found, random address set\n"); 10048c2ecf20Sopenharmony_ci ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr); 10058c2ecf20Sopenharmony_ci } else { 10068c2ecf20Sopenharmony_ci atusb->hw->phy->perm_extended_addr = extended_addr; 10078c2ecf20Sopenharmony_ci addr = swab64((__force u64)atusb->hw->phy->perm_extended_addr); 10088c2ecf20Sopenharmony_ci dev_info(&usb_dev->dev, "Read permanent extended address %8phC from device\n", 10098c2ecf20Sopenharmony_ci &addr); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci kfree(buffer); 10138c2ecf20Sopenharmony_ci return ret; 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci/* ----- Setup ------------------------------------------------------------- */ 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int atusb_probe(struct usb_interface *interface, 10198c2ecf20Sopenharmony_ci const struct usb_device_id *id) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct usb_device *usb_dev = interface_to_usbdev(interface); 10228c2ecf20Sopenharmony_ci struct ieee802154_hw *hw; 10238c2ecf20Sopenharmony_ci struct atusb *atusb = NULL; 10248c2ecf20Sopenharmony_ci int ret = -ENOMEM; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci hw = ieee802154_alloc_hw(sizeof(struct atusb), &atusb_ops); 10278c2ecf20Sopenharmony_ci if (!hw) 10288c2ecf20Sopenharmony_ci return -ENOMEM; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci atusb = hw->priv; 10318c2ecf20Sopenharmony_ci atusb->hw = hw; 10328c2ecf20Sopenharmony_ci atusb->usb_dev = usb_get_dev(usb_dev); 10338c2ecf20Sopenharmony_ci usb_set_intfdata(interface, atusb); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci atusb->shutdown = 0; 10368c2ecf20Sopenharmony_ci atusb->err = 0; 10378c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&atusb->work, atusb_work_urbs); 10388c2ecf20Sopenharmony_ci init_usb_anchor(&atusb->idle_urbs); 10398c2ecf20Sopenharmony_ci init_usb_anchor(&atusb->rx_urbs); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (atusb_alloc_urbs(atusb, ATUSB_NUM_RX_URBS)) 10428c2ecf20Sopenharmony_ci goto fail; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci atusb->tx_dr.bRequestType = ATUSB_REQ_TO_DEV; 10458c2ecf20Sopenharmony_ci atusb->tx_dr.bRequest = ATUSB_TX; 10468c2ecf20Sopenharmony_ci atusb->tx_dr.wValue = cpu_to_le16(0); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci atusb->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 10498c2ecf20Sopenharmony_ci if (!atusb->tx_urb) 10508c2ecf20Sopenharmony_ci goto fail; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci hw->parent = &usb_dev->dev; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci atusb_command(atusb, ATUSB_RF_RESET, 0); 10558c2ecf20Sopenharmony_ci atusb_get_and_conf_chip(atusb); 10568c2ecf20Sopenharmony_ci atusb_get_and_show_revision(atusb); 10578c2ecf20Sopenharmony_ci atusb_get_and_show_build(atusb); 10588c2ecf20Sopenharmony_ci atusb_set_extended_addr(atusb); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if ((atusb->fw_ver_maj == 0 && atusb->fw_ver_min >= 3) || atusb->fw_ver_maj > 0) 10618c2ecf20Sopenharmony_ci hw->flags |= IEEE802154_HW_FRAME_RETRIES; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci ret = atusb_get_and_clear_error(atusb); 10648c2ecf20Sopenharmony_ci if (ret) { 10658c2ecf20Sopenharmony_ci dev_err(&atusb->usb_dev->dev, 10668c2ecf20Sopenharmony_ci "%s: initialization failed, error = %d\n", 10678c2ecf20Sopenharmony_ci __func__, ret); 10688c2ecf20Sopenharmony_ci goto fail; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ret = ieee802154_register_hw(hw); 10728c2ecf20Sopenharmony_ci if (ret) 10738c2ecf20Sopenharmony_ci goto fail; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* If we just powered on, we're now in P_ON and need to enter TRX_OFF 10768c2ecf20Sopenharmony_ci * explicitly. Any resets after that will send us straight to TRX_OFF, 10778c2ecf20Sopenharmony_ci * making the command below redundant. 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_TRX_STATE, STATE_FORCE_TRX_OFF); 10808c2ecf20Sopenharmony_ci msleep(1); /* reset => TRX_OFF, tTR13 = 37 us */ 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci#if 0 10838c2ecf20Sopenharmony_ci /* Calculating the maximum time available to empty the frame buffer 10848c2ecf20Sopenharmony_ci * on reception: 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * According to [1], the inter-frame gap is 10878c2ecf20Sopenharmony_ci * R * 20 * 16 us + 128 us 10888c2ecf20Sopenharmony_ci * where R is a random number from 0 to 7. Furthermore, we have 20 bit 10898c2ecf20Sopenharmony_ci * times (80 us at 250 kbps) of SHR of the next frame before the 10908c2ecf20Sopenharmony_ci * transceiver begins storing data in the frame buffer. 10918c2ecf20Sopenharmony_ci * 10928c2ecf20Sopenharmony_ci * This yields a minimum time of 208 us between the last data of a 10938c2ecf20Sopenharmony_ci * frame and the first data of the next frame. This time is further 10948c2ecf20Sopenharmony_ci * reduced by interrupt latency in the atusb firmware. 10958c2ecf20Sopenharmony_ci * 10968c2ecf20Sopenharmony_ci * atusb currently needs about 500 us to retrieve a maximum-sized 10978c2ecf20Sopenharmony_ci * frame. We therefore have to allow reception of a new frame to begin 10988c2ecf20Sopenharmony_ci * while we retrieve the previous frame. 10998c2ecf20Sopenharmony_ci * 11008c2ecf20Sopenharmony_ci * [1] "JN-AN-1035 Calculating data rates in an IEEE 802.15.4-based 11018c2ecf20Sopenharmony_ci * network", Jennic 2006. 11028c2ecf20Sopenharmony_ci * http://www.jennic.com/download_file.php?supportFile=JN-AN-1035%20Calculating%20802-15-4%20Data%20Rates-1v0.pdf 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci atusb_write_subreg(atusb, SR_RX_SAFE_MODE, 1); 11068c2ecf20Sopenharmony_ci#endif 11078c2ecf20Sopenharmony_ci atusb_write_reg(atusb, RG_IRQ_MASK, 0xff); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci ret = atusb_get_and_clear_error(atusb); 11108c2ecf20Sopenharmony_ci if (!ret) 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci dev_err(&atusb->usb_dev->dev, 11148c2ecf20Sopenharmony_ci "%s: setup failed, error = %d\n", 11158c2ecf20Sopenharmony_ci __func__, ret); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ieee802154_unregister_hw(hw); 11188c2ecf20Sopenharmony_cifail: 11198c2ecf20Sopenharmony_ci atusb_free_urbs(atusb); 11208c2ecf20Sopenharmony_ci usb_kill_urb(atusb->tx_urb); 11218c2ecf20Sopenharmony_ci usb_free_urb(atusb->tx_urb); 11228c2ecf20Sopenharmony_ci usb_put_dev(usb_dev); 11238c2ecf20Sopenharmony_ci ieee802154_free_hw(hw); 11248c2ecf20Sopenharmony_ci return ret; 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic void atusb_disconnect(struct usb_interface *interface) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci struct atusb *atusb = usb_get_intfdata(interface); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci dev_dbg(&atusb->usb_dev->dev, "%s\n", __func__); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci atusb->shutdown = 1; 11348c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&atusb->work); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci usb_kill_anchored_urbs(&atusb->rx_urbs); 11378c2ecf20Sopenharmony_ci atusb_free_urbs(atusb); 11388c2ecf20Sopenharmony_ci usb_kill_urb(atusb->tx_urb); 11398c2ecf20Sopenharmony_ci usb_free_urb(atusb->tx_urb); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci ieee802154_unregister_hw(atusb->hw); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci usb_put_dev(atusb->usb_dev); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci ieee802154_free_hw(atusb->hw); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci usb_set_intfdata(interface, NULL); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci pr_debug("%s done\n", __func__); 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci/* The devices we work with */ 11538c2ecf20Sopenharmony_cistatic const struct usb_device_id atusb_device_table[] = { 11548c2ecf20Sopenharmony_ci { 11558c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 11568c2ecf20Sopenharmony_ci USB_DEVICE_ID_MATCH_INT_INFO, 11578c2ecf20Sopenharmony_ci .idVendor = ATUSB_VENDOR_ID, 11588c2ecf20Sopenharmony_ci .idProduct = ATUSB_PRODUCT_ID, 11598c2ecf20Sopenharmony_ci .bInterfaceClass = USB_CLASS_VENDOR_SPEC 11608c2ecf20Sopenharmony_ci }, 11618c2ecf20Sopenharmony_ci /* end with null element */ 11628c2ecf20Sopenharmony_ci {} 11638c2ecf20Sopenharmony_ci}; 11648c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, atusb_device_table); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic struct usb_driver atusb_driver = { 11678c2ecf20Sopenharmony_ci .name = "atusb", 11688c2ecf20Sopenharmony_ci .probe = atusb_probe, 11698c2ecf20Sopenharmony_ci .disconnect = atusb_disconnect, 11708c2ecf20Sopenharmony_ci .id_table = atusb_device_table, 11718c2ecf20Sopenharmony_ci}; 11728c2ecf20Sopenharmony_cimodule_usb_driver(atusb_driver); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexander Aring <alex.aring@gmail.com>"); 11758c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Sharpe <realrichardsharpe@gmail.com>"); 11768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stefan Schmidt <stefan@datenfreihafen.org>"); 11778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Werner Almesberger <werner@almesberger.net>"); 11788c2ecf20Sopenharmony_ciMODULE_AUTHOR("Josef Filzmaier <j.filzmaier@gmx.at>"); 11798c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ATUSB IEEE 802.15.4 Driver"); 11808c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1181