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