162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* ZD1211 USB-WLAN driver for Linux 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> 562306a36Sopenharmony_ci * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> 662306a36Sopenharmony_ci * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/firmware.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/skbuff.h> 1662306a36Sopenharmony_ci#include <linux/usb.h> 1762306a36Sopenharmony_ci#include <linux/workqueue.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <net/mac80211.h> 2062306a36Sopenharmony_ci#include <asm/unaligned.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "zd_def.h" 2362306a36Sopenharmony_ci#include "zd_mac.h" 2462306a36Sopenharmony_ci#include "zd_usb.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const struct usb_device_id usb_ids[] = { 2762306a36Sopenharmony_ci /* ZD1211 */ 2862306a36Sopenharmony_ci { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, 2962306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, 3062306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 }, 3162306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, 3262306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 }, 3362306a36Sopenharmony_ci { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 }, 3462306a36Sopenharmony_ci { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 }, 3562306a36Sopenharmony_ci { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 }, 3662306a36Sopenharmony_ci { USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 }, 3762306a36Sopenharmony_ci { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 }, 3862306a36Sopenharmony_ci { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, 3962306a36Sopenharmony_ci { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 }, 4062306a36Sopenharmony_ci { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 }, 4162306a36Sopenharmony_ci { USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 }, 4262306a36Sopenharmony_ci { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 }, 4362306a36Sopenharmony_ci { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, 4462306a36Sopenharmony_ci { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, 4562306a36Sopenharmony_ci { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 }, 4662306a36Sopenharmony_ci { USB_DEVICE(0x14ea, 0xab10), .driver_info = DEVICE_ZD1211 }, 4762306a36Sopenharmony_ci { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, 4862306a36Sopenharmony_ci { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, 4962306a36Sopenharmony_ci { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, 5062306a36Sopenharmony_ci { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, 5162306a36Sopenharmony_ci { USB_DEVICE(0x157e, 0x3207), .driver_info = DEVICE_ZD1211 }, 5262306a36Sopenharmony_ci { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, 5362306a36Sopenharmony_ci { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, 5462306a36Sopenharmony_ci /* ZD1211B */ 5562306a36Sopenharmony_ci { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B }, 5662306a36Sopenharmony_ci { USB_DEVICE(0x0409, 0x0248), .driver_info = DEVICE_ZD1211B }, 5762306a36Sopenharmony_ci { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B }, 5862306a36Sopenharmony_ci { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, 5962306a36Sopenharmony_ci { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B }, 6062306a36Sopenharmony_ci { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, 6162306a36Sopenharmony_ci { USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B }, 6262306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B }, 6362306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, 6462306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, 6562306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, 6662306a36Sopenharmony_ci { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B }, 6762306a36Sopenharmony_ci { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, 6862306a36Sopenharmony_ci { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B }, 6962306a36Sopenharmony_ci { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, 7062306a36Sopenharmony_ci { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B }, 7162306a36Sopenharmony_ci { USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B }, 7262306a36Sopenharmony_ci { USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B }, 7362306a36Sopenharmony_ci { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, 7462306a36Sopenharmony_ci { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B }, 7562306a36Sopenharmony_ci { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, 7662306a36Sopenharmony_ci { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, 7762306a36Sopenharmony_ci { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B }, 7862306a36Sopenharmony_ci { USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B }, 7962306a36Sopenharmony_ci { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B }, 8062306a36Sopenharmony_ci { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, 8162306a36Sopenharmony_ci { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, 8262306a36Sopenharmony_ci { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, 8362306a36Sopenharmony_ci { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, 8462306a36Sopenharmony_ci { USB_DEVICE(0x2019, 0xed01), .driver_info = DEVICE_ZD1211B }, 8562306a36Sopenharmony_ci /* "Driverless" devices that need ejecting */ 8662306a36Sopenharmony_ci { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, 8762306a36Sopenharmony_ci { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, 8862306a36Sopenharmony_ci {} 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 9262306a36Sopenharmony_ciMODULE_DESCRIPTION("USB driver for devices with the ZD1211 chip."); 9362306a36Sopenharmony_ciMODULE_AUTHOR("Ulrich Kunitz"); 9462306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Drake"); 9562306a36Sopenharmony_ciMODULE_VERSION("1.0"); 9662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usb_ids); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define FW_ZD1211_PREFIX "zd1211/zd1211_" 9962306a36Sopenharmony_ci#define FW_ZD1211B_PREFIX "zd1211/zd1211b_" 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req, 10262306a36Sopenharmony_ci unsigned int count); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* USB device initialization */ 10562306a36Sopenharmony_cistatic void int_urb_complete(struct urb *urb); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int request_fw_file( 10862306a36Sopenharmony_ci const struct firmware **fw, const char *name, struct device *device) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci int r; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci dev_dbg_f(device, "fw name %s\n", name); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci r = request_firmware(fw, name, device); 11562306a36Sopenharmony_ci if (r) 11662306a36Sopenharmony_ci dev_err(device, 11762306a36Sopenharmony_ci "Could not load firmware file %s. Error number %d\n", 11862306a36Sopenharmony_ci name, r); 11962306a36Sopenharmony_ci return r; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic inline u16 get_bcdDevice(const struct usb_device *udev) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return le16_to_cpu(udev->descriptor.bcdDevice); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cienum upload_code_flags { 12862306a36Sopenharmony_ci REBOOT = 1, 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* Ensures that MAX_TRANSFER_SIZE is even. */ 13262306a36Sopenharmony_ci#define MAX_TRANSFER_SIZE (USB_MAX_TRANSFER_SIZE & ~1) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int upload_code(struct usb_device *udev, 13562306a36Sopenharmony_ci const u8 *data, size_t size, u16 code_offset, int flags) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci u8 *p; 13862306a36Sopenharmony_ci int r; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* USB request blocks need "kmalloced" buffers. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL); 14362306a36Sopenharmony_ci if (!p) { 14462306a36Sopenharmony_ci r = -ENOMEM; 14562306a36Sopenharmony_ci goto error; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci size &= ~1; 14962306a36Sopenharmony_ci while (size > 0) { 15062306a36Sopenharmony_ci size_t transfer_size = size <= MAX_TRANSFER_SIZE ? 15162306a36Sopenharmony_ci size : MAX_TRANSFER_SIZE; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci dev_dbg_f(&udev->dev, "transfer size %zu\n", transfer_size); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci memcpy(p, data, transfer_size); 15662306a36Sopenharmony_ci r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 15762306a36Sopenharmony_ci USB_REQ_FIRMWARE_DOWNLOAD, 15862306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR, 15962306a36Sopenharmony_ci code_offset, 0, p, transfer_size, 1000 /* ms */); 16062306a36Sopenharmony_ci if (r < 0) { 16162306a36Sopenharmony_ci dev_err(&udev->dev, 16262306a36Sopenharmony_ci "USB control request for firmware upload" 16362306a36Sopenharmony_ci " failed. Error number %d\n", r); 16462306a36Sopenharmony_ci goto error; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci transfer_size = r & ~1; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci size -= transfer_size; 16962306a36Sopenharmony_ci data += transfer_size; 17062306a36Sopenharmony_ci code_offset += transfer_size/sizeof(u16); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (flags & REBOOT) { 17462306a36Sopenharmony_ci u8 ret; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Use "DMA-aware" buffer. */ 17762306a36Sopenharmony_ci r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 17862306a36Sopenharmony_ci USB_REQ_FIRMWARE_CONFIRM, 17962306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR, 18062306a36Sopenharmony_ci 0, 0, p, sizeof(ret), 5000 /* ms */); 18162306a36Sopenharmony_ci if (r != sizeof(ret)) { 18262306a36Sopenharmony_ci dev_err(&udev->dev, 18362306a36Sopenharmony_ci "control request firmware confirmation failed." 18462306a36Sopenharmony_ci " Return value %d\n", r); 18562306a36Sopenharmony_ci if (r >= 0) 18662306a36Sopenharmony_ci r = -ENODEV; 18762306a36Sopenharmony_ci goto error; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci ret = p[0]; 19062306a36Sopenharmony_ci if (ret & 0x80) { 19162306a36Sopenharmony_ci dev_err(&udev->dev, 19262306a36Sopenharmony_ci "Internal error while downloading." 19362306a36Sopenharmony_ci " Firmware confirm return value %#04x\n", 19462306a36Sopenharmony_ci (unsigned int)ret); 19562306a36Sopenharmony_ci r = -ENODEV; 19662306a36Sopenharmony_ci goto error; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci dev_dbg_f(&udev->dev, "firmware confirm return value %#04x\n", 19962306a36Sopenharmony_ci (unsigned int)ret); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci r = 0; 20362306a36Sopenharmony_cierror: 20462306a36Sopenharmony_ci kfree(p); 20562306a36Sopenharmony_ci return r; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic u16 get_word(const void *data, u16 offset) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci const __le16 *p = data; 21162306a36Sopenharmony_ci return le16_to_cpu(p[offset]); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic char *get_fw_name(struct zd_usb *usb, char *buffer, size_t size, 21562306a36Sopenharmony_ci const char* postfix) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci scnprintf(buffer, size, "%s%s", 21862306a36Sopenharmony_ci usb->is_zd1211b ? 21962306a36Sopenharmony_ci FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX, 22062306a36Sopenharmony_ci postfix); 22162306a36Sopenharmony_ci return buffer; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int handle_version_mismatch(struct zd_usb *usb, 22562306a36Sopenharmony_ci const struct firmware *ub_fw) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 22862306a36Sopenharmony_ci const struct firmware *ur_fw = NULL; 22962306a36Sopenharmony_ci int offset; 23062306a36Sopenharmony_ci int r = 0; 23162306a36Sopenharmony_ci char fw_name[128]; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci r = request_fw_file(&ur_fw, 23462306a36Sopenharmony_ci get_fw_name(usb, fw_name, sizeof(fw_name), "ur"), 23562306a36Sopenharmony_ci &udev->dev); 23662306a36Sopenharmony_ci if (r) 23762306a36Sopenharmony_ci goto error; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT); 24062306a36Sopenharmony_ci if (r) 24162306a36Sopenharmony_ci goto error; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16)); 24462306a36Sopenharmony_ci r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset, 24562306a36Sopenharmony_ci E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* At this point, the vendor driver downloads the whole firmware 24862306a36Sopenharmony_ci * image, hacks around with version IDs, and uploads it again, 24962306a36Sopenharmony_ci * completely overwriting the boot code. We do not do this here as 25062306a36Sopenharmony_ci * it is not required on any tested devices, and it is suspected to 25162306a36Sopenharmony_ci * cause problems. */ 25262306a36Sopenharmony_cierror: 25362306a36Sopenharmony_ci release_firmware(ur_fw); 25462306a36Sopenharmony_ci return r; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int upload_firmware(struct zd_usb *usb) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci int r; 26062306a36Sopenharmony_ci u16 fw_bcdDevice; 26162306a36Sopenharmony_ci u16 bcdDevice; 26262306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 26362306a36Sopenharmony_ci const struct firmware *ub_fw = NULL; 26462306a36Sopenharmony_ci const struct firmware *uph_fw = NULL; 26562306a36Sopenharmony_ci char fw_name[128]; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci bcdDevice = get_bcdDevice(udev); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci r = request_fw_file(&ub_fw, 27062306a36Sopenharmony_ci get_fw_name(usb, fw_name, sizeof(fw_name), "ub"), 27162306a36Sopenharmony_ci &udev->dev); 27262306a36Sopenharmony_ci if (r) 27362306a36Sopenharmony_ci goto error; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (fw_bcdDevice != bcdDevice) { 27862306a36Sopenharmony_ci dev_info(&udev->dev, 27962306a36Sopenharmony_ci "firmware version %#06x and device bootcode version " 28062306a36Sopenharmony_ci "%#06x differ\n", fw_bcdDevice, bcdDevice); 28162306a36Sopenharmony_ci if (bcdDevice <= 0x4313) 28262306a36Sopenharmony_ci dev_warn(&udev->dev, "device has old bootcode, please " 28362306a36Sopenharmony_ci "report success or failure\n"); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci r = handle_version_mismatch(usb, ub_fw); 28662306a36Sopenharmony_ci if (r) 28762306a36Sopenharmony_ci goto error; 28862306a36Sopenharmony_ci } else { 28962306a36Sopenharmony_ci dev_dbg_f(&udev->dev, 29062306a36Sopenharmony_ci "firmware device id %#06x is equal to the " 29162306a36Sopenharmony_ci "actual device id\n", fw_bcdDevice); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci r = request_fw_file(&uph_fw, 29662306a36Sopenharmony_ci get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"), 29762306a36Sopenharmony_ci &udev->dev); 29862306a36Sopenharmony_ci if (r) 29962306a36Sopenharmony_ci goto error; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT); 30262306a36Sopenharmony_ci if (r) { 30362306a36Sopenharmony_ci dev_err(&udev->dev, 30462306a36Sopenharmony_ci "Could not upload firmware code uph. Error number %d\n", 30562306a36Sopenharmony_ci r); 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* FALL-THROUGH */ 30962306a36Sopenharmony_cierror: 31062306a36Sopenharmony_ci release_firmware(ub_fw); 31162306a36Sopenharmony_ci release_firmware(uph_fw); 31262306a36Sopenharmony_ci return r; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ciMODULE_FIRMWARE(FW_ZD1211B_PREFIX "ur"); 31662306a36Sopenharmony_ciMODULE_FIRMWARE(FW_ZD1211_PREFIX "ur"); 31762306a36Sopenharmony_ciMODULE_FIRMWARE(FW_ZD1211B_PREFIX "ub"); 31862306a36Sopenharmony_ciMODULE_FIRMWARE(FW_ZD1211_PREFIX "ub"); 31962306a36Sopenharmony_ciMODULE_FIRMWARE(FW_ZD1211B_PREFIX "uphr"); 32062306a36Sopenharmony_ciMODULE_FIRMWARE(FW_ZD1211_PREFIX "uphr"); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* Read data from device address space using "firmware interface" which does 32362306a36Sopenharmony_ci * not require firmware to be loaded. */ 32462306a36Sopenharmony_ciint zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci int r; 32762306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 32862306a36Sopenharmony_ci u8 *buf; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Use "DMA-aware" buffer. */ 33162306a36Sopenharmony_ci buf = kmalloc(len, GFP_KERNEL); 33262306a36Sopenharmony_ci if (!buf) 33362306a36Sopenharmony_ci return -ENOMEM; 33462306a36Sopenharmony_ci r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 33562306a36Sopenharmony_ci USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0, 33662306a36Sopenharmony_ci buf, len, 5000); 33762306a36Sopenharmony_ci if (r < 0) { 33862306a36Sopenharmony_ci dev_err(&udev->dev, 33962306a36Sopenharmony_ci "read over firmware interface failed: %d\n", r); 34062306a36Sopenharmony_ci goto exit; 34162306a36Sopenharmony_ci } else if (r != len) { 34262306a36Sopenharmony_ci dev_err(&udev->dev, 34362306a36Sopenharmony_ci "incomplete read over firmware interface: %d/%d\n", 34462306a36Sopenharmony_ci r, len); 34562306a36Sopenharmony_ci r = -EIO; 34662306a36Sopenharmony_ci goto exit; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci r = 0; 34962306a36Sopenharmony_ci memcpy(data, buf, len); 35062306a36Sopenharmony_ciexit: 35162306a36Sopenharmony_ci kfree(buf); 35262306a36Sopenharmony_ci return r; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci#define urb_dev(urb) (&(urb)->dev->dev) 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic inline void handle_regs_int_override(struct urb *urb) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct zd_usb *usb = urb->context; 36062306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 36162306a36Sopenharmony_ci unsigned long flags; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci spin_lock_irqsave(&intr->lock, flags); 36462306a36Sopenharmony_ci if (atomic_read(&intr->read_regs_enabled)) { 36562306a36Sopenharmony_ci atomic_set(&intr->read_regs_enabled, 0); 36662306a36Sopenharmony_ci intr->read_regs_int_overridden = 1; 36762306a36Sopenharmony_ci complete(&intr->read_regs.completion); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci spin_unlock_irqrestore(&intr->lock, flags); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic inline void handle_regs_int(struct urb *urb) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct zd_usb *usb = urb->context; 37562306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 37662306a36Sopenharmony_ci unsigned long flags; 37762306a36Sopenharmony_ci int len; 37862306a36Sopenharmony_ci u16 int_num; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci spin_lock_irqsave(&intr->lock, flags); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); 38362306a36Sopenharmony_ci if (int_num == CR_INTERRUPT) { 38462306a36Sopenharmony_ci struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context)); 38562306a36Sopenharmony_ci spin_lock(&mac->lock); 38662306a36Sopenharmony_ci memcpy(&mac->intr_buffer, urb->transfer_buffer, 38762306a36Sopenharmony_ci USB_MAX_EP_INT_BUFFER); 38862306a36Sopenharmony_ci spin_unlock(&mac->lock); 38962306a36Sopenharmony_ci schedule_work(&mac->process_intr); 39062306a36Sopenharmony_ci } else if (atomic_read(&intr->read_regs_enabled)) { 39162306a36Sopenharmony_ci len = urb->actual_length; 39262306a36Sopenharmony_ci intr->read_regs.length = urb->actual_length; 39362306a36Sopenharmony_ci if (len > sizeof(intr->read_regs.buffer)) 39462306a36Sopenharmony_ci len = sizeof(intr->read_regs.buffer); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci memcpy(intr->read_regs.buffer, urb->transfer_buffer, len); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* Sometimes USB_INT_ID_REGS is not overridden, but comes after 39962306a36Sopenharmony_ci * USB_INT_ID_RETRY_FAILED. Read-reg retry then gets this 40062306a36Sopenharmony_ci * delayed USB_INT_ID_REGS, but leaves USB_INT_ID_REGS of 40162306a36Sopenharmony_ci * retry unhandled. Next read-reg command then might catch 40262306a36Sopenharmony_ci * this wrong USB_INT_ID_REGS. Fix by ignoring wrong reads. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci if (!check_read_regs(usb, intr->read_regs.req, 40562306a36Sopenharmony_ci intr->read_regs.req_count)) 40662306a36Sopenharmony_ci goto out; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci atomic_set(&intr->read_regs_enabled, 0); 40962306a36Sopenharmony_ci intr->read_regs_int_overridden = 0; 41062306a36Sopenharmony_ci complete(&intr->read_regs.completion); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci goto out; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ciout: 41662306a36Sopenharmony_ci spin_unlock_irqrestore(&intr->lock, flags); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* CR_INTERRUPT might override read_reg too. */ 41962306a36Sopenharmony_ci if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled)) 42062306a36Sopenharmony_ci handle_regs_int_override(urb); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void int_urb_complete(struct urb *urb) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci int r; 42662306a36Sopenharmony_ci struct usb_int_header *hdr; 42762306a36Sopenharmony_ci struct zd_usb *usb; 42862306a36Sopenharmony_ci struct zd_usb_interrupt *intr; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci switch (urb->status) { 43162306a36Sopenharmony_ci case 0: 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case -ESHUTDOWN: 43462306a36Sopenharmony_ci case -EINVAL: 43562306a36Sopenharmony_ci case -ENODEV: 43662306a36Sopenharmony_ci case -ENOENT: 43762306a36Sopenharmony_ci case -ECONNRESET: 43862306a36Sopenharmony_ci case -EPIPE: 43962306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); 44062306a36Sopenharmony_ci return; 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); 44362306a36Sopenharmony_ci goto resubmit; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (urb->actual_length < sizeof(hdr)) { 44762306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb); 44862306a36Sopenharmony_ci goto resubmit; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci hdr = urb->transfer_buffer; 45262306a36Sopenharmony_ci if (hdr->type != USB_INT_TYPE) { 45362306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb); 45462306a36Sopenharmony_ci goto resubmit; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* USB_INT_ID_RETRY_FAILED triggered by tx-urb submit can override 45862306a36Sopenharmony_ci * pending USB_INT_ID_REGS causing read command timeout. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci usb = urb->context; 46162306a36Sopenharmony_ci intr = &usb->intr; 46262306a36Sopenharmony_ci if (hdr->id != USB_INT_ID_REGS && atomic_read(&intr->read_regs_enabled)) 46362306a36Sopenharmony_ci handle_regs_int_override(urb); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci switch (hdr->id) { 46662306a36Sopenharmony_ci case USB_INT_ID_REGS: 46762306a36Sopenharmony_ci handle_regs_int(urb); 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci case USB_INT_ID_RETRY_FAILED: 47062306a36Sopenharmony_ci zd_mac_tx_failed(urb); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci default: 47362306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb, 47462306a36Sopenharmony_ci (unsigned int)hdr->id); 47562306a36Sopenharmony_ci goto resubmit; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciresubmit: 47962306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 48062306a36Sopenharmony_ci if (r) { 48162306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "error: resubmit urb %p err code %d\n", 48262306a36Sopenharmony_ci urb, r); 48362306a36Sopenharmony_ci /* TODO: add worker to reset intr->urb */ 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci return; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic inline int int_urb_interval(struct usb_device *udev) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci switch (udev->speed) { 49162306a36Sopenharmony_ci case USB_SPEED_HIGH: 49262306a36Sopenharmony_ci return 4; 49362306a36Sopenharmony_ci case USB_SPEED_LOW: 49462306a36Sopenharmony_ci return 10; 49562306a36Sopenharmony_ci case USB_SPEED_FULL: 49662306a36Sopenharmony_ci default: 49762306a36Sopenharmony_ci return 1; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic inline int usb_int_enabled(struct zd_usb *usb) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci unsigned long flags; 50462306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 50562306a36Sopenharmony_ci struct urb *urb; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci spin_lock_irqsave(&intr->lock, flags); 50862306a36Sopenharmony_ci urb = intr->urb; 50962306a36Sopenharmony_ci spin_unlock_irqrestore(&intr->lock, flags); 51062306a36Sopenharmony_ci return urb != NULL; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ciint zd_usb_enable_int(struct zd_usb *usb) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci int r; 51662306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 51762306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 51862306a36Sopenharmony_ci struct urb *urb; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 52362306a36Sopenharmony_ci if (!urb) { 52462306a36Sopenharmony_ci r = -ENOMEM; 52562306a36Sopenharmony_ci goto out; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ZD_ASSERT(!irqs_disabled()); 52962306a36Sopenharmony_ci spin_lock_irq(&intr->lock); 53062306a36Sopenharmony_ci if (intr->urb) { 53162306a36Sopenharmony_ci spin_unlock_irq(&intr->lock); 53262306a36Sopenharmony_ci r = 0; 53362306a36Sopenharmony_ci goto error_free_urb; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci intr->urb = urb; 53662306a36Sopenharmony_ci spin_unlock_irq(&intr->lock); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci r = -ENOMEM; 53962306a36Sopenharmony_ci intr->buffer = usb_alloc_coherent(udev, USB_MAX_EP_INT_BUFFER, 54062306a36Sopenharmony_ci GFP_KERNEL, &intr->buffer_dma); 54162306a36Sopenharmony_ci if (!intr->buffer) { 54262306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 54362306a36Sopenharmony_ci "couldn't allocate transfer_buffer\n"); 54462306a36Sopenharmony_ci goto error_set_urb_null; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN), 54862306a36Sopenharmony_ci intr->buffer, USB_MAX_EP_INT_BUFFER, 54962306a36Sopenharmony_ci int_urb_complete, usb, 55062306a36Sopenharmony_ci intr->interval); 55162306a36Sopenharmony_ci urb->transfer_dma = intr->buffer_dma; 55262306a36Sopenharmony_ci urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); 55562306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_KERNEL); 55662306a36Sopenharmony_ci if (r) { 55762306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 55862306a36Sopenharmony_ci "Couldn't submit urb. Error number %d\n", r); 55962306a36Sopenharmony_ci goto error; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_cierror: 56462306a36Sopenharmony_ci usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, 56562306a36Sopenharmony_ci intr->buffer, intr->buffer_dma); 56662306a36Sopenharmony_cierror_set_urb_null: 56762306a36Sopenharmony_ci spin_lock_irq(&intr->lock); 56862306a36Sopenharmony_ci intr->urb = NULL; 56962306a36Sopenharmony_ci spin_unlock_irq(&intr->lock); 57062306a36Sopenharmony_cierror_free_urb: 57162306a36Sopenharmony_ci usb_free_urb(urb); 57262306a36Sopenharmony_ciout: 57362306a36Sopenharmony_ci return r; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_civoid zd_usb_disable_int(struct zd_usb *usb) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci unsigned long flags; 57962306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 58062306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 58162306a36Sopenharmony_ci struct urb *urb; 58262306a36Sopenharmony_ci void *buffer; 58362306a36Sopenharmony_ci dma_addr_t buffer_dma; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci spin_lock_irqsave(&intr->lock, flags); 58662306a36Sopenharmony_ci urb = intr->urb; 58762306a36Sopenharmony_ci if (!urb) { 58862306a36Sopenharmony_ci spin_unlock_irqrestore(&intr->lock, flags); 58962306a36Sopenharmony_ci return; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci intr->urb = NULL; 59262306a36Sopenharmony_ci buffer = intr->buffer; 59362306a36Sopenharmony_ci buffer_dma = intr->buffer_dma; 59462306a36Sopenharmony_ci intr->buffer = NULL; 59562306a36Sopenharmony_ci spin_unlock_irqrestore(&intr->lock, flags); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci usb_kill_urb(urb); 59862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb); 59962306a36Sopenharmony_ci usb_free_urb(urb); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, buffer, buffer_dma); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, 60562306a36Sopenharmony_ci unsigned int length) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci int i; 60862306a36Sopenharmony_ci const struct rx_length_info *length_info; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (length < sizeof(struct rx_length_info)) { 61162306a36Sopenharmony_ci /* It's not a complete packet anyhow. */ 61262306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "invalid, small RX packet : %d\n", 61362306a36Sopenharmony_ci length); 61462306a36Sopenharmony_ci return; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci length_info = (struct rx_length_info *) 61762306a36Sopenharmony_ci (buffer + length - sizeof(struct rx_length_info)); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* It might be that three frames are merged into a single URB 62062306a36Sopenharmony_ci * transaction. We have to check for the length info tag. 62162306a36Sopenharmony_ci * 62262306a36Sopenharmony_ci * While testing we discovered that length_info might be unaligned, 62362306a36Sopenharmony_ci * because if USB transactions are merged, the last packet will not 62462306a36Sopenharmony_ci * be padded. Unaligned access might also happen if the length_info 62562306a36Sopenharmony_ci * structure is not present. 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ci if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG) 62862306a36Sopenharmony_ci { 62962306a36Sopenharmony_ci unsigned int l, k, n; 63062306a36Sopenharmony_ci for (i = 0, l = 0;; i++) { 63162306a36Sopenharmony_ci k = get_unaligned_le16(&length_info->length[i]); 63262306a36Sopenharmony_ci if (k == 0) 63362306a36Sopenharmony_ci return; 63462306a36Sopenharmony_ci n = l+k; 63562306a36Sopenharmony_ci if (n > length) 63662306a36Sopenharmony_ci return; 63762306a36Sopenharmony_ci zd_mac_rx(zd_usb_to_hw(usb), buffer+l, k); 63862306a36Sopenharmony_ci if (i >= 2) 63962306a36Sopenharmony_ci return; 64062306a36Sopenharmony_ci l = (n+3) & ~3; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci } else { 64362306a36Sopenharmony_ci zd_mac_rx(zd_usb_to_hw(usb), buffer, length); 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void rx_urb_complete(struct urb *urb) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci int r; 65062306a36Sopenharmony_ci struct zd_usb *usb; 65162306a36Sopenharmony_ci struct zd_usb_rx *rx; 65262306a36Sopenharmony_ci const u8 *buffer; 65362306a36Sopenharmony_ci unsigned int length; 65462306a36Sopenharmony_ci unsigned long flags; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci switch (urb->status) { 65762306a36Sopenharmony_ci case 0: 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci case -ESHUTDOWN: 66062306a36Sopenharmony_ci case -EINVAL: 66162306a36Sopenharmony_ci case -ENODEV: 66262306a36Sopenharmony_ci case -ENOENT: 66362306a36Sopenharmony_ci case -ECONNRESET: 66462306a36Sopenharmony_ci case -EPIPE: 66562306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); 66662306a36Sopenharmony_ci return; 66762306a36Sopenharmony_ci default: 66862306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); 66962306a36Sopenharmony_ci goto resubmit; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci buffer = urb->transfer_buffer; 67362306a36Sopenharmony_ci length = urb->actual_length; 67462306a36Sopenharmony_ci usb = urb->context; 67562306a36Sopenharmony_ci rx = &usb->rx; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci tasklet_schedule(&rx->reset_timer_tasklet); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (length%rx->usb_packet_size > rx->usb_packet_size-4) { 68062306a36Sopenharmony_ci /* If there is an old first fragment, we don't care. */ 68162306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "*** first fragment ***\n"); 68262306a36Sopenharmony_ci ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment)); 68362306a36Sopenharmony_ci spin_lock_irqsave(&rx->lock, flags); 68462306a36Sopenharmony_ci memcpy(rx->fragment, buffer, length); 68562306a36Sopenharmony_ci rx->fragment_length = length; 68662306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 68762306a36Sopenharmony_ci goto resubmit; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci spin_lock_irqsave(&rx->lock, flags); 69162306a36Sopenharmony_ci if (rx->fragment_length > 0) { 69262306a36Sopenharmony_ci /* We are on a second fragment, we believe */ 69362306a36Sopenharmony_ci ZD_ASSERT(length + rx->fragment_length <= 69462306a36Sopenharmony_ci ARRAY_SIZE(rx->fragment)); 69562306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "*** second fragment ***\n"); 69662306a36Sopenharmony_ci memcpy(rx->fragment+rx->fragment_length, buffer, length); 69762306a36Sopenharmony_ci handle_rx_packet(usb, rx->fragment, 69862306a36Sopenharmony_ci rx->fragment_length + length); 69962306a36Sopenharmony_ci rx->fragment_length = 0; 70062306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 70162306a36Sopenharmony_ci } else { 70262306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 70362306a36Sopenharmony_ci handle_rx_packet(usb, buffer, length); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ciresubmit: 70762306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 70862306a36Sopenharmony_ci if (r) 70962306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p resubmit error %d\n", urb, r); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic struct urb *alloc_rx_urb(struct zd_usb *usb) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 71562306a36Sopenharmony_ci struct urb *urb; 71662306a36Sopenharmony_ci void *buffer; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 71962306a36Sopenharmony_ci if (!urb) 72062306a36Sopenharmony_ci return NULL; 72162306a36Sopenharmony_ci buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL, 72262306a36Sopenharmony_ci &urb->transfer_dma); 72362306a36Sopenharmony_ci if (!buffer) { 72462306a36Sopenharmony_ci usb_free_urb(urb); 72562306a36Sopenharmony_ci return NULL; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN), 72962306a36Sopenharmony_ci buffer, USB_MAX_RX_SIZE, 73062306a36Sopenharmony_ci rx_urb_complete, usb); 73162306a36Sopenharmony_ci urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci return urb; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic void free_rx_urb(struct urb *urb) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci if (!urb) 73962306a36Sopenharmony_ci return; 74062306a36Sopenharmony_ci usb_free_coherent(urb->dev, urb->transfer_buffer_length, 74162306a36Sopenharmony_ci urb->transfer_buffer, urb->transfer_dma); 74262306a36Sopenharmony_ci usb_free_urb(urb); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int __zd_usb_enable_rx(struct zd_usb *usb) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci int i, r; 74862306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 74962306a36Sopenharmony_ci struct urb **urbs; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci r = -ENOMEM; 75462306a36Sopenharmony_ci urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); 75562306a36Sopenharmony_ci if (!urbs) 75662306a36Sopenharmony_ci goto error; 75762306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) { 75862306a36Sopenharmony_ci urbs[i] = alloc_rx_urb(usb); 75962306a36Sopenharmony_ci if (!urbs[i]) 76062306a36Sopenharmony_ci goto error; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ZD_ASSERT(!irqs_disabled()); 76462306a36Sopenharmony_ci spin_lock_irq(&rx->lock); 76562306a36Sopenharmony_ci if (rx->urbs) { 76662306a36Sopenharmony_ci spin_unlock_irq(&rx->lock); 76762306a36Sopenharmony_ci r = 0; 76862306a36Sopenharmony_ci goto error; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci rx->urbs = urbs; 77162306a36Sopenharmony_ci rx->urbs_count = RX_URBS_COUNT; 77262306a36Sopenharmony_ci spin_unlock_irq(&rx->lock); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) { 77562306a36Sopenharmony_ci r = usb_submit_urb(urbs[i], GFP_KERNEL); 77662306a36Sopenharmony_ci if (r) 77762306a36Sopenharmony_ci goto error_submit; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return 0; 78162306a36Sopenharmony_cierror_submit: 78262306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) { 78362306a36Sopenharmony_ci usb_kill_urb(urbs[i]); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci spin_lock_irq(&rx->lock); 78662306a36Sopenharmony_ci rx->urbs = NULL; 78762306a36Sopenharmony_ci rx->urbs_count = 0; 78862306a36Sopenharmony_ci spin_unlock_irq(&rx->lock); 78962306a36Sopenharmony_cierror: 79062306a36Sopenharmony_ci if (urbs) { 79162306a36Sopenharmony_ci for (i = 0; i < RX_URBS_COUNT; i++) 79262306a36Sopenharmony_ci free_rx_urb(urbs[i]); 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci return r; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ciint zd_usb_enable_rx(struct zd_usb *usb) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci int r; 80062306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci mutex_lock(&rx->setup_mutex); 80362306a36Sopenharmony_ci r = __zd_usb_enable_rx(usb); 80462306a36Sopenharmony_ci mutex_unlock(&rx->setup_mutex); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci zd_usb_reset_rx_idle_timer(usb); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return r; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic void __zd_usb_disable_rx(struct zd_usb *usb) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci int i; 81462306a36Sopenharmony_ci unsigned long flags; 81562306a36Sopenharmony_ci struct urb **urbs; 81662306a36Sopenharmony_ci unsigned int count; 81762306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci spin_lock_irqsave(&rx->lock, flags); 82062306a36Sopenharmony_ci urbs = rx->urbs; 82162306a36Sopenharmony_ci count = rx->urbs_count; 82262306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 82362306a36Sopenharmony_ci if (!urbs) 82462306a36Sopenharmony_ci return; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci for (i = 0; i < count; i++) { 82762306a36Sopenharmony_ci usb_kill_urb(urbs[i]); 82862306a36Sopenharmony_ci free_rx_urb(urbs[i]); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci kfree(urbs); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci spin_lock_irqsave(&rx->lock, flags); 83362306a36Sopenharmony_ci rx->urbs = NULL; 83462306a36Sopenharmony_ci rx->urbs_count = 0; 83562306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_civoid zd_usb_disable_rx(struct zd_usb *usb) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci mutex_lock(&rx->setup_mutex); 84362306a36Sopenharmony_ci __zd_usb_disable_rx(usb); 84462306a36Sopenharmony_ci mutex_unlock(&rx->setup_mutex); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci tasklet_kill(&rx->reset_timer_tasklet); 84762306a36Sopenharmony_ci cancel_delayed_work_sync(&rx->idle_work); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic void zd_usb_reset_rx(struct zd_usb *usb) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci bool do_reset; 85362306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 85462306a36Sopenharmony_ci unsigned long flags; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci mutex_lock(&rx->setup_mutex); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci spin_lock_irqsave(&rx->lock, flags); 85962306a36Sopenharmony_ci do_reset = rx->urbs != NULL; 86062306a36Sopenharmony_ci spin_unlock_irqrestore(&rx->lock, flags); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (do_reset) { 86362306a36Sopenharmony_ci __zd_usb_disable_rx(usb); 86462306a36Sopenharmony_ci __zd_usb_enable_rx(usb); 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci mutex_unlock(&rx->setup_mutex); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (do_reset) 87062306a36Sopenharmony_ci zd_usb_reset_rx_idle_timer(usb); 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci/** 87462306a36Sopenharmony_ci * zd_usb_disable_tx - disable transmission 87562306a36Sopenharmony_ci * @usb: the zd1211rw-private USB structure 87662306a36Sopenharmony_ci * 87762306a36Sopenharmony_ci * Frees all URBs in the free list and marks the transmission as disabled. 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_civoid zd_usb_disable_tx(struct zd_usb *usb) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 88262306a36Sopenharmony_ci unsigned long flags; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci atomic_set(&tx->enabled, 0); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* kill all submitted tx-urbs */ 88762306a36Sopenharmony_ci usb_kill_anchored_urbs(&tx->submitted); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 89062306a36Sopenharmony_ci WARN_ON(!skb_queue_empty(&tx->submitted_skbs)); 89162306a36Sopenharmony_ci WARN_ON(tx->submitted_urbs != 0); 89262306a36Sopenharmony_ci tx->submitted_urbs = 0; 89362306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* The stopped state is ignored, relying on ieee80211_wake_queues() 89662306a36Sopenharmony_ci * in a potentionally following zd_usb_enable_tx(). 89762306a36Sopenharmony_ci */ 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/** 90162306a36Sopenharmony_ci * zd_usb_enable_tx - enables transmission 90262306a36Sopenharmony_ci * @usb: a &struct zd_usb pointer 90362306a36Sopenharmony_ci * 90462306a36Sopenharmony_ci * This function enables transmission and prepares the &zd_usb_tx data 90562306a36Sopenharmony_ci * structure. 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_civoid zd_usb_enable_tx(struct zd_usb *usb) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci unsigned long flags; 91062306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 91362306a36Sopenharmony_ci atomic_set(&tx->enabled, 1); 91462306a36Sopenharmony_ci tx->submitted_urbs = 0; 91562306a36Sopenharmony_ci ieee80211_wake_queues(zd_usb_to_hw(usb)); 91662306a36Sopenharmony_ci tx->stopped = 0; 91762306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic void tx_dec_submitted_urbs(struct zd_usb *usb) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 92362306a36Sopenharmony_ci unsigned long flags; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 92662306a36Sopenharmony_ci --tx->submitted_urbs; 92762306a36Sopenharmony_ci if (tx->stopped && tx->submitted_urbs <= ZD_USB_TX_LOW) { 92862306a36Sopenharmony_ci ieee80211_wake_queues(zd_usb_to_hw(usb)); 92962306a36Sopenharmony_ci tx->stopped = 0; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic void tx_inc_submitted_urbs(struct zd_usb *usb) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 93762306a36Sopenharmony_ci unsigned long flags; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci spin_lock_irqsave(&tx->lock, flags); 94062306a36Sopenharmony_ci ++tx->submitted_urbs; 94162306a36Sopenharmony_ci if (!tx->stopped && tx->submitted_urbs > ZD_USB_TX_HIGH) { 94262306a36Sopenharmony_ci ieee80211_stop_queues(zd_usb_to_hw(usb)); 94362306a36Sopenharmony_ci tx->stopped = 1; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci spin_unlock_irqrestore(&tx->lock, flags); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci/** 94962306a36Sopenharmony_ci * tx_urb_complete - completes the execution of an URB 95062306a36Sopenharmony_ci * @urb: a URB 95162306a36Sopenharmony_ci * 95262306a36Sopenharmony_ci * This function is called if the URB has been transferred to a device or an 95362306a36Sopenharmony_ci * error has happened. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_cistatic void tx_urb_complete(struct urb *urb) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci int r; 95862306a36Sopenharmony_ci struct sk_buff *skb; 95962306a36Sopenharmony_ci struct ieee80211_tx_info *info; 96062306a36Sopenharmony_ci struct zd_usb *usb; 96162306a36Sopenharmony_ci struct zd_usb_tx *tx; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci skb = (struct sk_buff *)urb->context; 96462306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * grab 'usb' pointer before handing off the skb (since 96762306a36Sopenharmony_ci * it might be freed by zd_mac_tx_to_dev or mac80211) 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; 97062306a36Sopenharmony_ci tx = &usb->tx; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci switch (urb->status) { 97362306a36Sopenharmony_ci case 0: 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci case -ESHUTDOWN: 97662306a36Sopenharmony_ci case -EINVAL: 97762306a36Sopenharmony_ci case -ENODEV: 97862306a36Sopenharmony_ci case -ENOENT: 97962306a36Sopenharmony_ci case -ECONNRESET: 98062306a36Sopenharmony_ci case -EPIPE: 98162306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci default: 98462306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); 98562306a36Sopenharmony_ci goto resubmit; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_cifree_urb: 98862306a36Sopenharmony_ci skb_unlink(skb, &usb->tx.submitted_skbs); 98962306a36Sopenharmony_ci zd_mac_tx_to_dev(skb, urb->status); 99062306a36Sopenharmony_ci usb_free_urb(urb); 99162306a36Sopenharmony_ci tx_dec_submitted_urbs(usb); 99262306a36Sopenharmony_ci return; 99362306a36Sopenharmony_ciresubmit: 99462306a36Sopenharmony_ci usb_anchor_urb(urb, &tx->submitted); 99562306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 99662306a36Sopenharmony_ci if (r) { 99762306a36Sopenharmony_ci usb_unanchor_urb(urb); 99862306a36Sopenharmony_ci dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r); 99962306a36Sopenharmony_ci goto free_urb; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci/** 100462306a36Sopenharmony_ci * zd_usb_tx: initiates transfer of a frame of the device 100562306a36Sopenharmony_ci * 100662306a36Sopenharmony_ci * @usb: the zd1211rw-private USB structure 100762306a36Sopenharmony_ci * @skb: a &struct sk_buff pointer 100862306a36Sopenharmony_ci * 100962306a36Sopenharmony_ci * This function transmits a frame to the device. It doesn't wait for 101062306a36Sopenharmony_ci * completion. The frame must contain the control set and have all the 101162306a36Sopenharmony_ci * control set information available. 101262306a36Sopenharmony_ci * 101362306a36Sopenharmony_ci * The function returns 0 if the transfer has been successfully initiated. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ciint zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci int r; 101862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 101962306a36Sopenharmony_ci struct usb_device *udev = zd_usb_to_usbdev(usb); 102062306a36Sopenharmony_ci struct urb *urb; 102162306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (!atomic_read(&tx->enabled)) { 102462306a36Sopenharmony_ci r = -ENOENT; 102562306a36Sopenharmony_ci goto out; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 102962306a36Sopenharmony_ci if (!urb) { 103062306a36Sopenharmony_ci r = -ENOMEM; 103162306a36Sopenharmony_ci goto out; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), 103562306a36Sopenharmony_ci skb->data, skb->len, tx_urb_complete, skb); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci info->rate_driver_data[1] = (void *)jiffies; 103862306a36Sopenharmony_ci skb_queue_tail(&tx->submitted_skbs, skb); 103962306a36Sopenharmony_ci usb_anchor_urb(urb, &tx->submitted); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_ATOMIC); 104262306a36Sopenharmony_ci if (r) { 104362306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "error submit urb %p %d\n", urb, r); 104462306a36Sopenharmony_ci usb_unanchor_urb(urb); 104562306a36Sopenharmony_ci skb_unlink(skb, &tx->submitted_skbs); 104662306a36Sopenharmony_ci goto error; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci tx_inc_submitted_urbs(usb); 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_cierror: 105162306a36Sopenharmony_ci usb_free_urb(urb); 105262306a36Sopenharmony_ciout: 105362306a36Sopenharmony_ci return r; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic bool zd_tx_timeout(struct zd_usb *usb) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 105962306a36Sopenharmony_ci struct sk_buff_head *q = &tx->submitted_skbs; 106062306a36Sopenharmony_ci struct sk_buff *skb, *skbnext; 106162306a36Sopenharmony_ci struct ieee80211_tx_info *info; 106262306a36Sopenharmony_ci unsigned long flags, trans_start; 106362306a36Sopenharmony_ci bool have_timedout = false; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci spin_lock_irqsave(&q->lock, flags); 106662306a36Sopenharmony_ci skb_queue_walk_safe(q, skb, skbnext) { 106762306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 106862306a36Sopenharmony_ci trans_start = (unsigned long)info->rate_driver_data[1]; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (time_is_before_jiffies(trans_start + ZD_TX_TIMEOUT)) { 107162306a36Sopenharmony_ci have_timedout = true; 107262306a36Sopenharmony_ci break; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci spin_unlock_irqrestore(&q->lock, flags); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci return have_timedout; 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic void zd_tx_watchdog_handler(struct work_struct *work) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci struct zd_usb *usb = 108362306a36Sopenharmony_ci container_of(work, struct zd_usb, tx.watchdog_work.work); 108462306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (!atomic_read(&tx->enabled) || !tx->watchdog_enabled) 108762306a36Sopenharmony_ci goto out; 108862306a36Sopenharmony_ci if (!zd_tx_timeout(usb)) 108962306a36Sopenharmony_ci goto out; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* TX halted, try reset */ 109262306a36Sopenharmony_ci dev_warn(zd_usb_dev(usb), "TX-stall detected, resetting device..."); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci usb_queue_reset_device(usb->intf); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* reset will stop this worker, don't rearm */ 109762306a36Sopenharmony_ci return; 109862306a36Sopenharmony_ciout: 109962306a36Sopenharmony_ci queue_delayed_work(zd_workqueue, &tx->watchdog_work, 110062306a36Sopenharmony_ci ZD_TX_WATCHDOG_INTERVAL); 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_civoid zd_tx_watchdog_enable(struct zd_usb *usb) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (!tx->watchdog_enabled) { 110862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 110962306a36Sopenharmony_ci queue_delayed_work(zd_workqueue, &tx->watchdog_work, 111062306a36Sopenharmony_ci ZD_TX_WATCHDOG_INTERVAL); 111162306a36Sopenharmony_ci tx->watchdog_enabled = 1; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_civoid zd_tx_watchdog_disable(struct zd_usb *usb) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (tx->watchdog_enabled) { 112062306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 112162306a36Sopenharmony_ci tx->watchdog_enabled = 0; 112262306a36Sopenharmony_ci cancel_delayed_work_sync(&tx->watchdog_work); 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic void zd_rx_idle_timer_handler(struct work_struct *work) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci struct zd_usb *usb = 112962306a36Sopenharmony_ci container_of(work, struct zd_usb, rx.idle_work.work); 113062306a36Sopenharmony_ci struct zd_mac *mac = zd_usb_to_mac(usb); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags)) 113362306a36Sopenharmony_ci return; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci /* 30 seconds since last rx, reset rx */ 113862306a36Sopenharmony_ci zd_usb_reset_rx(usb); 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic void zd_usb_reset_rx_idle_timer_tasklet(struct tasklet_struct *t) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct zd_usb *usb = from_tasklet(usb, t, rx.reset_timer_tasklet); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci zd_usb_reset_rx_idle_timer(usb); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_civoid zd_usb_reset_rx_idle_timer(struct zd_usb *usb) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci mod_delayed_work(zd_workqueue, &rx->idle_work, ZD_RX_IDLE_INTERVAL); 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic inline void init_usb_interrupt(struct zd_usb *usb) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci spin_lock_init(&intr->lock); 116062306a36Sopenharmony_ci intr->interval = int_urb_interval(zd_usb_to_usbdev(usb)); 116162306a36Sopenharmony_ci init_completion(&intr->read_regs.completion); 116262306a36Sopenharmony_ci atomic_set(&intr->read_regs_enabled, 0); 116362306a36Sopenharmony_ci intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT); 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic inline void init_usb_rx(struct zd_usb *usb) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct zd_usb_rx *rx = &usb->rx; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci spin_lock_init(&rx->lock); 117162306a36Sopenharmony_ci mutex_init(&rx->setup_mutex); 117262306a36Sopenharmony_ci if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) { 117362306a36Sopenharmony_ci rx->usb_packet_size = 512; 117462306a36Sopenharmony_ci } else { 117562306a36Sopenharmony_ci rx->usb_packet_size = 64; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci ZD_ASSERT(rx->fragment_length == 0); 117862306a36Sopenharmony_ci INIT_DELAYED_WORK(&rx->idle_work, zd_rx_idle_timer_handler); 117962306a36Sopenharmony_ci rx->reset_timer_tasklet.func = (void (*)) 118062306a36Sopenharmony_ci zd_usb_reset_rx_idle_timer_tasklet; 118162306a36Sopenharmony_ci rx->reset_timer_tasklet.data = (unsigned long)&rx->reset_timer_tasklet; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic inline void init_usb_tx(struct zd_usb *usb) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci struct zd_usb_tx *tx = &usb->tx; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci spin_lock_init(&tx->lock); 118962306a36Sopenharmony_ci atomic_set(&tx->enabled, 0); 119062306a36Sopenharmony_ci tx->stopped = 0; 119162306a36Sopenharmony_ci skb_queue_head_init(&tx->submitted_skbs); 119262306a36Sopenharmony_ci init_usb_anchor(&tx->submitted); 119362306a36Sopenharmony_ci tx->submitted_urbs = 0; 119462306a36Sopenharmony_ci tx->watchdog_enabled = 0; 119562306a36Sopenharmony_ci INIT_DELAYED_WORK(&tx->watchdog_work, zd_tx_watchdog_handler); 119662306a36Sopenharmony_ci} 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_civoid zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, 119962306a36Sopenharmony_ci struct usb_interface *intf) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci memset(usb, 0, sizeof(*usb)); 120262306a36Sopenharmony_ci usb->intf = usb_get_intf(intf); 120362306a36Sopenharmony_ci usb_set_intfdata(usb->intf, hw); 120462306a36Sopenharmony_ci init_usb_anchor(&usb->submitted_cmds); 120562306a36Sopenharmony_ci init_usb_interrupt(usb); 120662306a36Sopenharmony_ci init_usb_tx(usb); 120762306a36Sopenharmony_ci init_usb_rx(usb); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_civoid zd_usb_clear(struct zd_usb *usb) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci usb_set_intfdata(usb->intf, NULL); 121362306a36Sopenharmony_ci usb_put_intf(usb->intf); 121462306a36Sopenharmony_ci ZD_MEMCLEAR(usb, sizeof(*usb)); 121562306a36Sopenharmony_ci /* FIXME: usb_interrupt, usb_tx, usb_rx? */ 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic const char *speed(enum usb_device_speed speed) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci switch (speed) { 122162306a36Sopenharmony_ci case USB_SPEED_LOW: 122262306a36Sopenharmony_ci return "low"; 122362306a36Sopenharmony_ci case USB_SPEED_FULL: 122462306a36Sopenharmony_ci return "full"; 122562306a36Sopenharmony_ci case USB_SPEED_HIGH: 122662306a36Sopenharmony_ci return "high"; 122762306a36Sopenharmony_ci default: 122862306a36Sopenharmony_ci return "unknown speed"; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic int scnprint_id(struct usb_device *udev, char *buffer, size_t size) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s", 123562306a36Sopenharmony_ci le16_to_cpu(udev->descriptor.idVendor), 123662306a36Sopenharmony_ci le16_to_cpu(udev->descriptor.idProduct), 123762306a36Sopenharmony_ci get_bcdDevice(udev), 123862306a36Sopenharmony_ci speed(udev->speed)); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ciint zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(usb->intf); 124462306a36Sopenharmony_ci return scnprint_id(udev, buffer, size); 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci#ifdef DEBUG 124862306a36Sopenharmony_cistatic void print_id(struct usb_device *udev) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci char buffer[40]; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci scnprint_id(udev, buffer, sizeof(buffer)); 125362306a36Sopenharmony_ci buffer[sizeof(buffer)-1] = 0; 125462306a36Sopenharmony_ci dev_dbg_f(&udev->dev, "%s\n", buffer); 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci#else 125762306a36Sopenharmony_ci#define print_id(udev) do { } while (0) 125862306a36Sopenharmony_ci#endif 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic int eject_installer(struct usb_interface *intf) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 126362306a36Sopenharmony_ci struct usb_host_interface *iface_desc = intf->cur_altsetting; 126462306a36Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 126562306a36Sopenharmony_ci unsigned char *cmd; 126662306a36Sopenharmony_ci u8 bulk_out_ep; 126762306a36Sopenharmony_ci int r; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (iface_desc->desc.bNumEndpoints < 2) 127062306a36Sopenharmony_ci return -ENODEV; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci /* Find bulk out endpoint */ 127362306a36Sopenharmony_ci for (r = 1; r >= 0; r--) { 127462306a36Sopenharmony_ci endpoint = &iface_desc->endpoint[r].desc; 127562306a36Sopenharmony_ci if (usb_endpoint_dir_out(endpoint) && 127662306a36Sopenharmony_ci usb_endpoint_xfer_bulk(endpoint)) { 127762306a36Sopenharmony_ci bulk_out_ep = endpoint->bEndpointAddress; 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci if (r == -1) { 128262306a36Sopenharmony_ci dev_err(&udev->dev, 128362306a36Sopenharmony_ci "zd1211rw: Could not find bulk out endpoint\n"); 128462306a36Sopenharmony_ci return -ENODEV; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci cmd = kzalloc(31, GFP_KERNEL); 128862306a36Sopenharmony_ci if (cmd == NULL) 128962306a36Sopenharmony_ci return -ENODEV; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci /* USB bulk command block */ 129262306a36Sopenharmony_ci cmd[0] = 0x55; /* bulk command signature */ 129362306a36Sopenharmony_ci cmd[1] = 0x53; /* bulk command signature */ 129462306a36Sopenharmony_ci cmd[2] = 0x42; /* bulk command signature */ 129562306a36Sopenharmony_ci cmd[3] = 0x43; /* bulk command signature */ 129662306a36Sopenharmony_ci cmd[14] = 6; /* command length */ 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */ 129962306a36Sopenharmony_ci cmd[19] = 0x2; /* eject disc */ 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci dev_info(&udev->dev, "Ejecting virtual installer media...\n"); 130262306a36Sopenharmony_ci r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep), 130362306a36Sopenharmony_ci cmd, 31, NULL, 2000); 130462306a36Sopenharmony_ci kfree(cmd); 130562306a36Sopenharmony_ci if (r) 130662306a36Sopenharmony_ci return r; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* At this point, the device disconnects and reconnects with the real 130962306a36Sopenharmony_ci * ID numbers. */ 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci usb_set_intfdata(intf, NULL); 131262306a36Sopenharmony_ci return 0; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ciint zd_usb_init_hw(struct zd_usb *usb) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci int r; 131862306a36Sopenharmony_ci struct zd_mac *mac = zd_usb_to_mac(usb); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci r = upload_firmware(usb); 132362306a36Sopenharmony_ci if (r) { 132462306a36Sopenharmony_ci dev_err(zd_usb_dev(usb), 132562306a36Sopenharmony_ci "couldn't load firmware. Error number %d\n", r); 132662306a36Sopenharmony_ci return r; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci r = usb_reset_configuration(zd_usb_to_usbdev(usb)); 133062306a36Sopenharmony_ci if (r) { 133162306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 133262306a36Sopenharmony_ci "couldn't reset configuration. Error number %d\n", r); 133362306a36Sopenharmony_ci return r; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci r = zd_mac_init_hw(mac->hw); 133762306a36Sopenharmony_ci if (r) { 133862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 133962306a36Sopenharmony_ci "couldn't initialize mac. Error number %d\n", r); 134062306a36Sopenharmony_ci return r; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci usb->initialized = 1; 134462306a36Sopenharmony_ci return 0; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int probe(struct usb_interface *intf, const struct usb_device_id *id) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci int r; 135062306a36Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 135162306a36Sopenharmony_ci struct zd_usb *usb; 135262306a36Sopenharmony_ci struct ieee80211_hw *hw = NULL; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci print_id(udev); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (id->driver_info & DEVICE_INSTALLER) 135762306a36Sopenharmony_ci return eject_installer(intf); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci switch (udev->speed) { 136062306a36Sopenharmony_ci case USB_SPEED_LOW: 136162306a36Sopenharmony_ci case USB_SPEED_FULL: 136262306a36Sopenharmony_ci case USB_SPEED_HIGH: 136362306a36Sopenharmony_ci break; 136462306a36Sopenharmony_ci default: 136562306a36Sopenharmony_ci dev_dbg_f(&intf->dev, "Unknown USB speed\n"); 136662306a36Sopenharmony_ci r = -ENODEV; 136762306a36Sopenharmony_ci goto error; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci r = usb_reset_device(udev); 137162306a36Sopenharmony_ci if (r) { 137262306a36Sopenharmony_ci dev_err(&intf->dev, 137362306a36Sopenharmony_ci "couldn't reset usb device. Error number %d\n", r); 137462306a36Sopenharmony_ci goto error; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci hw = zd_mac_alloc_hw(intf); 137862306a36Sopenharmony_ci if (hw == NULL) { 137962306a36Sopenharmony_ci r = -ENOMEM; 138062306a36Sopenharmony_ci goto error; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci usb = &zd_hw_mac(hw)->chip.usb; 138462306a36Sopenharmony_ci usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci r = zd_mac_preinit_hw(hw); 138762306a36Sopenharmony_ci if (r) { 138862306a36Sopenharmony_ci dev_dbg_f(&intf->dev, 138962306a36Sopenharmony_ci "couldn't initialize mac. Error number %d\n", r); 139062306a36Sopenharmony_ci goto error; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci r = ieee80211_register_hw(hw); 139462306a36Sopenharmony_ci if (r) { 139562306a36Sopenharmony_ci dev_dbg_f(&intf->dev, 139662306a36Sopenharmony_ci "couldn't register device. Error number %d\n", r); 139762306a36Sopenharmony_ci goto error; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci dev_dbg_f(&intf->dev, "successful\n"); 140162306a36Sopenharmony_ci dev_info(&intf->dev, "%s\n", wiphy_name(hw->wiphy)); 140262306a36Sopenharmony_ci return 0; 140362306a36Sopenharmony_cierror: 140462306a36Sopenharmony_ci usb_reset_device(interface_to_usbdev(intf)); 140562306a36Sopenharmony_ci if (hw) { 140662306a36Sopenharmony_ci zd_mac_clear(zd_hw_mac(hw)); 140762306a36Sopenharmony_ci ieee80211_free_hw(hw); 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci return r; 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic void disconnect(struct usb_interface *intf) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci struct ieee80211_hw *hw = zd_intf_to_hw(intf); 141562306a36Sopenharmony_ci struct zd_mac *mac; 141662306a36Sopenharmony_ci struct zd_usb *usb; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* Either something really bad happened, or we're just dealing with 141962306a36Sopenharmony_ci * a DEVICE_INSTALLER. */ 142062306a36Sopenharmony_ci if (hw == NULL) 142162306a36Sopenharmony_ci return; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci mac = zd_hw_mac(hw); 142462306a36Sopenharmony_ci usb = &mac->chip.usb; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Just in case something has gone wrong! */ 143162306a36Sopenharmony_ci zd_usb_disable_tx(usb); 143262306a36Sopenharmony_ci zd_usb_disable_rx(usb); 143362306a36Sopenharmony_ci zd_usb_disable_int(usb); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* If the disconnect has been caused by a removal of the 143662306a36Sopenharmony_ci * driver module, the reset allows reloading of the driver. If the 143762306a36Sopenharmony_ci * reset will not be executed here, the upload of the firmware in the 143862306a36Sopenharmony_ci * probe function caused by the reloading of the driver will fail. 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_ci usb_reset_device(interface_to_usbdev(intf)); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci zd_mac_clear(mac); 144362306a36Sopenharmony_ci ieee80211_free_hw(hw); 144462306a36Sopenharmony_ci dev_dbg(&intf->dev, "disconnected\n"); 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_cistatic void zd_usb_resume(struct zd_usb *usb) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci struct zd_mac *mac = zd_usb_to_mac(usb); 145062306a36Sopenharmony_ci int r; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci r = zd_op_start(zd_usb_to_hw(usb)); 145562306a36Sopenharmony_ci if (r < 0) { 145662306a36Sopenharmony_ci dev_warn(zd_usb_dev(usb), "Device resume failed " 145762306a36Sopenharmony_ci "with error code %d. Retrying...\n", r); 145862306a36Sopenharmony_ci if (usb->was_running) 145962306a36Sopenharmony_ci set_bit(ZD_DEVICE_RUNNING, &mac->flags); 146062306a36Sopenharmony_ci usb_queue_reset_device(usb->intf); 146162306a36Sopenharmony_ci return; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci if (mac->type != NL80211_IFTYPE_UNSPECIFIED) { 146562306a36Sopenharmony_ci r = zd_restore_settings(mac); 146662306a36Sopenharmony_ci if (r < 0) { 146762306a36Sopenharmony_ci dev_dbg(zd_usb_dev(usb), 146862306a36Sopenharmony_ci "failed to restore settings, %d\n", r); 146962306a36Sopenharmony_ci return; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_cistatic void zd_usb_stop(struct zd_usb *usb) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "\n"); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci zd_op_stop(zd_usb_to_hw(usb)); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci zd_usb_disable_tx(usb); 148162306a36Sopenharmony_ci zd_usb_disable_rx(usb); 148262306a36Sopenharmony_ci zd_usb_disable_int(usb); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci usb->initialized = 0; 148562306a36Sopenharmony_ci} 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_cistatic int pre_reset(struct usb_interface *intf) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(intf); 149062306a36Sopenharmony_ci struct zd_mac *mac; 149162306a36Sopenharmony_ci struct zd_usb *usb; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (!hw || intf->condition != USB_INTERFACE_BOUND) 149462306a36Sopenharmony_ci return 0; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci mac = zd_hw_mac(hw); 149762306a36Sopenharmony_ci usb = &mac->chip.usb; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci usb->was_running = test_bit(ZD_DEVICE_RUNNING, &mac->flags); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci zd_usb_stop(usb); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci mutex_lock(&mac->chip.mutex); 150462306a36Sopenharmony_ci return 0; 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_cistatic int post_reset(struct usb_interface *intf) 150862306a36Sopenharmony_ci{ 150962306a36Sopenharmony_ci struct ieee80211_hw *hw = usb_get_intfdata(intf); 151062306a36Sopenharmony_ci struct zd_mac *mac; 151162306a36Sopenharmony_ci struct zd_usb *usb; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (!hw || intf->condition != USB_INTERFACE_BOUND) 151462306a36Sopenharmony_ci return 0; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci mac = zd_hw_mac(hw); 151762306a36Sopenharmony_ci usb = &mac->chip.usb; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci mutex_unlock(&mac->chip.mutex); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (usb->was_running) 152262306a36Sopenharmony_ci zd_usb_resume(usb); 152362306a36Sopenharmony_ci return 0; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic struct usb_driver driver = { 152762306a36Sopenharmony_ci .name = KBUILD_MODNAME, 152862306a36Sopenharmony_ci .id_table = usb_ids, 152962306a36Sopenharmony_ci .probe = probe, 153062306a36Sopenharmony_ci .disconnect = disconnect, 153162306a36Sopenharmony_ci .pre_reset = pre_reset, 153262306a36Sopenharmony_ci .post_reset = post_reset, 153362306a36Sopenharmony_ci .disable_hub_initiated_lpm = 1, 153462306a36Sopenharmony_ci}; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistruct workqueue_struct *zd_workqueue; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_cistatic int __init usb_init(void) 153962306a36Sopenharmony_ci{ 154062306a36Sopenharmony_ci int r; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci pr_debug("%s usb_init()\n", driver.name); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci zd_workqueue = create_singlethread_workqueue(driver.name); 154562306a36Sopenharmony_ci if (zd_workqueue == NULL) { 154662306a36Sopenharmony_ci pr_err("%s couldn't create workqueue\n", driver.name); 154762306a36Sopenharmony_ci return -ENOMEM; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci r = usb_register(&driver); 155162306a36Sopenharmony_ci if (r) { 155262306a36Sopenharmony_ci destroy_workqueue(zd_workqueue); 155362306a36Sopenharmony_ci pr_err("%s usb_register() failed. Error number %d\n", 155462306a36Sopenharmony_ci driver.name, r); 155562306a36Sopenharmony_ci return r; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci pr_debug("%s initialized\n", driver.name); 155962306a36Sopenharmony_ci return 0; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic void __exit usb_exit(void) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci pr_debug("%s usb_exit()\n", driver.name); 156562306a36Sopenharmony_ci usb_deregister(&driver); 156662306a36Sopenharmony_ci destroy_workqueue(zd_workqueue); 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cimodule_init(usb_init); 157062306a36Sopenharmony_cimodule_exit(usb_exit); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len, 157362306a36Sopenharmony_ci int *actual_length, int timeout) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci /* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in 157662306a36Sopenharmony_ci * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint 157762306a36Sopenharmony_ci * descriptor. 157862306a36Sopenharmony_ci */ 157962306a36Sopenharmony_ci struct usb_host_endpoint *ep; 158062306a36Sopenharmony_ci unsigned int pipe; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci pipe = usb_sndintpipe(udev, EP_REGS_OUT); 158362306a36Sopenharmony_ci ep = usb_pipe_endpoint(udev, pipe); 158462306a36Sopenharmony_ci if (!ep) 158562306a36Sopenharmony_ci return -EINVAL; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci if (usb_endpoint_xfer_int(&ep->desc)) { 158862306a36Sopenharmony_ci return usb_interrupt_msg(udev, pipe, data, len, 158962306a36Sopenharmony_ci actual_length, timeout); 159062306a36Sopenharmony_ci } else { 159162306a36Sopenharmony_ci pipe = usb_sndbulkpipe(udev, EP_REGS_OUT); 159262306a36Sopenharmony_ci return usb_bulk_msg(udev, pipe, data, len, actual_length, 159362306a36Sopenharmony_ci timeout); 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci} 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_cistatic void prepare_read_regs_int(struct zd_usb *usb, 159862306a36Sopenharmony_ci struct usb_req_read_regs *req, 159962306a36Sopenharmony_ci unsigned int count) 160062306a36Sopenharmony_ci{ 160162306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci spin_lock_irq(&intr->lock); 160462306a36Sopenharmony_ci atomic_set(&intr->read_regs_enabled, 1); 160562306a36Sopenharmony_ci intr->read_regs.req = req; 160662306a36Sopenharmony_ci intr->read_regs.req_count = count; 160762306a36Sopenharmony_ci reinit_completion(&intr->read_regs.completion); 160862306a36Sopenharmony_ci spin_unlock_irq(&intr->lock); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic void disable_read_regs_int(struct zd_usb *usb) 161262306a36Sopenharmony_ci{ 161362306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci spin_lock_irq(&intr->lock); 161662306a36Sopenharmony_ci atomic_set(&intr->read_regs_enabled, 0); 161762306a36Sopenharmony_ci spin_unlock_irq(&intr->lock); 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req, 162162306a36Sopenharmony_ci unsigned int count) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci int i; 162462306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 162562306a36Sopenharmony_ci struct read_regs_int *rr = &intr->read_regs; 162662306a36Sopenharmony_ci struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci /* The created block size seems to be larger than expected. 162962306a36Sopenharmony_ci * However results appear to be correct. 163062306a36Sopenharmony_ci */ 163162306a36Sopenharmony_ci if (rr->length < struct_size(regs, regs, count)) { 163262306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 163362306a36Sopenharmony_ci "error: actual length %d less than expected %zu\n", 163462306a36Sopenharmony_ci rr->length, struct_size(regs, regs, count)); 163562306a36Sopenharmony_ci return false; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (rr->length > sizeof(rr->buffer)) { 163962306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 164062306a36Sopenharmony_ci "error: actual length %d exceeds buffer size %zu\n", 164162306a36Sopenharmony_ci rr->length, sizeof(rr->buffer)); 164262306a36Sopenharmony_ci return false; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci for (i = 0; i < count; i++) { 164662306a36Sopenharmony_ci struct reg_data *rd = ®s->regs[i]; 164762306a36Sopenharmony_ci if (rd->addr != req->addr[i]) { 164862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 164962306a36Sopenharmony_ci "rd[%d] addr %#06hx expected %#06hx\n", i, 165062306a36Sopenharmony_ci le16_to_cpu(rd->addr), 165162306a36Sopenharmony_ci le16_to_cpu(req->addr[i])); 165262306a36Sopenharmony_ci return false; 165362306a36Sopenharmony_ci } 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci return true; 165762306a36Sopenharmony_ci} 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cistatic int get_results(struct zd_usb *usb, u16 *values, 166062306a36Sopenharmony_ci struct usb_req_read_regs *req, unsigned int count, 166162306a36Sopenharmony_ci bool *retry) 166262306a36Sopenharmony_ci{ 166362306a36Sopenharmony_ci int r; 166462306a36Sopenharmony_ci int i; 166562306a36Sopenharmony_ci struct zd_usb_interrupt *intr = &usb->intr; 166662306a36Sopenharmony_ci struct read_regs_int *rr = &intr->read_regs; 166762306a36Sopenharmony_ci struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci spin_lock_irq(&intr->lock); 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci r = -EIO; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* Read failed because firmware bug? */ 167462306a36Sopenharmony_ci *retry = !!intr->read_regs_int_overridden; 167562306a36Sopenharmony_ci if (*retry) 167662306a36Sopenharmony_ci goto error_unlock; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (!check_read_regs(usb, req, count)) { 167962306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "error: invalid read regs\n"); 168062306a36Sopenharmony_ci goto error_unlock; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 168462306a36Sopenharmony_ci struct reg_data *rd = ®s->regs[i]; 168562306a36Sopenharmony_ci values[i] = le16_to_cpu(rd->value); 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci r = 0; 168962306a36Sopenharmony_cierror_unlock: 169062306a36Sopenharmony_ci spin_unlock_irq(&intr->lock); 169162306a36Sopenharmony_ci return r; 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ciint zd_usb_ioread16v(struct zd_usb *usb, u16 *values, 169562306a36Sopenharmony_ci const zd_addr_t *addresses, unsigned int count) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci int r, i, req_len, actual_req_len, try_count = 0; 169862306a36Sopenharmony_ci struct usb_device *udev; 169962306a36Sopenharmony_ci struct usb_req_read_regs *req = NULL; 170062306a36Sopenharmony_ci unsigned long timeout; 170162306a36Sopenharmony_ci bool retry = false; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci if (count < 1) { 170462306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n"); 170562306a36Sopenharmony_ci return -EINVAL; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci if (count > USB_MAX_IOREAD16_COUNT) { 170862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 170962306a36Sopenharmony_ci "error: count %u exceeds possible max %u\n", 171062306a36Sopenharmony_ci count, USB_MAX_IOREAD16_COUNT); 171162306a36Sopenharmony_ci return -EINVAL; 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci if (!usb_int_enabled(usb)) { 171462306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 171562306a36Sopenharmony_ci "error: usb interrupt not enabled\n"); 171662306a36Sopenharmony_ci return -EWOULDBLOCK; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); 172062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct usb_req_read_regs) + USB_MAX_IOREAD16_COUNT * 172162306a36Sopenharmony_ci sizeof(__le16) > sizeof(usb->req_buf)); 172262306a36Sopenharmony_ci BUG_ON(sizeof(struct usb_req_read_regs) + count * sizeof(__le16) > 172362306a36Sopenharmony_ci sizeof(usb->req_buf)); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); 172662306a36Sopenharmony_ci req = (void *)usb->req_buf; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci req->id = cpu_to_le16(USB_REQ_READ_REGS); 172962306a36Sopenharmony_ci for (i = 0; i < count; i++) 173062306a36Sopenharmony_ci req->addr[i] = cpu_to_le16((u16)addresses[i]); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ciretry_read: 173362306a36Sopenharmony_ci try_count++; 173462306a36Sopenharmony_ci udev = zd_usb_to_usbdev(usb); 173562306a36Sopenharmony_ci prepare_read_regs_int(usb, req, count); 173662306a36Sopenharmony_ci r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); 173762306a36Sopenharmony_ci if (r) { 173862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 173962306a36Sopenharmony_ci "error in zd_ep_regs_out_msg(). Error number %d\n", r); 174062306a36Sopenharmony_ci goto error; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci if (req_len != actual_req_len) { 174362306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n" 174462306a36Sopenharmony_ci " req_len %d != actual_req_len %d\n", 174562306a36Sopenharmony_ci req_len, actual_req_len); 174662306a36Sopenharmony_ci r = -EIO; 174762306a36Sopenharmony_ci goto error; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion, 175162306a36Sopenharmony_ci msecs_to_jiffies(50)); 175262306a36Sopenharmony_ci if (!timeout) { 175362306a36Sopenharmony_ci disable_read_regs_int(usb); 175462306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "read timed out\n"); 175562306a36Sopenharmony_ci r = -ETIMEDOUT; 175662306a36Sopenharmony_ci goto error; 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci r = get_results(usb, values, req, count, &retry); 176062306a36Sopenharmony_ci if (retry && try_count < 20) { 176162306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "read retry, tries so far: %d\n", 176262306a36Sopenharmony_ci try_count); 176362306a36Sopenharmony_ci goto retry_read; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_cierror: 176662306a36Sopenharmony_ci return r; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_cistatic void iowrite16v_urb_complete(struct urb *urb) 177062306a36Sopenharmony_ci{ 177162306a36Sopenharmony_ci struct zd_usb *usb = urb->context; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (urb->status && !usb->cmd_error) 177462306a36Sopenharmony_ci usb->cmd_error = urb->status; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (!usb->cmd_error && 177762306a36Sopenharmony_ci urb->actual_length != urb->transfer_buffer_length) 177862306a36Sopenharmony_ci usb->cmd_error = -EIO; 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic int zd_submit_waiting_urb(struct zd_usb *usb, bool last) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci int r = 0; 178462306a36Sopenharmony_ci struct urb *urb = usb->urb_async_waiting; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci if (!urb) 178762306a36Sopenharmony_ci return 0; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci usb->urb_async_waiting = NULL; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (!last) 179262306a36Sopenharmony_ci urb->transfer_flags |= URB_NO_INTERRUPT; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci usb_anchor_urb(urb, &usb->submitted_cmds); 179562306a36Sopenharmony_ci r = usb_submit_urb(urb, GFP_KERNEL); 179662306a36Sopenharmony_ci if (r) { 179762306a36Sopenharmony_ci usb_unanchor_urb(urb); 179862306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 179962306a36Sopenharmony_ci "error in usb_submit_urb(). Error number %d\n", r); 180062306a36Sopenharmony_ci goto error; 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci /* fall-through with r == 0 */ 180462306a36Sopenharmony_cierror: 180562306a36Sopenharmony_ci usb_free_urb(urb); 180662306a36Sopenharmony_ci return r; 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_civoid zd_usb_iowrite16v_async_start(struct zd_usb *usb) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci ZD_ASSERT(usb_anchor_empty(&usb->submitted_cmds)); 181262306a36Sopenharmony_ci ZD_ASSERT(usb->urb_async_waiting == NULL); 181362306a36Sopenharmony_ci ZD_ASSERT(!usb->in_async); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci usb->in_async = 1; 181862306a36Sopenharmony_ci usb->cmd_error = 0; 181962306a36Sopenharmony_ci usb->urb_async_waiting = NULL; 182062306a36Sopenharmony_ci} 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ciint zd_usb_iowrite16v_async_end(struct zd_usb *usb, unsigned int timeout) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci int r; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); 182762306a36Sopenharmony_ci ZD_ASSERT(usb->in_async); 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci /* Submit last iowrite16v URB */ 183062306a36Sopenharmony_ci r = zd_submit_waiting_urb(usb, true); 183162306a36Sopenharmony_ci if (r) { 183262306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 183362306a36Sopenharmony_ci "error in zd_submit_waiting_usb(). " 183462306a36Sopenharmony_ci "Error number %d\n", r); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci usb_kill_anchored_urbs(&usb->submitted_cmds); 183762306a36Sopenharmony_ci goto error; 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (timeout) 184162306a36Sopenharmony_ci timeout = usb_wait_anchor_empty_timeout(&usb->submitted_cmds, 184262306a36Sopenharmony_ci timeout); 184362306a36Sopenharmony_ci if (!timeout) { 184462306a36Sopenharmony_ci usb_kill_anchored_urbs(&usb->submitted_cmds); 184562306a36Sopenharmony_ci if (usb->cmd_error == -ENOENT) { 184662306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "timed out"); 184762306a36Sopenharmony_ci r = -ETIMEDOUT; 184862306a36Sopenharmony_ci goto error; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci r = usb->cmd_error; 185362306a36Sopenharmony_cierror: 185462306a36Sopenharmony_ci usb->in_async = 0; 185562306a36Sopenharmony_ci return r; 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ciint zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, 185962306a36Sopenharmony_ci unsigned int count) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci int r; 186262306a36Sopenharmony_ci struct usb_device *udev; 186362306a36Sopenharmony_ci struct usb_req_write_regs *req = NULL; 186462306a36Sopenharmony_ci int i, req_len; 186562306a36Sopenharmony_ci struct urb *urb; 186662306a36Sopenharmony_ci struct usb_host_endpoint *ep; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); 186962306a36Sopenharmony_ci ZD_ASSERT(usb->in_async); 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci if (count == 0) 187262306a36Sopenharmony_ci return 0; 187362306a36Sopenharmony_ci if (count > USB_MAX_IOWRITE16_COUNT) { 187462306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 187562306a36Sopenharmony_ci "error: count %u exceeds possible max %u\n", 187662306a36Sopenharmony_ci count, USB_MAX_IOWRITE16_COUNT); 187762306a36Sopenharmony_ci return -EINVAL; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci udev = zd_usb_to_usbdev(usb); 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci ep = usb_pipe_endpoint(udev, usb_sndintpipe(udev, EP_REGS_OUT)); 188362306a36Sopenharmony_ci if (!ep) 188462306a36Sopenharmony_ci return -ENOENT; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 188762306a36Sopenharmony_ci if (!urb) 188862306a36Sopenharmony_ci return -ENOMEM; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci req_len = struct_size(req, reg_writes, count); 189162306a36Sopenharmony_ci req = kmalloc(req_len, GFP_KERNEL); 189262306a36Sopenharmony_ci if (!req) { 189362306a36Sopenharmony_ci r = -ENOMEM; 189462306a36Sopenharmony_ci goto error; 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci req->id = cpu_to_le16(USB_REQ_WRITE_REGS); 189862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 189962306a36Sopenharmony_ci struct reg_data *rw = &req->reg_writes[i]; 190062306a36Sopenharmony_ci rw->addr = cpu_to_le16((u16)ioreqs[i].addr); 190162306a36Sopenharmony_ci rw->value = cpu_to_le16(ioreqs[i].value); 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci /* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode 190562306a36Sopenharmony_ci * endpoint is bulk. Select correct type URB by endpoint descriptor. 190662306a36Sopenharmony_ci */ 190762306a36Sopenharmony_ci if (usb_endpoint_xfer_int(&ep->desc)) 190862306a36Sopenharmony_ci usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), 190962306a36Sopenharmony_ci req, req_len, iowrite16v_urb_complete, usb, 191062306a36Sopenharmony_ci ep->desc.bInterval); 191162306a36Sopenharmony_ci else 191262306a36Sopenharmony_ci usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT), 191362306a36Sopenharmony_ci req, req_len, iowrite16v_urb_complete, usb); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci urb->transfer_flags |= URB_FREE_BUFFER; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci /* Submit previous URB */ 191862306a36Sopenharmony_ci r = zd_submit_waiting_urb(usb, false); 191962306a36Sopenharmony_ci if (r) { 192062306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 192162306a36Sopenharmony_ci "error in zd_submit_waiting_usb(). " 192262306a36Sopenharmony_ci "Error number %d\n", r); 192362306a36Sopenharmony_ci goto error; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci /* Delay submit so that URB_NO_INTERRUPT flag can be set for all URBs 192762306a36Sopenharmony_ci * of currect batch except for very last. 192862306a36Sopenharmony_ci */ 192962306a36Sopenharmony_ci usb->urb_async_waiting = urb; 193062306a36Sopenharmony_ci return 0; 193162306a36Sopenharmony_cierror: 193262306a36Sopenharmony_ci usb_free_urb(urb); 193362306a36Sopenharmony_ci return r; 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ciint zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, 193762306a36Sopenharmony_ci unsigned int count) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci int r; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci zd_usb_iowrite16v_async_start(usb); 194262306a36Sopenharmony_ci r = zd_usb_iowrite16v_async(usb, ioreqs, count); 194362306a36Sopenharmony_ci if (r) { 194462306a36Sopenharmony_ci zd_usb_iowrite16v_async_end(usb, 0); 194562306a36Sopenharmony_ci return r; 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci return zd_usb_iowrite16v_async_end(usb, 50 /* ms */); 194862306a36Sopenharmony_ci} 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ciint zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) 195162306a36Sopenharmony_ci{ 195262306a36Sopenharmony_ci int r; 195362306a36Sopenharmony_ci struct usb_device *udev; 195462306a36Sopenharmony_ci struct usb_req_rfwrite *req = NULL; 195562306a36Sopenharmony_ci int i, req_len, actual_req_len; 195662306a36Sopenharmony_ci u16 bit_value_template; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (bits < USB_MIN_RFWRITE_BIT_COUNT) { 195962306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 196062306a36Sopenharmony_ci "error: bits %d are smaller than" 196162306a36Sopenharmony_ci " USB_MIN_RFWRITE_BIT_COUNT %d\n", 196262306a36Sopenharmony_ci bits, USB_MIN_RFWRITE_BIT_COUNT); 196362306a36Sopenharmony_ci return -EINVAL; 196462306a36Sopenharmony_ci } 196562306a36Sopenharmony_ci if (bits > USB_MAX_RFWRITE_BIT_COUNT) { 196662306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 196762306a36Sopenharmony_ci "error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n", 196862306a36Sopenharmony_ci bits, USB_MAX_RFWRITE_BIT_COUNT); 196962306a36Sopenharmony_ci return -EINVAL; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci#ifdef DEBUG 197262306a36Sopenharmony_ci if (value & (~0UL << bits)) { 197362306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 197462306a36Sopenharmony_ci "error: value %#09x has bits >= %d set\n", 197562306a36Sopenharmony_ci value, bits); 197662306a36Sopenharmony_ci return -EINVAL; 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci#endif /* DEBUG */ 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits); 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203); 198362306a36Sopenharmony_ci if (r) { 198462306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 198562306a36Sopenharmony_ci "error %d: Couldn't read ZD_CR203\n", r); 198662306a36Sopenharmony_ci return r; 198762306a36Sopenharmony_ci } 198862306a36Sopenharmony_ci bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&zd_usb_to_chip(usb)->mutex)); 199162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct usb_req_rfwrite) + 199262306a36Sopenharmony_ci USB_MAX_RFWRITE_BIT_COUNT * sizeof(__le16) > 199362306a36Sopenharmony_ci sizeof(usb->req_buf)); 199462306a36Sopenharmony_ci BUG_ON(sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16) > 199562306a36Sopenharmony_ci sizeof(usb->req_buf)); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); 199862306a36Sopenharmony_ci req = (void *)usb->req_buf; 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci req->id = cpu_to_le16(USB_REQ_WRITE_RF); 200162306a36Sopenharmony_ci /* 1: 3683a, but not used in ZYDAS driver */ 200262306a36Sopenharmony_ci req->value = cpu_to_le16(2); 200362306a36Sopenharmony_ci req->bits = cpu_to_le16(bits); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci for (i = 0; i < bits; i++) { 200662306a36Sopenharmony_ci u16 bv = bit_value_template; 200762306a36Sopenharmony_ci if (value & (1 << (bits-1-i))) 200862306a36Sopenharmony_ci bv |= RF_DATA; 200962306a36Sopenharmony_ci req->bit_values[i] = cpu_to_le16(bv); 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci udev = zd_usb_to_usbdev(usb); 201362306a36Sopenharmony_ci r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); 201462306a36Sopenharmony_ci if (r) { 201562306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), 201662306a36Sopenharmony_ci "error in zd_ep_regs_out_msg(). Error number %d\n", r); 201762306a36Sopenharmony_ci goto out; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci if (req_len != actual_req_len) { 202062306a36Sopenharmony_ci dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()" 202162306a36Sopenharmony_ci " req_len %d != actual_req_len %d\n", 202262306a36Sopenharmony_ci req_len, actual_req_len); 202362306a36Sopenharmony_ci r = -EIO; 202462306a36Sopenharmony_ci goto out; 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci /* FALL-THROUGH with r == 0 */ 202862306a36Sopenharmony_ciout: 202962306a36Sopenharmony_ci return r; 203062306a36Sopenharmony_ci} 2031