11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for ZyDAS zd1201 based wireless USB devices. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * version 2 as published by the Free Software Foundation. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Parts of this driver have been derived from a wlan-ng version 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modified by ZyDAS. They also made documentation available, thanks! 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wireless.h> 212c706002fc147decdba2658ea48e4436faca3af2Johannes Berg#include <linux/ieee80211.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/iw_handler.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/firmware.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "zd1201.h" 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_id zd1201_table[] = { 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ 33d94519c1b0de827d5d142b9333b7f114c0b3a021maximilian attems {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ 34f29080976d109b6c08e42be8a1888f338785c502Mathieu {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {} 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 382a8063403112030f1748e207d97d4f8654754dffPavel Machekstatic int ap; /* Are we an AP or a normal station? */ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZD1201_VERSION "0.15" 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>"); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters"); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(ZD1201_VERSION); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ap, int, 0); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(usb, zd1201_table); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 512e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunkstatic int zd1201_fw_upload(struct usb_device *dev, int apfw) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct firmware *fw_entry; 5445ef0bdb18a37bcf102e2a18c757227f8b192a36David Woodhouse const char *data; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long len; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ret; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *fwfile; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (apfw) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fwfile = "zd1201-ap.fw"; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fwfile = "zd1201.fw"; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = request_firmware(&fw_entry, fwfile, &dev->dev); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n"); 702a8063403112030f1748e207d97d4f8654754dffPavel Machek dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n"); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = fw_entry->data; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = fw_entry->size; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = kmalloc(1024, GFP_ATOMIC); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buf) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (len > 0) { 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int translen = (len > 1024) ? 1024 : len; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(buf, data, translen); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DIR_OUT | 0x40, 0, 0, buf, translen, 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ZD1201_FW_TIMEOUT); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= translen; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data += translen; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2, 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 992a8063403112030f1748e207d97d4f8654754dffPavel Machek 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err < 0) 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1042a8063403112030f1748e207d97d4f8654754dffPavel Machek 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret & 0x80) { 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EIO; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = 0; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 1121bc3c9e1e44c2059fe2ffa6ff70ad0a925d7b05fJesper Juhl kfree(buf); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_firmware(fw_entry); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 117e01b0e0f90681072d29fe1ba6a29298683f42c15Ben HutchingsMODULE_FIRMWARE("zd1201-ap.fw"); 118e01b0e0f90681072d29fe1ba6a29298683f42c15Ben HutchingsMODULE_FIRMWARE("zd1201.fw"); 119e01b0e0f90681072d29fe1ba6a29298683f42c15Ben Hutchings 1207d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void zd1201_usbfree(struct urb *urb) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct zd1201 *zd = urb->context; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(urb->status) { 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EILSEQ: 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENODEV: 12738e2bfc94e95dd6005fdaf40dfec0157396741daPete Zaitcev case -ETIME: 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EPIPE: 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EOVERFLOW: 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->dev->name, urb->status); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(urb->transfer_buffer); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_free_urb(urb); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* cmdreq message: 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 type 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 cmd 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 parm0 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 parm1 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 parm2 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 pad[4] 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds total: 4 + 2 + 2 + 2 + 2 + 4 = 16 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 1502e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunkstatic int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, 1512e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunk int parm1, int parm2) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *command; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds command = kmalloc(16, GFP_ATOMIC); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!command) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&command[4]) = cpu_to_le16(cmd); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&command[6]) = cpu_to_le16(parm0); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&command[8]) = cpu_to_le16(parm1); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&command[10])= cpu_to_le16(parm2); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = usb_alloc_urb(0, GFP_ATOMIC); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb) { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(command); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), 1732a8063403112030f1748e207d97d4f8654754dffPavel Machek command, 16, zd1201_usbfree, zd); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = usb_submit_urb(urb, GFP_ATOMIC); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(command); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_free_urb(urb); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1792a8063403112030f1748e207d97d4f8654754dffPavel Machek 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Callback after sending out a packet */ 1847d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void zd1201_usbtx(struct urb *urb) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct zd1201 *zd = urb->context; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(zd->dev); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 190093cf723b2b06d774929ea07982f6a466ff22314Steven Cole/* Incoming data */ 1917d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void zd1201_usbrx(struct urb *urb) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct zd1201 *zd = urb->context; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int free = 0; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char type; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 199683f8c9e00d2aa911382186ca891bd221efaea74Eric Sesterhenn if (!zd) 200683f8c9e00d2aa911382186ca891bd221efaea74Eric Sesterhenn return; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(urb->status) { 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EILSEQ: 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENODEV: 20538e2bfc94e95dd6005fdaf40dfec0157396741daPete Zaitcev case -ETIME: 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EPIPE: 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -EOVERFLOW: 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n", 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->dev->name, urb->status); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free = 1; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (urb->status != 0 || urb->actual_length == 0) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = data[0]; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) { 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(zd->rxdata, data, urb->actual_length); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxlen = urb->actual_length; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 1; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&zd->rxdataq); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Info frame */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == ZD1201_PACKET_INQUIRE) { 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short infotype, framelen, copylen; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds framelen = le16_to_cpu(*(__le16*)&data[4]); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds infotype = le16_to_cpu(*(__le16*)&data[6]); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (infotype == ZD1201_INF_LINKSTATUS) { 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short linkstatus; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds linkstatus = le16_to_cpu(*(__le16*)&data[8]); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(linkstatus) { 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_on(zd->dev); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(zd->dev); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(zd->dev); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 4: 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_on(zd->dev); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(zd->dev); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (infotype == ZD1201_INF_ASSOCSTATUS) { 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short status = le16_to_cpu(*(__le16*)(data+8)); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int event; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union iwreq_data wrqu; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (status) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_ASSOCSTATUS_STAASSOC: 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_ASSOCSTATUS_REASSOC: 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event = IWEVREGISTERED; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_ASSOCSTATUS_DISASSOC: 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_ASSOCSTATUS_ASSOCFAIL: 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_ASSOCSTATUS_AUTHFAIL: 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event = IWEVEXPIRED; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrqu.addr.sa_family = ARPHRD_ETHER; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Send event to user space */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wireless_send_event(zd->dev, event, &wrqu, NULL); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (infotype == ZD1201_INF_AUTHREQ) { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union iwreq_data wrqu; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN); 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrqu.addr.sa_family = ARPHRD_ETHER; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There isn't a event that trully fits this request. 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds We assume that userspace will be smart enough to 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds see a new station being expired and sends back a 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds authstation ioctl to authorize it. */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Other infotypes are handled outside this handler */ 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxlen = 0; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i < urb->actual_length) { 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copylen = le16_to_cpu(*(__le16*)&data[i+2]); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Sanity check, sometimes we get junk */ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copylen+zd->rxlen > sizeof(zd->rxdata)) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxlen += copylen; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i += 64; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i >= urb->actual_length) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 1; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&zd->rxdataq); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Actual data */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) { 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int datalen = urb->actual_length-1; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short len, fc, seq; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hlist_node *node; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = ntohs(*(__be16 *)&data[datalen-2]); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len>datalen) 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len=datalen; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fc = le16_to_cpu(*(__le16 *)&data[datalen-16]); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds seq = le16_to_cpu(*(__le16 *)&data[datalen-24]); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3202a8063403112030f1748e207d97d4f8654754dffPavel Machek if (zd->monitor) { 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (datalen < 24) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(skb = dev_alloc_skb(datalen+24))) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 2), &data[datalen-16], 2); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 2), &data[datalen-2], 2); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 6), &data[datalen-14], 6); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 6), &data[datalen-22], 6); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 6), &data[datalen-8], 6); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 2), &data[datalen-24], 2); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, len), data, len); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, zd->dev); 33422bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger zd->dev->stats.rx_packets++; 33522bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger zd->dev->stats.rx_bytes += skb->len; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3403dcefbc9d6bd8b5ff0fc4bdbe3df938be5460f79Al Viro if ((seq & IEEE80211_SCTL_FRAG) || 3413dcefbc9d6bd8b5ff0fc4bdbe3df938be5460f79Al Viro (fc & IEEE80211_FCTL_MOREFRAGS)) { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct zd1201_frag *frag = NULL; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *ptr; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (datalen<14) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3473dcefbc9d6bd8b5ff0fc4bdbe3df938be5460f79Al Viro if ((seq & IEEE80211_SCTL_FRAG) == 0) { 34881065e2f415af6c028eac13f481fb9e60a0b487bAlexey Dobriyan frag = kmalloc(sizeof(*frag), GFP_ATOMIC); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!frag) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3512c706002fc147decdba2658ea48e4436faca3af2Johannes Berg skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) { 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(frag); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frag->skb = skb; 3573dcefbc9d6bd8b5ff0fc4bdbe3df938be5460f79Al Viro frag->seq = seq & IEEE80211_SCTL_SEQ; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 12), &data[datalen-14], 12); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 2), &data[6], 2); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, len), data+8, len); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hlist_add_head(&frag->fnode, &zd->fraglist); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hlist_for_each_entry(frag, node, &zd->fraglist, fnode) 3662a8063403112030f1748e207d97d4f8654754dffPavel Machek if (frag->seq == (seq&IEEE80211_SCTL_SEQ)) 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!frag) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = frag->skb; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr = skb_put(skb, len); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ptr) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(ptr, data+8, len); 3743dcefbc9d6bd8b5ff0fc4bdbe3df938be5460f79Al Viro if (fc & IEEE80211_FCTL_MOREFRAGS) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hlist_del_init(&frag->fnode); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(frag); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (datalen<14) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = dev_alloc_skb(len + 14 + 2); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto resubmit; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 12), &data[datalen-14], 12); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, 2), &data[6], 2); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb, len), data+8, len); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, zd->dev); 39022bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger zd->dev->stats.rx_packets++; 39122bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger zd->dev->stats.rx_bytes += skb->len; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsresubmit: 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(data, 0, ZD1201_RXSIZE); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->status = 0; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb->dev = zd->usb; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(usb_submit_urb(urb, GFP_ATOMIC)) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free = 1; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (free) { 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxlen = 0; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 1; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up(&zd->rxdataq); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(urb->transfer_buffer); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata, 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int riddatalen) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int code; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rid_fid; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int length; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *pdata; 4202a8063403112030f1748e207d97d4f8654754dffPavel Machek 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 0; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_event_interruptible(zd->rxdataq, zd->rxdatas); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->rxlen) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds code = le16_to_cpu(*(__le16*)(&zd->rxdata[4])); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6])); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length = le16_to_cpu(*(__le16*)(&zd->rxdata[8])); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (length > zd->rxlen) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length = zd->rxlen-6; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If access bit is not on, then error */ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid ) 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not enough buffer for allocating data */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (riddatalen != (length - 4)) { 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n", 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds riddatalen, zd->rxlen, length, rid, rid_fid); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODATA; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 0; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Issue SetRxRid commnd */ 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Receive RID record from resource packets */ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_event_interruptible(zd->rxdataq, zd->rxdatas); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->rxlen) 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) { 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n", 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdata[zd->rxlen-1]); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the data pointer and received data length */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdata = zd->rxdata; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length = zd->rxlen; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4692a8063403112030f1748e207d97d4f8654754dffPavel Machek int actual_length; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual_length = (length > 64) ? 64 : length; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4732a8063403112030f1748e207d97d4f8654754dffPavel Machek if (pdata[0] != 0x3) { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n", 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdata[0]); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (actual_length != 64) { 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Trim the last packet type byte */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual_length--; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip the 4 bytes header (RID length and RID) */ 4852a8063403112030f1748e207d97d4f8654754dffPavel Machek if (i == 0) { 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdata += 8; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual_length -= 8; 4882a8063403112030f1748e207d97d4f8654754dffPavel Machek } else { 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdata += 4; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual_length -= 4; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(riddata, pdata, actual_length); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds riddata += actual_length; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdata += actual_length; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length -= 64; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (length > 0); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * resreq: 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte type 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte sequence 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * u16 reserved 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte data[12] 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * total: 16 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int wait) 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *request; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reqlen; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char seq=0; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb; 51855016f10e31bb15b85d8c500f979dfdceb37d548Al Viro gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len += 4; /* first 4 are for header */ 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 0; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxlen = 0; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (seq=0; len > 0; seq++) { 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request = kmalloc(16, gfp_mask); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request) 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = usb_alloc_urb(0, gfp_mask); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb) { 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(request); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(request, 0, 16); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reqlen = len>12 ? 12 : len; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request[0] = ZD1201_USB_RESREQ; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request[1] = seq; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request[2] = 0; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request[3] = 0; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request[1] == 0) { 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* add header */ 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(__le16*)&request[6] = cpu_to_le16(rid); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(request+8, buf, reqlen-4); 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += reqlen-4; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(request+4, buf, reqlen); 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += reqlen; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= reqlen; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->endp_out2), request, 16, zd1201_usbfree, zd); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_submit_urb(urb, gfp_mask); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request = kmalloc(16, gfp_mask); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds urb = usb_alloc_urb(0, gfp_mask); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!urb) { 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(request); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&request[4]) = 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&request[6]) = cpu_to_le16(rid); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&request[8]) = cpu_to_le16(0); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *((__le16*)&request[10]) = cpu_to_le16(0); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request, 16, zd1201_usbfree, zd); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_submit_urb(urb, gfp_mask); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wait) { 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_event_interruptible(zd->rxdataq, zd->rxdatas); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) { 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&zd->usb->dev, "wrong or no RID received\n"); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr: 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(request); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_free_urb(urb); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le16 zdval; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16)); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *val = le16_to_cpu(zdval); 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le16 zdval = cpu_to_le16(val); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6112e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunkstatic int zd1201_drvr_start(struct zd1201 *zd) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err, i; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short max; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le16 zdmax; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buffer; 6172a8063403112030f1748e207d97d4f8654754dffPavel Machek 61880b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!buffer) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(zd->rx_urb, zd->usb, 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_usbrx, zd); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_submit_urb(zd->rx_urb, GFP_KERNEL); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_buffer; 6292a8063403112030f1748e207d97d4f8654754dffPavel Machek 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_urb; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax, 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(__le16)); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_urb; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max = le16_to_cpu(zdmax); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<max; i++) { 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_urb; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_urb: 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(zd->rx_urb); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_buffer: 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buffer); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Magic alert: The firmware doesn't seem to like the MAC state being 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * toggled in promisc (aka monitor) mode. 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (It works a number of times, but will halt eventually) 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So we turn it of before disabling and on after enabling if needed. 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_enable(struct zd1201 *zd) 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->mac_enabled) 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->mac_enabled = 1; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->monitor) 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_disable(struct zd1201 *zd) 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6812a8063403112030f1748e207d97d4f8654754dffPavel Machek 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->mac_enabled) 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->monitor) { 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!err) 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->mac_enabled = 0; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_mac_reset(struct zd1201 *zd) 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->mac_enabled) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_disable(zd); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_enable(zd); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err, val; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[IW_ESSID_MAX_SIZE+2]; 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_disable(zd); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(__le16 *)buf = cpu_to_le16(essidlen); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(buf+2, essid, essidlen); 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->ap) { /* Normal station */ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_ESSID_MAX_SIZE+2, 1); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* AP */ 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf, 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_ESSID_MAX_SIZE+2, 1); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->dev->dev_addr, zd->dev->addr_len, 1); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_enable(zd); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(100); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_net_open(struct net_device *dev) 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7483d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start MAC with wildcard if no essid set */ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->mac_enabled) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_join(zd, zd->essid, zd->essidlen); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_net_stop(struct net_device *dev) 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RFC 1042 encapsulates Ethernet frames in 802.11 frames 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0 767093cf723b2b06d774929ea07982f6a466ff22314Steven Cole (0x00, 0x00, 0x00). Zd requires an additional padding, copy 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of ethernet addresses, length of the standard RFC 1042 packet 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and a command byte (which is nul for tx). 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx frame (from Wlan NG): 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RFC 1042: 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds llc 0xAA 0xAA 0x03 (802.2 LLC) 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snap 0x00 0x00 0x00 (Ethernet encapsulated) 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type 2 bytes, Ethernet type field 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds payload (minus eth header) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Zydas specific: 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds padding 1B if (skb->len+8+1)%64==0 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Eth MAC addr 12 bytes, Ethernet MAC addresses 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length 2 bytes, RFC 1042 packet length 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (llc+snap+type+payload) 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd 1 null byte, zd1201 packet type 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 784d0cf9c0dadcdc89a755bcb301cfc9c796eb28ccfStephen Hemmingerstatic netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, 785d0cf9c0dadcdc89a755bcb301cfc9c796eb28ccfStephen Hemminger struct net_device *dev) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7873d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *txbuf = zd->txdata; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int txbuflen, pad = 0, err; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct urb *urb = zd->tx_urb; 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->mac_enabled || zd->monitor) { 79322bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger dev->stats.tx_dropped++; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 7956ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuflen = skb->len + 8 + 1; 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (txbuflen%64 == 0) { 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pad = 1; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuflen++; 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[0] = 0xAA; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[1] = 0xAA; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[2] = 0x03; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[3] = 0x00; /* rfc1042 */ 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[4] = 0x00; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[5] = 0x00; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pad) 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[skb->len-12+6]=0; 814d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf[txbuflen-1] = 0; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out), 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txbuf, txbuflen, zd1201_usbtx, zd); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 82322bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger dev->stats.tx_errors++; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 8254153e77596c4caaf52293b0c6b2207d73ed8f1ebPatrick McHardy } else { 8264153e77596c4caaf52293b0c6b2207d73ed8f1ebPatrick McHardy dev->stats.tx_packets++; 8274153e77596c4caaf52293b0c6b2207d73ed8f1ebPatrick McHardy dev->stats.tx_bytes += skb->len; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8316ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void zd1201_tx_timeout(struct net_device *dev) 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8363d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd) 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_unlink_urb(zd->tx_urb); 84322bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger dev->stats.tx_errors++; 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restart the timeout to quiet the watchdog: */ 8451ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_mac_address(struct net_device *dev, void *p) 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr *addr = p; 8513d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd) 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr->sa_data, dev->addr_len, 1); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_mac_reset(zd); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8683d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &zd->iwstats; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void zd1201_set_multicast(struct net_device *dev) 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8753d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 87622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8804cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko if (netdev_mc_count(dev) > ZD1201_MAXMULTI) 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 883655ffee284dfcf9a24ac0343f3e5ee6db85b85c5Jiri Pirko i = 0; 88422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) 88522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, 8874cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko netdev_mc_count(dev) * ETH_ALEN, 0); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_config_commit(struct net_device *dev, 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *data, char *essid) 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8933d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_mac_reset(zd); 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_name(struct net_device *dev, 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, char *name, char *extra) 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(name, "IEEE 802.11b"); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_freq(struct net_device *dev, 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_freq *freq, char *extra) 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9083d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short channel = 0; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (freq->e == 0) 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel = freq->m; 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 9159ee677c2276bfcbcf68042ec2718a504af0c5fd7David Kilroy channel = ieee80211_freq_to_dsss_chan(freq->m); 9169ee677c2276bfcbcf68042ec2718a504af0c5fd7David Kilroy if (channel < 0) 9179ee677c2276bfcbcf68042ec2718a504af0c5fd7David Kilroy channel = 0; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_mac_reset(zd); 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_freq(struct net_device *dev, 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_freq *freq, char *extra) 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9323d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short channel; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds freq->e = 0; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds freq->m = channel; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_mode(struct net_device *dev, 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, __u32 *mode, char *extra) 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9483d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short porttype, monitor = 0; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buffer[IW_ESSID_MAX_SIZE+2]; 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->ap) { 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*mode != IW_MODE_MASTER) 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->dev->type = ARPHRD_ETHER; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(*mode) { 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IW_MODE_MONITOR: 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds monitor = 1; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->dev->type = ARPHRD_IEEE80211; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure we are no longer associated with by 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setting an 'impossible' essid. 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (otherwise we mess up firmware) 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_join(zd, "\0-*#\0", 5); 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Put port in pIBSS */ 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 8: /* No pseudo-IBSS in wireless extensions (yet) */ 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds porttype = ZD1201_PORTTYPE_PSEUDOIBSS; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IW_MODE_ADHOC: 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds porttype = ZD1201_PORTTYPE_IBSS; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IW_MODE_INFRA: 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds porttype = ZD1201_PORTTYPE_BSS; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->monitor && !monitor) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_disable(zd); 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(__le16 *)buffer = cpu_to_le16(zd->essidlen); 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(buffer+2, zd->essid, zd->essidlen); 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer, IW_ESSID_MAX_SIZE+2, 1); 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9982a8063403112030f1748e207d97d4f8654754dffPavel Machek zd->monitor = monitor; 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If monitor mode is set we don't actually turn it on here since it 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is done during mac reset anyway (see zd1201_mac_enable). 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_mac_reset(zd); 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_mode(struct net_device *dev, 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, __u32 *mode, char *extra) 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10103d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short porttype; 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype); 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(porttype) { 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_PORTTYPE_IBSS: 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = IW_MODE_ADHOC; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_PORTTYPE_BSS: 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = IW_MODE_INFRA; 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_PORTTYPE_WDS: 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = IW_MODE_REPEAT; 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_PORTTYPE_PSEUDOIBSS: 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = 8;/* No Pseudo-IBSS... */ 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ZD1201_PORTTYPE_AP: 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = IW_MODE_MASTER; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n", 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds porttype); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = IW_MODE_AUTO; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->monitor) 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *mode = IW_MODE_MONITOR; 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_range(struct net_device *dev, 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *wrq, char *extra) 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_range *range = (struct iw_range *)extra; 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrq->length = sizeof(struct iw_range); 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(range, 0, sizeof(struct iw_range)); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->we_version_compiled = WIRELESS_EXT; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->we_version_source = WIRELESS_EXT; 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->max_qual.qual = 128; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->max_qual.level = 128; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->max_qual.noise = 128; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->max_qual.updated = 7; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->encoding_size[0] = 5; 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->encoding_size[1] = 13; 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->num_encoding_sizes = 2; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->max_encoding_tokens = ZD1201_NUMKEYS; 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->num_bitrates = 4; 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->bitrate[0] = 1000000; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->bitrate[1] = 2000000; 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->bitrate[2] = 5500000; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->bitrate[3] = 11000000; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->min_rts = 0; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->min_frag = ZD1201_FRAGMIN; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->max_rts = ZD1201_RTSMAX; 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds range->min_frag = ZD1201_FRAGMAX; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Little bit of magic here: we only get the quality if we poll 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for it, and we never get an actual request to trigger such 1080093cf723b2b06d774929ea07982f6a466ff22314Steven Cole * a poll. Therefore we 'assume' that the user will soon ask for 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the stats after asking the bssid. 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_wap(struct net_device *dev, 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10863d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buffer[6]; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { 1090093cf723b2b06d774929ea07982f6a466ff22314Steven Cole /* Unfortunately the quality and noise reported is useless. 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds they seem to be accumulators that increase until you 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read them, unless we poll on a fixed interval we can't 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds use them 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/ 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]); 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/ 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->iwstats.qual.updated = 2; 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11012a8063403112030f1748e207d97d4f8654754dffPavel Machek return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6); 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_scan(struct net_device *dev, 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *srq, char *extra) 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We do everything in get_scan */ 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_scan(struct net_device *dev, 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *srq, char *extra) 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11143d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err, i, j, enabled_save; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_event iwe; 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *cev = extra; 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *end_buf = extra + IW_SCAN_MAX_DATA; 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No scanning in AP mode */ 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->ap) 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Scan doesn't seem to work if disabled */ 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled_save = zd->mac_enabled; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_enable(zd); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rxdatas = 0; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ZD1201_INQ_SCANRESULTS, 0, 0); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_event_interruptible(zd->rxdataq, zd->rxdatas); 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->rxlen) 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS) 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i=8; i<zd->rxlen; i+=62) { 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = SIOCGIWAP; 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); 1145ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_event(info, cev, end_buf, 1146ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_ADDR_LEN); 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = SIOCGIWESSID; 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.data.length = zd->rxdata[i+16]; 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.data.flags = 1; 1151ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_point(info, cev, end_buf, 1152ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, zd->rxdata+i+18); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = SIOCGIWMODE; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->rxdata[i+14]&0x01) 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.mode = IW_MODE_MASTER; 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.mode = IW_MODE_ADHOC; 1159ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_event(info, cev, end_buf, 1160ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_UINT_LEN); 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = SIOCGIWFREQ; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.freq.m = zd->rxdata[i+0]; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.freq.e = 0; 1165ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_event(info, cev, end_buf, 1166ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_FREQ_LEN); 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = SIOCGIWRATE; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.bitrate.fixed = 0; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.bitrate.disabled = 0; 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; 1173ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_event(info, cev, end_buf, 1174ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_PARAM_LEN); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = SIOCGIWENCODE; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.data.length = 0; 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->rxdata[i+14]&0x10) 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.data.flags = IW_ENCODE_ENABLED; 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.data.flags = IW_ENCODE_DISABLED; 1183ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.cmd = IWEVQUAL; 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.qual.qual = zd->rxdata[i+4]; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.qual.noise= zd->rxdata[i+2]/10-100; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iwe.u.qual.updated = 7; 1190ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller cev = iwe_stream_add_event(info, cev, end_buf, 1191ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_QUAL_LEN); 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!enabled_save) 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_disable(zd); 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds srq->length = cev - extra; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds srq->flags = 0; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_essid(struct net_device *dev, 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *data, char *essid) 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12063d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->length > IW_ESSID_MAX_SIZE) 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->length < 1) 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->length = 1; 121222b99262f59ddf5d283e19047e37dbc3be907e93Jean Tourrilhes zd->essidlen = data->length; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(zd->essid, essid, data->length); 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_join(zd, zd->essid, zd->essidlen); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_essid(struct net_device *dev, 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *data, char *essid) 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12213d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(essid, zd->essid, zd->essidlen); 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->flags = 1; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->length = zd->essidlen; 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_point *data, char *nick) 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(nick, "zd1201"); 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->flags = 1; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->length = strlen(nick); 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_rate(struct net_device *dev, 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12423d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short rate; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (rrq->value) { 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1000000: 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rate = ZD1201_RATEB1; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2000000: 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rate = ZD1201_RATEB2; 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5500000: 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rate = ZD1201_RATEB5; 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 11000000: 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rate = ZD1201_RATEB11; 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rrq->fixed) { /* Also enable all lower bitrates */ 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rate |= rate-1; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12642a8063403112030f1748e207d97d4f8654754dffPavel Machek 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_mac_reset(zd); 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_rate(struct net_device *dev, 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12753d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short rate; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate); 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(rate) { 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = 1000000; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = 2000000; 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 5: 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = 5500000; 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 11: 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = 11000000; 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = 0; 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->fixed = 0; 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->disabled = 0; 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_param *rts, char *extra) 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13083d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short val = rts->value; 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rts->disabled || !rts->fixed) 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = ZD1201_RTSMAX; 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val > ZD1201_RTSMAX) 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val < 0) 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val); 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_mac_reset(zd); 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_param *rts, char *extra) 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13283d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short rtst; 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst); 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rts->value = rtst; 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rts->disabled = (rts->value == ZD1201_RTSMAX); 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rts->fixed = 1; 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_param *frag, char *extra) 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13453d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short val = frag->value; 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (frag->disabled || !frag->fixed) 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = ZD1201_FRAGMAX; 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val > ZD1201_FRAGMAX) 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val < ZD1201_FRAGMIN) 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val & 1) 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val); 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_mac_reset(zd); 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_param *frag, char *extra) 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13663d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short fragt; 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt); 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frag->value = fragt; 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frag->disabled = (frag->value == ZD1201_FRAGMAX); 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frag->fixed = 1; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_retry(struct net_device *dev, 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_retry(struct net_device *dev, 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_encode(struct net_device *dev, 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *erq, char *key) 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13953d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short i; 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err, rid; 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (erq->length > ZD1201_MAXKEYLEN) 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (erq->flags & IW_ENCODE_INDEX)-1; 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == -1) { 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i); 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i); 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i < 0 || i >= ZD1201_NUMKEYS) 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rid = ZD1201_RID_CNFDEFAULTKEY0 + i; 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, rid, key, erq->length, 1); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->encode_keylen[i] = erq->length; 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(zd->encode_keys[i], key, erq->length); 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i=0; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) { 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= 0x01; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->encode_enabled = 1; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->encode_enabled = 0; 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) { 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= 0x02; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->encode_restricted = 1; 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->encode_restricted = 0; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i); 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->encode_enabled) 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = ZD1201_CNFAUTHENTICATION_SHAREDKEY; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i); 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_mac_reset(zd); 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_encode(struct net_device *dev, 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_point *erq, char *key) 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14523d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short i; 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->encode_enabled) 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erq->flags = IW_ENCODE_ENABLED; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erq->flags = IW_ENCODE_DISABLED; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->encode_restricted) 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erq->flags |= IW_ENCODE_RESTRICTED; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erq->flags |= IW_ENCODE_OPEN; 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (erq->flags & IW_ENCODE_INDEX) -1; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == -1) { 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i); 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i<0 || i>= ZD1201_NUMKEYS) 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erq->flags |= i+1; 14752a8063403112030f1748e207d97d4f8654754dffPavel Machek 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds erq->length = zd->encode_keylen[i]; 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(key, zd->encode_keys[i], erq->length); 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_power(struct net_device *dev, 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *vwrq, char *extra) 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14853d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short enabled, duration, level; 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enabled = vwrq->disabled ? 0 : 1; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enabled) { 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vwrq->flags & IW_POWER_PERIOD) { 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds duration = vwrq->value; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ZD1201_RID_CNFMAXSLEEPDURATION, duration); 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vwrq->flags & IW_POWER_TIMEOUT) { 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ZD1201_RID_CNFMAXSLEEPDURATION, &duration); 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds level = vwrq->value * 4 / duration; 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (level > 4) 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds level = 4; 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (level < 0) 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds level = 0; 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS, 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds level); 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 15182a8063403112030f1748e207d97d4f8654754dffPavel Machek return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled); 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_power(struct net_device *dev, 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *vwrq, char *extra) 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15243d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short enabled, level, duration; 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled); 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level); 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration); 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->disabled = enabled ? 0 : 1; 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vwrq->flags & IW_POWER_TYPE) { 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vwrq->flags & IW_POWER_PERIOD) { 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->value = duration; 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->flags = IW_POWER_PERIOD; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->value = duration * level / 4; 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->flags = IW_POWER_TIMEOUT; 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vwrq->flags & IW_POWER_MODE) { 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enabled && level) 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->flags = IW_POWER_UNICAST_R; 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vwrq->flags = IW_POWER_ALL_R; 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const iw_handler zd1201_iw_handler[] = 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_config_commit, /* SIOCSIWCOMMIT */ 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_name, /* SIOCGIWNAME */ 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWNWID */ 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWNWID */ 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_freq, /* SIOCSIWFREQ */ 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_freq, /* SIOCGIWFREQ */ 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_mode, /* SIOCSIWMODE */ 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_mode, /* SIOCGIWMODE */ 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWSENS */ 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWSENS */ 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWRANGE */ 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_range, /* SIOCGIWRANGE */ 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWPRIV */ 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWPRIV */ 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWSTATS */ 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWSTATS */ 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWSPY */ 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWSPY */ 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* -- hole -- */ 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* -- hole -- */ 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL/*zd1201_set_wap*/, /* SIOCSIWAP */ 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_wap, /* SIOCGIWAP */ 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* -- hole -- */ 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWAPLIST */ 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_scan, /* SIOCSIWSCAN */ 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_scan, /* SIOCGIWSCAN */ 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_essid, /* SIOCSIWESSID */ 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_essid, /* SIOCGIWESSID */ 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWNICKN */ 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_nick, /* SIOCGIWNICKN */ 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* -- hole -- */ 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* -- hole -- */ 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_rate, /* SIOCSIWRATE */ 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_rate, /* SIOCGIWRATE */ 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_rts, /* SIOCSIWRTS */ 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_rts, /* SIOCGIWRTS */ 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_frag, /* SIOCSIWFRAG */ 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_frag, /* SIOCGIWFRAG */ 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCSIWTXPOW */ 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* SIOCGIWTXPOW */ 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_retry, /* SIOCSIWRETRY */ 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_retry, /* SIOCGIWRETRY */ 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_encode, /* SIOCSIWENCODE */ 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_encode, /* SIOCGIWENCODE */ 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_power, /* SIOCSIWPOWER */ 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_power, /* SIOCGIWPOWER */ 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_hostauth(struct net_device *dev, 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16113d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->ap) 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16162a8063403112030f1748e207d97d4f8654754dffPavel Machek return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value); 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_hostauth(struct net_device *dev, 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16223d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short hostauth; 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->ap) 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth); 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = hostauth; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->fixed = 1; 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_auth_sta(struct net_device *dev, 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct sockaddr *sta, char *extra) 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16413d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buffer[10]; 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->ap) 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(buffer, sta->sa_data, ETH_ALEN); 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(short*)(buffer+6) = 0; /* 0==success, 1==failure */ 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(short*)(buffer+8) = 0; 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1); 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_set_maxassoc(struct net_device *dev, 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16573d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->ap) 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value); 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int zd1201_get_maxassoc(struct net_device *dev, 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iw_request_info *info, struct iw_param *rrq, char *extra) 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16723d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct zd1201 *zd = netdev_priv(dev); 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short maxassoc; 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->ap) 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc); 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->value = maxassoc; 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rrq->fixed = 1; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const iw_handler zd1201_private_handler[] = { 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */ 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */ 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_auth_sta, /* ZD1201SIWAUTHSTA */ 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) NULL, /* nothing to get */ 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */ 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (iw_handler) zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */ 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct iw_priv_args zd1201_private_args[] = { 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_PRIV_TYPE_NONE, "sethostauth" }, 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE, 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" }, 170252950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_PRIV_TYPE_NONE, "authstation" }, 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_PRIV_TYPE_NONE, "setmaxassoc" }, 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE, 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" }, 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct iw_handler_def zd1201_iw_handlers = { 171152950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser .num_standard = ARRAY_SIZE(zd1201_iw_handler), 171252950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser .num_private = ARRAY_SIZE(zd1201_private_handler), 171352950ed40dc97456209979af1d8f51b63cf6dcabTobias Klauser .num_private_args = ARRAY_SIZE(zd1201_private_args), 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .standard = (iw_handler *)zd1201_iw_handler, 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .private = (iw_handler *)zd1201_private_handler, 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .private_args = (struct iw_priv_args *) zd1201_private_args, 17170073602544954002e35699477dc59cdd5e9112e3Jean Tourrilhes .get_wireless_stats = zd1201_get_wireless_stats, 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17202bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemmingerstatic const struct net_device_ops zd1201_netdev_ops = { 17212bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_open = zd1201_net_open, 17222bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_stop = zd1201_net_stop, 17232bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_start_xmit = zd1201_hard_start_xmit, 17242bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_tx_timeout = zd1201_tx_timeout, 1725afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = zd1201_set_multicast, 17262bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_set_mac_address = zd1201_set_mac_address, 17272bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_change_mtu = eth_change_mtu, 17282bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger .ndo_validate_addr = eth_validate_addr, 17292bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger}; 17302bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger 17312e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunkstatic int zd1201_probe(struct usb_interface *interface, 17322e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunk const struct usb_device_id *id) 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct zd1201 *zd; 17353d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville struct net_device *dev; 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_device *usb; 17372a8063403112030f1748e207d97d4f8654754dffPavel Machek int err; 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short porttype; 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char buf[IW_ESSID_MAX_SIZE+2]; 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb = interface_to_usbdev(interface); 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17433d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville dev = alloc_etherdev(sizeof(*zd)); 17443d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville if (!dev) 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 17463d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville zd = netdev_priv(dev); 17473d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville zd->dev = dev; 17483d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->ap = ap; 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->usb = usb; 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->removed = 0; 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&zd->rxdataq); 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_HLIST_HEAD(&zd->fraglist); 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_fw_upload(usb, zd->ap); 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err); 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_zd; 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->endp_in = 1; 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->endp_out = 1; 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->endp_out2 = 2; 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd->rx_urb || !zd->tx_urb) 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_zd; 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17692a8063403112030f1748e207d97d4f8654754dffPavel Machek mdelay(100); 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_drvr_start(zd); 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_zd; 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312); 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_start; 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11); 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_start; 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17832bd9f54d46e28fdaa15240af6a97c953720ea5c1Stephen Hemminger dev->netdev_ops = &zd1201_netdev_ops; 178422bc1ce4f171f53c27052e1d74d312345487db16Stephen Hemminger dev->wireless_handlers = &zd1201_iw_handlers; 17853d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville dev->watchdog_timeo = ZD1201_TX_TIMEOUT; 17863d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville strcpy(dev->name, "wlan%d"); 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, 17893d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville dev->dev_addr, dev->addr_len); 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 17913d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville goto err_start; 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set wildcard essid to match zd->essid */ 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(__le16 *)buf = cpu_to_le16(0); 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IW_ESSID_MAX_SIZE+2, 1); 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 17983d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville goto err_start; 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->ap) 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds porttype = ZD1201_PORTTYPE_AP; 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds porttype = ZD1201_PORTTYPE_BSS; 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 18063d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville goto err_start; 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18083d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville SET_NETDEV_DEV(dev, &usb->dev); 1809a083dec0ed537a75fbe8f2f83d198e9e672240d8Nathan Lynch 18103d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville err = register_netdev(dev); 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 18123d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville goto err_start; 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", 18143d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville dev->name); 18152a8063403112030f1748e207d97d4f8654754dffPavel Machek 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(interface, zd); 1817d91928e906e2866563a69506bb77ffebcf50613cPavel Machek zd1201_enable(zd); /* zd1201 likes to startup enabled, */ 1818d91928e906e2866563a69506bb77ffebcf50613cPavel Machek zd1201_disable(zd); /* interfering with all the wifis in range */ 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_start: 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Leave the device in reset state */ 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_zd: 1825f988f272fe8de462045e9f298e5b7f1e39b2e53aMariusz Kozlowski usb_free_urb(zd->tx_urb); 1826f988f272fe8de462045e9f298e5b7f1e39b2e53aMariusz Kozlowski usb_free_urb(zd->rx_urb); 18273d29b0c33d431ecc69ec778f8c236d382f59a85fJohn W. Linville free_netdev(dev); 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18312e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunkstatic void zd1201_disconnect(struct usb_interface *interface) 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1833b2767363192d5937e0f61f05b1b6b881da9ee55aJoe Perches struct zd1201 *zd = usb_get_intfdata(interface); 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct hlist_node *node, *node2; 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct zd1201_frag *frag; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!zd) 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_set_intfdata(interface, NULL); 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) { 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hlist_del_init(&frag->fnode); 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(frag->skb); 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(frag); 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->tx_urb) { 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(zd->tx_urb); 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_free_urb(zd->tx_urb); 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (zd->rx_urb) { 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_kill_urb(zd->rx_urb); 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_free_urb(zd->rx_urb); 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1855b88a2a22c6670c31586d1a716255eae4c320b363Wang Chen 1856b88a2a22c6670c31586d1a716255eae4c320b363Wang Chen if (zd->dev) { 1857b88a2a22c6670c31586d1a716255eae4c320b363Wang Chen unregister_netdev(zd->dev); 1858b88a2a22c6670c31586d1a716255eae4c320b363Wang Chen free_netdev(zd->dev); 1859b88a2a22c6670c31586d1a716255eae4c320b363Wang Chen } 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1862a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy#ifdef CONFIG_PM 1863a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1864a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroystatic int zd1201_suspend(struct usb_interface *interface, 1865a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy pm_message_t message) 1866a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy{ 1867a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy struct zd1201 *zd = usb_get_intfdata(interface); 1868a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1869a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy netif_device_detach(zd->dev); 1870a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1871a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy zd->was_enabled = zd->mac_enabled; 1872a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1873a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy if (zd->was_enabled) 1874a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy return zd1201_disable(zd); 1875a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy else 1876a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy return 0; 1877a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy} 1878a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1879a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroystatic int zd1201_resume(struct usb_interface *interface) 1880a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy{ 1881a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy struct zd1201 *zd = usb_get_intfdata(interface); 1882a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1883f58f97fa9d258e4110ee1257a63cd1af51787f69Colin Leroy if (!zd || !zd->dev) 1884f58f97fa9d258e4110ee1257a63cd1af51787f69Colin Leroy return -ENODEV; 1885f58f97fa9d258e4110ee1257a63cd1af51787f69Colin Leroy 1886a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy netif_device_attach(zd->dev); 1887a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1888a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy if (zd->was_enabled) 1889a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy return zd1201_enable(zd); 1890a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy else 1891a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy return 0; 1892a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy} 1893a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1894a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy#else 1895a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1896a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy#define zd1201_suspend NULL 1897a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy#define zd1201_resume NULL 1898a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 1899a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy#endif 1900a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy 19012e0a6b8cd27375089f8356e7f1ce2319059696ebAdrian Bunkstatic struct usb_driver zd1201_usb = { 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "zd1201", 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = zd1201_probe, 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = zd1201_disconnect, 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = zd1201_table, 1906a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy .suspend = zd1201_suspend, 1907a3c900bb8cbacfecf0be51313e43f330663266a1Colin Leroy .resume = zd1201_resume, 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1910d632eb1bf22e11def74e4e53cc47d790fbdba105Greg Kroah-Hartmanmodule_usb_driver(zd1201_usb); 1911