162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for ZyDAS zd1201 based USB wireless devices. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Parts of this driver have been derived from a wlan-ng version 862306a36Sopenharmony_ci * modified by ZyDAS. They also made documentation available, thanks! 962306a36Sopenharmony_ci * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/usb.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <linux/etherdevice.h> 1762306a36Sopenharmony_ci#include <linux/wireless.h> 1862306a36Sopenharmony_ci#include <net/cfg80211.h> 1962306a36Sopenharmony_ci#include <net/iw_handler.h> 2062306a36Sopenharmony_ci#include <linux/string.h> 2162306a36Sopenharmony_ci#include <linux/if_arp.h> 2262306a36Sopenharmony_ci#include <linux/firmware.h> 2362306a36Sopenharmony_ci#include "zd1201.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const struct usb_device_id zd1201_table[] = { 2662306a36Sopenharmony_ci {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */ 2762306a36Sopenharmony_ci {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */ 2862306a36Sopenharmony_ci {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ 2962306a36Sopenharmony_ci {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ 3062306a36Sopenharmony_ci {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ 3162306a36Sopenharmony_ci {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ 3262306a36Sopenharmony_ci {} 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int ap; /* Are we an AP or a normal station? */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define ZD1201_VERSION "0.15" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciMODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>"); 4062306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters"); 4162306a36Sopenharmony_ciMODULE_VERSION(ZD1201_VERSION); 4262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4362306a36Sopenharmony_cimodule_param(ap, int, 0); 4462306a36Sopenharmony_ciMODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); 4562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, zd1201_table); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int zd1201_fw_upload(struct usb_device *dev, int apfw) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci const struct firmware *fw_entry; 5162306a36Sopenharmony_ci const char *data; 5262306a36Sopenharmony_ci unsigned long len; 5362306a36Sopenharmony_ci int err; 5462306a36Sopenharmony_ci unsigned char ret; 5562306a36Sopenharmony_ci char *buf; 5662306a36Sopenharmony_ci char *fwfile; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (apfw) 5962306a36Sopenharmony_ci fwfile = "zd1201-ap.fw"; 6062306a36Sopenharmony_ci else 6162306a36Sopenharmony_ci fwfile = "zd1201.fw"; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci err = request_firmware(&fw_entry, fwfile, &dev->dev); 6462306a36Sopenharmony_ci if (err) { 6562306a36Sopenharmony_ci dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile); 6662306a36Sopenharmony_ci dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n"); 6762306a36Sopenharmony_ci dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n"); 6862306a36Sopenharmony_ci return err; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci data = fw_entry->data; 7262306a36Sopenharmony_ci len = fw_entry->size; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci buf = kmalloc(1024, GFP_ATOMIC); 7562306a36Sopenharmony_ci if (!buf) { 7662306a36Sopenharmony_ci err = -ENOMEM; 7762306a36Sopenharmony_ci goto exit; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci while (len > 0) { 8162306a36Sopenharmony_ci int translen = (len > 1024) ? 1024 : len; 8262306a36Sopenharmony_ci memcpy(buf, data, translen); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, 8562306a36Sopenharmony_ci USB_DIR_OUT | 0x40, 0, 0, buf, translen, 8662306a36Sopenharmony_ci ZD1201_FW_TIMEOUT); 8762306a36Sopenharmony_ci if (err < 0) 8862306a36Sopenharmony_ci goto exit; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci len -= translen; 9162306a36Sopenharmony_ci data += translen; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2, 9562306a36Sopenharmony_ci USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT); 9662306a36Sopenharmony_ci if (err < 0) 9762306a36Sopenharmony_ci goto exit; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, 10062306a36Sopenharmony_ci USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT); 10162306a36Sopenharmony_ci if (err < 0) 10262306a36Sopenharmony_ci goto exit; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci memcpy(&ret, buf, sizeof(ret)); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (ret & 0x80) { 10762306a36Sopenharmony_ci err = -EIO; 10862306a36Sopenharmony_ci goto exit; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci err = 0; 11262306a36Sopenharmony_ciexit: 11362306a36Sopenharmony_ci kfree(buf); 11462306a36Sopenharmony_ci release_firmware(fw_entry); 11562306a36Sopenharmony_ci return err; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciMODULE_FIRMWARE("zd1201-ap.fw"); 11962306a36Sopenharmony_ciMODULE_FIRMWARE("zd1201.fw"); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void zd1201_usbfree(struct urb *urb) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct zd1201 *zd = urb->context; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci switch(urb->status) { 12662306a36Sopenharmony_ci case -EILSEQ: 12762306a36Sopenharmony_ci case -ENODEV: 12862306a36Sopenharmony_ci case -ETIME: 12962306a36Sopenharmony_ci case -ENOENT: 13062306a36Sopenharmony_ci case -EPIPE: 13162306a36Sopenharmony_ci case -EOVERFLOW: 13262306a36Sopenharmony_ci case -ESHUTDOWN: 13362306a36Sopenharmony_ci dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", 13462306a36Sopenharmony_ci zd->dev->name, urb->status); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci kfree(urb->transfer_buffer); 13862306a36Sopenharmony_ci usb_free_urb(urb); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* cmdreq message: 14262306a36Sopenharmony_ci u32 type 14362306a36Sopenharmony_ci u16 cmd 14462306a36Sopenharmony_ci u16 parm0 14562306a36Sopenharmony_ci u16 parm1 14662306a36Sopenharmony_ci u16 parm2 14762306a36Sopenharmony_ci u8 pad[4] 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci total: 4 + 2 + 2 + 2 + 2 + 4 = 16 15062306a36Sopenharmony_ci*/ 15162306a36Sopenharmony_cistatic int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, 15262306a36Sopenharmony_ci int parm1, int parm2) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci unsigned char *command; 15562306a36Sopenharmony_ci int ret; 15662306a36Sopenharmony_ci struct urb *urb; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci command = kmalloc(16, GFP_ATOMIC); 15962306a36Sopenharmony_ci if (!command) 16062306a36Sopenharmony_ci return -ENOMEM; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ); 16362306a36Sopenharmony_ci *((__le16*)&command[4]) = cpu_to_le16(cmd); 16462306a36Sopenharmony_ci *((__le16*)&command[6]) = cpu_to_le16(parm0); 16562306a36Sopenharmony_ci *((__le16*)&command[8]) = cpu_to_le16(parm1); 16662306a36Sopenharmony_ci *((__le16*)&command[10])= cpu_to_le16(parm2); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci urb = usb_alloc_urb(0, GFP_ATOMIC); 16962306a36Sopenharmony_ci if (!urb) { 17062306a36Sopenharmony_ci kfree(command); 17162306a36Sopenharmony_ci return -ENOMEM; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), 17462306a36Sopenharmony_ci command, 16, zd1201_usbfree, zd); 17562306a36Sopenharmony_ci ret = usb_submit_urb(urb, GFP_ATOMIC); 17662306a36Sopenharmony_ci if (ret) { 17762306a36Sopenharmony_ci kfree(command); 17862306a36Sopenharmony_ci usb_free_urb(urb); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* Callback after sending out a packet */ 18562306a36Sopenharmony_cistatic void zd1201_usbtx(struct urb *urb) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct zd1201 *zd = urb->context; 18862306a36Sopenharmony_ci netif_wake_queue(zd->dev); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* Incoming data */ 19262306a36Sopenharmony_cistatic void zd1201_usbrx(struct urb *urb) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct zd1201 *zd = urb->context; 19562306a36Sopenharmony_ci int free = 0; 19662306a36Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 19762306a36Sopenharmony_ci struct sk_buff *skb; 19862306a36Sopenharmony_ci unsigned char type; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!zd) 20162306a36Sopenharmony_ci return; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci switch(urb->status) { 20462306a36Sopenharmony_ci case -EILSEQ: 20562306a36Sopenharmony_ci case -ENODEV: 20662306a36Sopenharmony_ci case -ETIME: 20762306a36Sopenharmony_ci case -ENOENT: 20862306a36Sopenharmony_ci case -EPIPE: 20962306a36Sopenharmony_ci case -EOVERFLOW: 21062306a36Sopenharmony_ci case -ESHUTDOWN: 21162306a36Sopenharmony_ci dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n", 21262306a36Sopenharmony_ci zd->dev->name, urb->status); 21362306a36Sopenharmony_ci free = 1; 21462306a36Sopenharmony_ci goto exit; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (urb->status != 0 || urb->actual_length == 0) 21862306a36Sopenharmony_ci goto resubmit; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci type = data[0]; 22162306a36Sopenharmony_ci if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) { 22262306a36Sopenharmony_ci memcpy(zd->rxdata, data, urb->actual_length); 22362306a36Sopenharmony_ci zd->rxlen = urb->actual_length; 22462306a36Sopenharmony_ci zd->rxdatas = 1; 22562306a36Sopenharmony_ci wake_up(&zd->rxdataq); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci /* Info frame */ 22862306a36Sopenharmony_ci if (type == ZD1201_PACKET_INQUIRE) { 22962306a36Sopenharmony_ci int i = 0; 23062306a36Sopenharmony_ci unsigned short infotype, copylen; 23162306a36Sopenharmony_ci infotype = le16_to_cpu(*(__le16*)&data[6]); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (infotype == ZD1201_INF_LINKSTATUS) { 23462306a36Sopenharmony_ci short linkstatus; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci linkstatus = le16_to_cpu(*(__le16*)&data[8]); 23762306a36Sopenharmony_ci switch(linkstatus) { 23862306a36Sopenharmony_ci case 1: 23962306a36Sopenharmony_ci netif_carrier_on(zd->dev); 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case 2: 24262306a36Sopenharmony_ci netif_carrier_off(zd->dev); 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci case 3: 24562306a36Sopenharmony_ci netif_carrier_off(zd->dev); 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci case 4: 24862306a36Sopenharmony_ci netif_carrier_on(zd->dev); 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci default: 25162306a36Sopenharmony_ci netif_carrier_off(zd->dev); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci goto resubmit; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci if (infotype == ZD1201_INF_ASSOCSTATUS) { 25662306a36Sopenharmony_ci short status = le16_to_cpu(*(__le16*)(data+8)); 25762306a36Sopenharmony_ci int event; 25862306a36Sopenharmony_ci union iwreq_data wrqu; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci switch (status) { 26162306a36Sopenharmony_ci case ZD1201_ASSOCSTATUS_STAASSOC: 26262306a36Sopenharmony_ci case ZD1201_ASSOCSTATUS_REASSOC: 26362306a36Sopenharmony_ci event = IWEVREGISTERED; 26462306a36Sopenharmony_ci break; 26562306a36Sopenharmony_ci case ZD1201_ASSOCSTATUS_DISASSOC: 26662306a36Sopenharmony_ci case ZD1201_ASSOCSTATUS_ASSOCFAIL: 26762306a36Sopenharmony_ci case ZD1201_ASSOCSTATUS_AUTHFAIL: 26862306a36Sopenharmony_ci default: 26962306a36Sopenharmony_ci event = IWEVEXPIRED; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN); 27262306a36Sopenharmony_ci wrqu.addr.sa_family = ARPHRD_ETHER; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Send event to user space */ 27562306a36Sopenharmony_ci wireless_send_event(zd->dev, event, &wrqu, NULL); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci goto resubmit; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci if (infotype == ZD1201_INF_AUTHREQ) { 28062306a36Sopenharmony_ci union iwreq_data wrqu; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN); 28362306a36Sopenharmony_ci wrqu.addr.sa_family = ARPHRD_ETHER; 28462306a36Sopenharmony_ci /* There isn't a event that trully fits this request. 28562306a36Sopenharmony_ci We assume that userspace will be smart enough to 28662306a36Sopenharmony_ci see a new station being expired and sends back a 28762306a36Sopenharmony_ci authstation ioctl to authorize it. */ 28862306a36Sopenharmony_ci wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL); 28962306a36Sopenharmony_ci goto resubmit; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci /* Other infotypes are handled outside this handler */ 29262306a36Sopenharmony_ci zd->rxlen = 0; 29362306a36Sopenharmony_ci while (i < urb->actual_length) { 29462306a36Sopenharmony_ci copylen = le16_to_cpu(*(__le16*)&data[i+2]); 29562306a36Sopenharmony_ci /* Sanity check, sometimes we get junk */ 29662306a36Sopenharmony_ci if (copylen+zd->rxlen > sizeof(zd->rxdata)) 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen); 29962306a36Sopenharmony_ci zd->rxlen += copylen; 30062306a36Sopenharmony_ci i += 64; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci if (i >= urb->actual_length) { 30362306a36Sopenharmony_ci zd->rxdatas = 1; 30462306a36Sopenharmony_ci wake_up(&zd->rxdataq); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci goto resubmit; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci /* Actual data */ 30962306a36Sopenharmony_ci if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) { 31062306a36Sopenharmony_ci int datalen = urb->actual_length-1; 31162306a36Sopenharmony_ci unsigned short len, fc, seq; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci len = ntohs(*(__be16 *)&data[datalen-2]); 31462306a36Sopenharmony_ci if (len>datalen) 31562306a36Sopenharmony_ci len=datalen; 31662306a36Sopenharmony_ci fc = le16_to_cpu(*(__le16 *)&data[datalen-16]); 31762306a36Sopenharmony_ci seq = le16_to_cpu(*(__le16 *)&data[datalen-24]); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (zd->monitor) { 32062306a36Sopenharmony_ci if (datalen < 24) 32162306a36Sopenharmony_ci goto resubmit; 32262306a36Sopenharmony_ci if (!(skb = dev_alloc_skb(datalen+24))) 32362306a36Sopenharmony_ci goto resubmit; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 16], 2); 32662306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 2], 2); 32762306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 14], 6); 32862306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 22], 6); 32962306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 8], 6); 33062306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 24], 2); 33162306a36Sopenharmony_ci skb_put_data(skb, data, len); 33262306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, zd->dev); 33362306a36Sopenharmony_ci zd->dev->stats.rx_packets++; 33462306a36Sopenharmony_ci zd->dev->stats.rx_bytes += skb->len; 33562306a36Sopenharmony_ci netif_rx(skb); 33662306a36Sopenharmony_ci goto resubmit; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if ((seq & IEEE80211_SCTL_FRAG) || 34062306a36Sopenharmony_ci (fc & IEEE80211_FCTL_MOREFRAGS)) { 34162306a36Sopenharmony_ci struct zd1201_frag *frag = NULL; 34262306a36Sopenharmony_ci char *ptr; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (datalen<14) 34562306a36Sopenharmony_ci goto resubmit; 34662306a36Sopenharmony_ci if ((seq & IEEE80211_SCTL_FRAG) == 0) { 34762306a36Sopenharmony_ci frag = kmalloc(sizeof(*frag), GFP_ATOMIC); 34862306a36Sopenharmony_ci if (!frag) 34962306a36Sopenharmony_ci goto resubmit; 35062306a36Sopenharmony_ci skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); 35162306a36Sopenharmony_ci if (!skb) { 35262306a36Sopenharmony_ci kfree(frag); 35362306a36Sopenharmony_ci goto resubmit; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci frag->skb = skb; 35662306a36Sopenharmony_ci frag->seq = seq & IEEE80211_SCTL_SEQ; 35762306a36Sopenharmony_ci skb_reserve(skb, 2); 35862306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 14], 12); 35962306a36Sopenharmony_ci skb_put_data(skb, &data[6], 2); 36062306a36Sopenharmony_ci skb_put_data(skb, data + 8, len); 36162306a36Sopenharmony_ci hlist_add_head(&frag->fnode, &zd->fraglist); 36262306a36Sopenharmony_ci goto resubmit; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci hlist_for_each_entry(frag, &zd->fraglist, fnode) 36562306a36Sopenharmony_ci if (frag->seq == (seq&IEEE80211_SCTL_SEQ)) 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci if (!frag) 36862306a36Sopenharmony_ci goto resubmit; 36962306a36Sopenharmony_ci skb = frag->skb; 37062306a36Sopenharmony_ci ptr = skb_put(skb, len); 37162306a36Sopenharmony_ci if (ptr) 37262306a36Sopenharmony_ci memcpy(ptr, data+8, len); 37362306a36Sopenharmony_ci if (fc & IEEE80211_FCTL_MOREFRAGS) 37462306a36Sopenharmony_ci goto resubmit; 37562306a36Sopenharmony_ci hlist_del_init(&frag->fnode); 37662306a36Sopenharmony_ci kfree(frag); 37762306a36Sopenharmony_ci } else { 37862306a36Sopenharmony_ci if (datalen<14) 37962306a36Sopenharmony_ci goto resubmit; 38062306a36Sopenharmony_ci skb = dev_alloc_skb(len + 14 + 2); 38162306a36Sopenharmony_ci if (!skb) 38262306a36Sopenharmony_ci goto resubmit; 38362306a36Sopenharmony_ci skb_reserve(skb, 2); 38462306a36Sopenharmony_ci skb_put_data(skb, &data[datalen - 14], 12); 38562306a36Sopenharmony_ci skb_put_data(skb, &data[6], 2); 38662306a36Sopenharmony_ci skb_put_data(skb, data + 8, len); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, zd->dev); 38962306a36Sopenharmony_ci zd->dev->stats.rx_packets++; 39062306a36Sopenharmony_ci zd->dev->stats.rx_bytes += skb->len; 39162306a36Sopenharmony_ci netif_rx(skb); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ciresubmit: 39462306a36Sopenharmony_ci memset(data, 0, ZD1201_RXSIZE); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci urb->status = 0; 39762306a36Sopenharmony_ci urb->dev = zd->usb; 39862306a36Sopenharmony_ci if(usb_submit_urb(urb, GFP_ATOMIC)) 39962306a36Sopenharmony_ci free = 1; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciexit: 40262306a36Sopenharmony_ci if (free) { 40362306a36Sopenharmony_ci zd->rxlen = 0; 40462306a36Sopenharmony_ci zd->rxdatas = 1; 40562306a36Sopenharmony_ci wake_up(&zd->rxdataq); 40662306a36Sopenharmony_ci kfree(urb->transfer_buffer); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata, 41162306a36Sopenharmony_ci unsigned int riddatalen) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci int err; 41462306a36Sopenharmony_ci int i = 0; 41562306a36Sopenharmony_ci int code; 41662306a36Sopenharmony_ci int rid_fid; 41762306a36Sopenharmony_ci int length; 41862306a36Sopenharmony_ci unsigned char *pdata; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci zd->rxdatas = 0; 42162306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0); 42262306a36Sopenharmony_ci if (err) 42362306a36Sopenharmony_ci return err; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci wait_event_interruptible(zd->rxdataq, zd->rxdatas); 42662306a36Sopenharmony_ci if (!zd->rxlen) 42762306a36Sopenharmony_ci return -EIO; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci code = le16_to_cpu(*(__le16*)(&zd->rxdata[4])); 43062306a36Sopenharmony_ci rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6])); 43162306a36Sopenharmony_ci length = le16_to_cpu(*(__le16*)(&zd->rxdata[8])); 43262306a36Sopenharmony_ci if (length > zd->rxlen) 43362306a36Sopenharmony_ci length = zd->rxlen-6; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* If access bit is not on, then error */ 43662306a36Sopenharmony_ci if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid ) 43762306a36Sopenharmony_ci return -EINVAL; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Not enough buffer for allocating data */ 44062306a36Sopenharmony_ci if (riddatalen != (length - 4)) { 44162306a36Sopenharmony_ci dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n", 44262306a36Sopenharmony_ci riddatalen, zd->rxlen, length, rid, rid_fid); 44362306a36Sopenharmony_ci return -ENODATA; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci zd->rxdatas = 0; 44762306a36Sopenharmony_ci /* Issue SetRxRid commnd */ 44862306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length); 44962306a36Sopenharmony_ci if (err) 45062306a36Sopenharmony_ci return err; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Receive RID record from resource packets */ 45362306a36Sopenharmony_ci wait_event_interruptible(zd->rxdataq, zd->rxdatas); 45462306a36Sopenharmony_ci if (!zd->rxlen) 45562306a36Sopenharmony_ci return -EIO; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) { 45862306a36Sopenharmony_ci dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n", 45962306a36Sopenharmony_ci zd->rxdata[zd->rxlen-1]); 46062306a36Sopenharmony_ci return -EINVAL; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Set the data pointer and received data length */ 46462306a36Sopenharmony_ci pdata = zd->rxdata; 46562306a36Sopenharmony_ci length = zd->rxlen; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci do { 46862306a36Sopenharmony_ci int actual_length; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci actual_length = (length > 64) ? 64 : length; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (pdata[0] != 0x3) { 47362306a36Sopenharmony_ci dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n", 47462306a36Sopenharmony_ci pdata[0]); 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (actual_length != 64) { 47962306a36Sopenharmony_ci /* Trim the last packet type byte */ 48062306a36Sopenharmony_ci actual_length--; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Skip the 4 bytes header (RID length and RID) */ 48462306a36Sopenharmony_ci if (i == 0) { 48562306a36Sopenharmony_ci pdata += 8; 48662306a36Sopenharmony_ci actual_length -= 8; 48762306a36Sopenharmony_ci } else { 48862306a36Sopenharmony_ci pdata += 4; 48962306a36Sopenharmony_ci actual_length -= 4; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci memcpy(riddata, pdata, actual_length); 49362306a36Sopenharmony_ci riddata += actual_length; 49462306a36Sopenharmony_ci pdata += actual_length; 49562306a36Sopenharmony_ci length -= 64; 49662306a36Sopenharmony_ci i++; 49762306a36Sopenharmony_ci } while (length > 0); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/* 50362306a36Sopenharmony_ci * resreq: 50462306a36Sopenharmony_ci * byte type 50562306a36Sopenharmony_ci * byte sequence 50662306a36Sopenharmony_ci * u16 reserved 50762306a36Sopenharmony_ci * byte data[12] 50862306a36Sopenharmony_ci * total: 16 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_cistatic int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci int err; 51362306a36Sopenharmony_ci unsigned char *request; 51462306a36Sopenharmony_ci int reqlen; 51562306a36Sopenharmony_ci char seq=0; 51662306a36Sopenharmony_ci struct urb *urb; 51762306a36Sopenharmony_ci gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci len += 4; /* first 4 are for header */ 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci zd->rxdatas = 0; 52262306a36Sopenharmony_ci zd->rxlen = 0; 52362306a36Sopenharmony_ci for (seq=0; len > 0; seq++) { 52462306a36Sopenharmony_ci request = kzalloc(16, gfp_mask); 52562306a36Sopenharmony_ci if (!request) 52662306a36Sopenharmony_ci return -ENOMEM; 52762306a36Sopenharmony_ci urb = usb_alloc_urb(0, gfp_mask); 52862306a36Sopenharmony_ci if (!urb) { 52962306a36Sopenharmony_ci kfree(request); 53062306a36Sopenharmony_ci return -ENOMEM; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci reqlen = len>12 ? 12 : len; 53362306a36Sopenharmony_ci request[0] = ZD1201_USB_RESREQ; 53462306a36Sopenharmony_ci request[1] = seq; 53562306a36Sopenharmony_ci request[2] = 0; 53662306a36Sopenharmony_ci request[3] = 0; 53762306a36Sopenharmony_ci if (request[1] == 0) { 53862306a36Sopenharmony_ci /* add header */ 53962306a36Sopenharmony_ci *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2); 54062306a36Sopenharmony_ci *(__le16*)&request[6] = cpu_to_le16(rid); 54162306a36Sopenharmony_ci memcpy(request+8, buf, reqlen-4); 54262306a36Sopenharmony_ci buf += reqlen-4; 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci memcpy(request+4, buf, reqlen); 54562306a36Sopenharmony_ci buf += reqlen; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci len -= reqlen; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, 55162306a36Sopenharmony_ci zd->endp_out2), request, 16, zd1201_usbfree, zd); 55262306a36Sopenharmony_ci err = usb_submit_urb(urb, gfp_mask); 55362306a36Sopenharmony_ci if (err) 55462306a36Sopenharmony_ci goto err; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci request = kmalloc(16, gfp_mask); 55862306a36Sopenharmony_ci if (!request) 55962306a36Sopenharmony_ci return -ENOMEM; 56062306a36Sopenharmony_ci urb = usb_alloc_urb(0, gfp_mask); 56162306a36Sopenharmony_ci if (!urb) { 56262306a36Sopenharmony_ci kfree(request); 56362306a36Sopenharmony_ci return -ENOMEM; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ); 56662306a36Sopenharmony_ci *((__le16*)&request[4]) = 56762306a36Sopenharmony_ci cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT); 56862306a36Sopenharmony_ci *((__le16*)&request[6]) = cpu_to_le16(rid); 56962306a36Sopenharmony_ci *((__le16*)&request[8]) = cpu_to_le16(0); 57062306a36Sopenharmony_ci *((__le16*)&request[10]) = cpu_to_le16(0); 57162306a36Sopenharmony_ci usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), 57262306a36Sopenharmony_ci request, 16, zd1201_usbfree, zd); 57362306a36Sopenharmony_ci err = usb_submit_urb(urb, gfp_mask); 57462306a36Sopenharmony_ci if (err) 57562306a36Sopenharmony_ci goto err; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (wait) { 57862306a36Sopenharmony_ci wait_event_interruptible(zd->rxdataq, zd->rxdatas); 57962306a36Sopenharmony_ci if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) { 58062306a36Sopenharmony_ci dev_dbg(&zd->usb->dev, "wrong or no RID received\n"); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_cierr: 58662306a36Sopenharmony_ci kfree(request); 58762306a36Sopenharmony_ci usb_free_urb(urb); 58862306a36Sopenharmony_ci return err; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci int err; 59462306a36Sopenharmony_ci __le16 zdval; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16)); 59762306a36Sopenharmony_ci if (err) 59862306a36Sopenharmony_ci return err; 59962306a36Sopenharmony_ci *val = le16_to_cpu(zdval); 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci __le16 zdval = cpu_to_le16(val); 60662306a36Sopenharmony_ci return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int zd1201_drvr_start(struct zd1201 *zd) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci int err, i; 61262306a36Sopenharmony_ci short max; 61362306a36Sopenharmony_ci __le16 zdmax; 61462306a36Sopenharmony_ci unsigned char *buffer; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); 61762306a36Sopenharmony_ci if (!buffer) 61862306a36Sopenharmony_ci return -ENOMEM; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci usb_fill_bulk_urb(zd->rx_urb, zd->usb, 62162306a36Sopenharmony_ci usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, 62262306a36Sopenharmony_ci zd1201_usbrx, zd); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci err = usb_submit_urb(zd->rx_urb, GFP_KERNEL); 62562306a36Sopenharmony_ci if (err) 62662306a36Sopenharmony_ci goto err_buffer; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); 62962306a36Sopenharmony_ci if (err) 63062306a36Sopenharmony_ci goto err_urb; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax, 63362306a36Sopenharmony_ci sizeof(__le16)); 63462306a36Sopenharmony_ci if (err) 63562306a36Sopenharmony_ci goto err_urb; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci max = le16_to_cpu(zdmax); 63862306a36Sopenharmony_ci for (i=0; i<max; i++) { 63962306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0); 64062306a36Sopenharmony_ci if (err) 64162306a36Sopenharmony_ci goto err_urb; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cierr_urb: 64762306a36Sopenharmony_ci usb_kill_urb(zd->rx_urb); 64862306a36Sopenharmony_ci return err; 64962306a36Sopenharmony_cierr_buffer: 65062306a36Sopenharmony_ci kfree(buffer); 65162306a36Sopenharmony_ci return err; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci/* Magic alert: The firmware doesn't seem to like the MAC state being 65562306a36Sopenharmony_ci * toggled in promisc (aka monitor) mode. 65662306a36Sopenharmony_ci * (It works a number of times, but will halt eventually) 65762306a36Sopenharmony_ci * So we turn it of before disabling and on after enabling if needed. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_cistatic int zd1201_enable(struct zd1201 *zd) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci int err; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (zd->mac_enabled) 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0); 66762306a36Sopenharmony_ci if (!err) 66862306a36Sopenharmony_ci zd->mac_enabled = 1; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (zd->monitor) 67162306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return err; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic int zd1201_disable(struct zd1201 *zd) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci int err; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (!zd->mac_enabled) 68162306a36Sopenharmony_ci return 0; 68262306a36Sopenharmony_ci if (zd->monitor) { 68362306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); 68462306a36Sopenharmony_ci if (err) 68562306a36Sopenharmony_ci return err; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0); 68962306a36Sopenharmony_ci if (!err) 69062306a36Sopenharmony_ci zd->mac_enabled = 0; 69162306a36Sopenharmony_ci return err; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int zd1201_mac_reset(struct zd1201 *zd) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci if (!zd->mac_enabled) 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_ci zd1201_disable(zd); 69962306a36Sopenharmony_ci return zd1201_enable(zd); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci int err, val; 70562306a36Sopenharmony_ci char buf[IW_ESSID_MAX_SIZE+2]; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci err = zd1201_disable(zd); 70862306a36Sopenharmony_ci if (err) 70962306a36Sopenharmony_ci return err; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; 71262306a36Sopenharmony_ci val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY; 71362306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val); 71462306a36Sopenharmony_ci if (err) 71562306a36Sopenharmony_ci return err; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci *(__le16 *)buf = cpu_to_le16(essidlen); 71862306a36Sopenharmony_ci memcpy(buf+2, essid, essidlen); 71962306a36Sopenharmony_ci if (!zd->ap) { /* Normal station */ 72062306a36Sopenharmony_ci err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, 72162306a36Sopenharmony_ci IW_ESSID_MAX_SIZE+2, 1); 72262306a36Sopenharmony_ci if (err) 72362306a36Sopenharmony_ci return err; 72462306a36Sopenharmony_ci } else { /* AP */ 72562306a36Sopenharmony_ci err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf, 72662306a36Sopenharmony_ci IW_ESSID_MAX_SIZE+2, 1); 72762306a36Sopenharmony_ci if (err) 72862306a36Sopenharmony_ci return err; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 73262306a36Sopenharmony_ci zd->dev->dev_addr, zd->dev->addr_len, 1); 73362306a36Sopenharmony_ci if (err) 73462306a36Sopenharmony_ci return err; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci err = zd1201_enable(zd); 73762306a36Sopenharmony_ci if (err) 73862306a36Sopenharmony_ci return err; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci msleep(100); 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic int zd1201_net_open(struct net_device *dev) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Start MAC with wildcard if no essid set */ 74962306a36Sopenharmony_ci if (!zd->mac_enabled) 75062306a36Sopenharmony_ci zd1201_join(zd, zd->essid, zd->essidlen); 75162306a36Sopenharmony_ci netif_start_queue(dev); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic int zd1201_net_stop(struct net_device *dev) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci netif_stop_queue(dev); 75962306a36Sopenharmony_ci return 0; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci/* 76362306a36Sopenharmony_ci RFC 1042 encapsulates Ethernet frames in 802.11 frames 76462306a36Sopenharmony_ci by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0 76562306a36Sopenharmony_ci (0x00, 0x00, 0x00). Zd requires an additional padding, copy 76662306a36Sopenharmony_ci of ethernet addresses, length of the standard RFC 1042 packet 76762306a36Sopenharmony_ci and a command byte (which is nul for tx). 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci tx frame (from Wlan NG): 77062306a36Sopenharmony_ci RFC 1042: 77162306a36Sopenharmony_ci llc 0xAA 0xAA 0x03 (802.2 LLC) 77262306a36Sopenharmony_ci snap 0x00 0x00 0x00 (Ethernet encapsulated) 77362306a36Sopenharmony_ci type 2 bytes, Ethernet type field 77462306a36Sopenharmony_ci payload (minus eth header) 77562306a36Sopenharmony_ci Zydas specific: 77662306a36Sopenharmony_ci padding 1B if (skb->len+8+1)%64==0 77762306a36Sopenharmony_ci Eth MAC addr 12 bytes, Ethernet MAC addresses 77862306a36Sopenharmony_ci length 2 bytes, RFC 1042 packet length 77962306a36Sopenharmony_ci (llc+snap+type+payload) 78062306a36Sopenharmony_ci zd 1 null byte, zd1201 packet type 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_cistatic netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, 78362306a36Sopenharmony_ci struct net_device *dev) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 78662306a36Sopenharmony_ci unsigned char *txbuf = zd->txdata; 78762306a36Sopenharmony_ci int txbuflen, pad = 0, err; 78862306a36Sopenharmony_ci struct urb *urb = zd->tx_urb; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (!zd->mac_enabled || zd->monitor) { 79162306a36Sopenharmony_ci dev->stats.tx_dropped++; 79262306a36Sopenharmony_ci kfree_skb(skb); 79362306a36Sopenharmony_ci return NETDEV_TX_OK; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci netif_stop_queue(dev); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci txbuflen = skb->len + 8 + 1; 79862306a36Sopenharmony_ci if (txbuflen%64 == 0) { 79962306a36Sopenharmony_ci pad = 1; 80062306a36Sopenharmony_ci txbuflen++; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci txbuf[0] = 0xAA; 80362306a36Sopenharmony_ci txbuf[1] = 0xAA; 80462306a36Sopenharmony_ci txbuf[2] = 0x03; 80562306a36Sopenharmony_ci txbuf[3] = 0x00; /* rfc1042 */ 80662306a36Sopenharmony_ci txbuf[4] = 0x00; 80762306a36Sopenharmony_ci txbuf[5] = 0x00; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); 81062306a36Sopenharmony_ci if (pad) 81162306a36Sopenharmony_ci txbuf[skb->len-12+6]=0; 81262306a36Sopenharmony_ci skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); 81362306a36Sopenharmony_ci *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); 81462306a36Sopenharmony_ci txbuf[txbuflen-1] = 0; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out), 81762306a36Sopenharmony_ci txbuf, txbuflen, zd1201_usbtx, zd); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC); 82062306a36Sopenharmony_ci if (err) { 82162306a36Sopenharmony_ci dev->stats.tx_errors++; 82262306a36Sopenharmony_ci netif_start_queue(dev); 82362306a36Sopenharmony_ci } else { 82462306a36Sopenharmony_ci dev->stats.tx_packets++; 82562306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci kfree_skb(skb); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return NETDEV_TX_OK; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (!zd) 83762306a36Sopenharmony_ci return; 83862306a36Sopenharmony_ci dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", 83962306a36Sopenharmony_ci dev->name); 84062306a36Sopenharmony_ci usb_unlink_urb(zd->tx_urb); 84162306a36Sopenharmony_ci dev->stats.tx_errors++; 84262306a36Sopenharmony_ci /* Restart the timeout to quiet the watchdog: */ 84362306a36Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int zd1201_set_mac_address(struct net_device *dev, void *p) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct sockaddr *addr = p; 84962306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 85062306a36Sopenharmony_ci int err; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (!zd) 85362306a36Sopenharmony_ci return -ENODEV; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 85662306a36Sopenharmony_ci addr->sa_data, dev->addr_len, 1); 85762306a36Sopenharmony_ci if (err) 85862306a36Sopenharmony_ci return err; 85962306a36Sopenharmony_ci eth_hw_addr_set(dev, addr->sa_data); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return zd1201_mac_reset(zd); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return &zd->iwstats; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic void zd1201_set_multicast(struct net_device *dev) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 87462306a36Sopenharmony_ci struct netdev_hw_addr *ha; 87562306a36Sopenharmony_ci unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; 87662306a36Sopenharmony_ci int i; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci if (netdev_mc_count(dev) > ZD1201_MAXMULTI) 87962306a36Sopenharmony_ci return; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci i = 0; 88262306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) 88362306a36Sopenharmony_ci memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN); 88462306a36Sopenharmony_ci zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, 88562306a36Sopenharmony_ci netdev_mc_count(dev) * ETH_ALEN, 0); 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic int zd1201_config_commit(struct net_device *dev, 88962306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *essid) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return zd1201_mac_reset(zd); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int zd1201_get_name(struct net_device *dev, 89762306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci strcpy(wrqu->name, "IEEE 802.11b"); 90062306a36Sopenharmony_ci return 0; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic int zd1201_set_freq(struct net_device *dev, 90462306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct iw_freq *freq = &wrqu->freq; 90762306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 90862306a36Sopenharmony_ci short channel = 0; 90962306a36Sopenharmony_ci int err; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (freq->e == 0) 91262306a36Sopenharmony_ci channel = freq->m; 91362306a36Sopenharmony_ci else 91462306a36Sopenharmony_ci channel = ieee80211_frequency_to_channel(freq->m); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); 91762306a36Sopenharmony_ci if (err) 91862306a36Sopenharmony_ci return err; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci zd1201_mac_reset(zd); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int zd1201_get_freq(struct net_device *dev, 92662306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct iw_freq *freq = &wrqu->freq; 92962306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 93062306a36Sopenharmony_ci short channel; 93162306a36Sopenharmony_ci int err; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel); 93462306a36Sopenharmony_ci if (err) 93562306a36Sopenharmony_ci return err; 93662306a36Sopenharmony_ci freq->e = 0; 93762306a36Sopenharmony_ci freq->m = channel; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic int zd1201_set_mode(struct net_device *dev, 94362306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci __u32 *mode = &wrqu->mode; 94662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 94762306a36Sopenharmony_ci short porttype, monitor = 0; 94862306a36Sopenharmony_ci unsigned char buffer[IW_ESSID_MAX_SIZE+2]; 94962306a36Sopenharmony_ci int err; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (zd->ap) { 95262306a36Sopenharmony_ci if (*mode != IW_MODE_MASTER) 95362306a36Sopenharmony_ci return -EINVAL; 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); 95862306a36Sopenharmony_ci if (err) 95962306a36Sopenharmony_ci return err; 96062306a36Sopenharmony_ci zd->dev->type = ARPHRD_ETHER; 96162306a36Sopenharmony_ci switch(*mode) { 96262306a36Sopenharmony_ci case IW_MODE_MONITOR: 96362306a36Sopenharmony_ci monitor = 1; 96462306a36Sopenharmony_ci zd->dev->type = ARPHRD_IEEE80211; 96562306a36Sopenharmony_ci /* Make sure we are no longer associated with by 96662306a36Sopenharmony_ci setting an 'impossible' essid. 96762306a36Sopenharmony_ci (otherwise we mess up firmware) 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci zd1201_join(zd, "\0-*#\0", 5); 97062306a36Sopenharmony_ci /* Put port in pIBSS */ 97162306a36Sopenharmony_ci fallthrough; 97262306a36Sopenharmony_ci case 8: /* No pseudo-IBSS in wireless extensions (yet) */ 97362306a36Sopenharmony_ci porttype = ZD1201_PORTTYPE_PSEUDOIBSS; 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci case IW_MODE_ADHOC: 97662306a36Sopenharmony_ci porttype = ZD1201_PORTTYPE_IBSS; 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci case IW_MODE_INFRA: 97962306a36Sopenharmony_ci porttype = ZD1201_PORTTYPE_BSS; 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci default: 98262306a36Sopenharmony_ci return -EINVAL; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); 98662306a36Sopenharmony_ci if (err) 98762306a36Sopenharmony_ci return err; 98862306a36Sopenharmony_ci if (zd->monitor && !monitor) { 98962306a36Sopenharmony_ci zd1201_disable(zd); 99062306a36Sopenharmony_ci *(__le16 *)buffer = cpu_to_le16(zd->essidlen); 99162306a36Sopenharmony_ci memcpy(buffer+2, zd->essid, zd->essidlen); 99262306a36Sopenharmony_ci err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, 99362306a36Sopenharmony_ci buffer, IW_ESSID_MAX_SIZE+2, 1); 99462306a36Sopenharmony_ci if (err) 99562306a36Sopenharmony_ci return err; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci zd->monitor = monitor; 99862306a36Sopenharmony_ci /* If monitor mode is set we don't actually turn it on here since it 99962306a36Sopenharmony_ci * is done during mac reset anyway (see zd1201_mac_enable). 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci zd1201_mac_reset(zd); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return 0; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic int zd1201_get_mode(struct net_device *dev, 100762306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci __u32 *mode = &wrqu->mode; 101062306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 101162306a36Sopenharmony_ci short porttype; 101262306a36Sopenharmony_ci int err; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype); 101562306a36Sopenharmony_ci if (err) 101662306a36Sopenharmony_ci return err; 101762306a36Sopenharmony_ci switch(porttype) { 101862306a36Sopenharmony_ci case ZD1201_PORTTYPE_IBSS: 101962306a36Sopenharmony_ci *mode = IW_MODE_ADHOC; 102062306a36Sopenharmony_ci break; 102162306a36Sopenharmony_ci case ZD1201_PORTTYPE_BSS: 102262306a36Sopenharmony_ci *mode = IW_MODE_INFRA; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci case ZD1201_PORTTYPE_WDS: 102562306a36Sopenharmony_ci *mode = IW_MODE_REPEAT; 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci case ZD1201_PORTTYPE_PSEUDOIBSS: 102862306a36Sopenharmony_ci *mode = 8;/* No Pseudo-IBSS... */ 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci case ZD1201_PORTTYPE_AP: 103162306a36Sopenharmony_ci *mode = IW_MODE_MASTER; 103262306a36Sopenharmony_ci break; 103362306a36Sopenharmony_ci default: 103462306a36Sopenharmony_ci dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n", 103562306a36Sopenharmony_ci porttype); 103662306a36Sopenharmony_ci *mode = IW_MODE_AUTO; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci if (zd->monitor) 103962306a36Sopenharmony_ci *mode = IW_MODE_MONITOR; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci return 0; 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic int zd1201_get_range(struct net_device *dev, 104562306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct iw_point *wrq = &wrqu->data; 104862306a36Sopenharmony_ci struct iw_range *range = (struct iw_range *)extra; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci wrq->length = sizeof(struct iw_range); 105162306a36Sopenharmony_ci memset(range, 0, sizeof(struct iw_range)); 105262306a36Sopenharmony_ci range->we_version_compiled = WIRELESS_EXT; 105362306a36Sopenharmony_ci range->we_version_source = WIRELESS_EXT; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci range->max_qual.qual = 128; 105662306a36Sopenharmony_ci range->max_qual.level = 128; 105762306a36Sopenharmony_ci range->max_qual.noise = 128; 105862306a36Sopenharmony_ci range->max_qual.updated = 7; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci range->encoding_size[0] = 5; 106162306a36Sopenharmony_ci range->encoding_size[1] = 13; 106262306a36Sopenharmony_ci range->num_encoding_sizes = 2; 106362306a36Sopenharmony_ci range->max_encoding_tokens = ZD1201_NUMKEYS; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci range->num_bitrates = 4; 106662306a36Sopenharmony_ci range->bitrate[0] = 1000000; 106762306a36Sopenharmony_ci range->bitrate[1] = 2000000; 106862306a36Sopenharmony_ci range->bitrate[2] = 5500000; 106962306a36Sopenharmony_ci range->bitrate[3] = 11000000; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci range->min_rts = 0; 107262306a36Sopenharmony_ci range->min_frag = ZD1201_FRAGMIN; 107362306a36Sopenharmony_ci range->max_rts = ZD1201_RTSMAX; 107462306a36Sopenharmony_ci range->min_frag = ZD1201_FRAGMAX; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return 0; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/* Little bit of magic here: we only get the quality if we poll 108062306a36Sopenharmony_ci * for it, and we never get an actual request to trigger such 108162306a36Sopenharmony_ci * a poll. Therefore we 'assume' that the user will soon ask for 108262306a36Sopenharmony_ci * the stats after asking the bssid. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_cistatic int zd1201_get_wap(struct net_device *dev, 108562306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct sockaddr *ap_addr = &wrqu->ap_addr; 108862306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 108962306a36Sopenharmony_ci unsigned char buffer[6]; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { 109262306a36Sopenharmony_ci /* Unfortunately the quality and noise reported is useless. 109362306a36Sopenharmony_ci they seem to be accumulators that increase until you 109462306a36Sopenharmony_ci read them, unless we poll on a fixed interval we can't 109562306a36Sopenharmony_ci use them 109662306a36Sopenharmony_ci */ 109762306a36Sopenharmony_ci /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/ 109862306a36Sopenharmony_ci zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]); 109962306a36Sopenharmony_ci /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/ 110062306a36Sopenharmony_ci zd->iwstats.qual.updated = 2; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6); 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic int zd1201_set_scan(struct net_device *dev, 110762306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci /* We do everything in get_scan */ 111062306a36Sopenharmony_ci return 0; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int zd1201_get_scan(struct net_device *dev, 111462306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci struct iw_point *srq = &wrqu->data; 111762306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 111862306a36Sopenharmony_ci int err, i, j, enabled_save; 111962306a36Sopenharmony_ci struct iw_event iwe; 112062306a36Sopenharmony_ci char *cev = extra; 112162306a36Sopenharmony_ci char *end_buf = extra + IW_SCAN_MAX_DATA; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* No scanning in AP mode */ 112462306a36Sopenharmony_ci if (zd->ap) 112562306a36Sopenharmony_ci return -EOPNOTSUPP; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci /* Scan doesn't seem to work if disabled */ 112862306a36Sopenharmony_ci enabled_save = zd->mac_enabled; 112962306a36Sopenharmony_ci zd1201_enable(zd); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci zd->rxdatas = 0; 113262306a36Sopenharmony_ci err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, 113362306a36Sopenharmony_ci ZD1201_INQ_SCANRESULTS, 0, 0); 113462306a36Sopenharmony_ci if (err) 113562306a36Sopenharmony_ci return err; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci wait_event_interruptible(zd->rxdataq, zd->rxdatas); 113862306a36Sopenharmony_ci if (!zd->rxlen) 113962306a36Sopenharmony_ci return -EIO; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS) 114262306a36Sopenharmony_ci return -EIO; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci for(i=8; i<zd->rxlen; i+=62) { 114562306a36Sopenharmony_ci iwe.cmd = SIOCGIWAP; 114662306a36Sopenharmony_ci iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 114762306a36Sopenharmony_ci memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); 114862306a36Sopenharmony_ci cev = iwe_stream_add_event(info, cev, end_buf, 114962306a36Sopenharmony_ci &iwe, IW_EV_ADDR_LEN); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci iwe.cmd = SIOCGIWESSID; 115262306a36Sopenharmony_ci iwe.u.data.length = zd->rxdata[i+16]; 115362306a36Sopenharmony_ci iwe.u.data.flags = 1; 115462306a36Sopenharmony_ci cev = iwe_stream_add_point(info, cev, end_buf, 115562306a36Sopenharmony_ci &iwe, zd->rxdata+i+18); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci iwe.cmd = SIOCGIWMODE; 115862306a36Sopenharmony_ci if (zd->rxdata[i+14]&0x01) 115962306a36Sopenharmony_ci iwe.u.mode = IW_MODE_MASTER; 116062306a36Sopenharmony_ci else 116162306a36Sopenharmony_ci iwe.u.mode = IW_MODE_ADHOC; 116262306a36Sopenharmony_ci cev = iwe_stream_add_event(info, cev, end_buf, 116362306a36Sopenharmony_ci &iwe, IW_EV_UINT_LEN); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci iwe.cmd = SIOCGIWFREQ; 116662306a36Sopenharmony_ci iwe.u.freq.m = zd->rxdata[i+0]; 116762306a36Sopenharmony_ci iwe.u.freq.e = 0; 116862306a36Sopenharmony_ci cev = iwe_stream_add_event(info, cev, end_buf, 116962306a36Sopenharmony_ci &iwe, IW_EV_FREQ_LEN); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci iwe.cmd = SIOCGIWRATE; 117262306a36Sopenharmony_ci iwe.u.bitrate.fixed = 0; 117362306a36Sopenharmony_ci iwe.u.bitrate.disabled = 0; 117462306a36Sopenharmony_ci for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { 117562306a36Sopenharmony_ci iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; 117662306a36Sopenharmony_ci cev = iwe_stream_add_event(info, cev, end_buf, 117762306a36Sopenharmony_ci &iwe, IW_EV_PARAM_LEN); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci iwe.cmd = SIOCGIWENCODE; 118162306a36Sopenharmony_ci iwe.u.data.length = 0; 118262306a36Sopenharmony_ci if (zd->rxdata[i+14]&0x10) 118362306a36Sopenharmony_ci iwe.u.data.flags = IW_ENCODE_ENABLED; 118462306a36Sopenharmony_ci else 118562306a36Sopenharmony_ci iwe.u.data.flags = IW_ENCODE_DISABLED; 118662306a36Sopenharmony_ci cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci iwe.cmd = IWEVQUAL; 118962306a36Sopenharmony_ci iwe.u.qual.qual = zd->rxdata[i+4]; 119062306a36Sopenharmony_ci iwe.u.qual.noise= zd->rxdata[i+2]/10-100; 119162306a36Sopenharmony_ci iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; 119262306a36Sopenharmony_ci iwe.u.qual.updated = 7; 119362306a36Sopenharmony_ci cev = iwe_stream_add_event(info, cev, end_buf, 119462306a36Sopenharmony_ci &iwe, IW_EV_QUAL_LEN); 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (!enabled_save) 119862306a36Sopenharmony_ci zd1201_disable(zd); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci srq->length = cev - extra; 120162306a36Sopenharmony_ci srq->flags = 0; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci return 0; 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic int zd1201_set_essid(struct net_device *dev, 120762306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *essid) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci struct iw_point *data = &wrqu->data; 121062306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (data->length > IW_ESSID_MAX_SIZE) 121362306a36Sopenharmony_ci return -EINVAL; 121462306a36Sopenharmony_ci if (data->length < 1) 121562306a36Sopenharmony_ci data->length = 1; 121662306a36Sopenharmony_ci zd->essidlen = data->length; 121762306a36Sopenharmony_ci memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); 121862306a36Sopenharmony_ci memcpy(zd->essid, essid, data->length); 121962306a36Sopenharmony_ci return zd1201_join(zd, zd->essid, zd->essidlen); 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_cistatic int zd1201_get_essid(struct net_device *dev, 122362306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *essid) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci struct iw_point *data = &wrqu->data; 122662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci memcpy(essid, zd->essid, zd->essidlen); 122962306a36Sopenharmony_ci data->flags = 1; 123062306a36Sopenharmony_ci data->length = zd->essidlen; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci return 0; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, 123662306a36Sopenharmony_ci union iwreq_data *wrqu, char *nick) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct iw_point *data = &wrqu->data; 123962306a36Sopenharmony_ci strcpy(nick, "zd1201"); 124062306a36Sopenharmony_ci data->flags = 1; 124162306a36Sopenharmony_ci data->length = strlen(nick); 124262306a36Sopenharmony_ci return 0; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic int zd1201_set_rate(struct net_device *dev, 124662306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci struct iw_param *rrq = &wrqu->bitrate; 124962306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 125062306a36Sopenharmony_ci short rate; 125162306a36Sopenharmony_ci int err; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci switch (rrq->value) { 125462306a36Sopenharmony_ci case 1000000: 125562306a36Sopenharmony_ci rate = ZD1201_RATEB1; 125662306a36Sopenharmony_ci break; 125762306a36Sopenharmony_ci case 2000000: 125862306a36Sopenharmony_ci rate = ZD1201_RATEB2; 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci case 5500000: 126162306a36Sopenharmony_ci rate = ZD1201_RATEB5; 126262306a36Sopenharmony_ci break; 126362306a36Sopenharmony_ci case 11000000: 126462306a36Sopenharmony_ci default: 126562306a36Sopenharmony_ci rate = ZD1201_RATEB11; 126662306a36Sopenharmony_ci break; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci if (!rrq->fixed) { /* Also enable all lower bitrates */ 126962306a36Sopenharmony_ci rate |= rate-1; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate); 127362306a36Sopenharmony_ci if (err) 127462306a36Sopenharmony_ci return err; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci return zd1201_mac_reset(zd); 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_cistatic int zd1201_get_rate(struct net_device *dev, 128062306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct iw_param *rrq = &wrqu->bitrate; 128362306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 128462306a36Sopenharmony_ci short rate; 128562306a36Sopenharmony_ci int err; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate); 128862306a36Sopenharmony_ci if (err) 128962306a36Sopenharmony_ci return err; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci switch(rate) { 129262306a36Sopenharmony_ci case 1: 129362306a36Sopenharmony_ci rrq->value = 1000000; 129462306a36Sopenharmony_ci break; 129562306a36Sopenharmony_ci case 2: 129662306a36Sopenharmony_ci rrq->value = 2000000; 129762306a36Sopenharmony_ci break; 129862306a36Sopenharmony_ci case 5: 129962306a36Sopenharmony_ci rrq->value = 5500000; 130062306a36Sopenharmony_ci break; 130162306a36Sopenharmony_ci case 11: 130262306a36Sopenharmony_ci rrq->value = 11000000; 130362306a36Sopenharmony_ci break; 130462306a36Sopenharmony_ci default: 130562306a36Sopenharmony_ci rrq->value = 0; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci rrq->fixed = 0; 130862306a36Sopenharmony_ci rrq->disabled = 0; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci return 0; 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, 131462306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci struct iw_param *rts = &wrqu->rts; 131762306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 131862306a36Sopenharmony_ci int err; 131962306a36Sopenharmony_ci short val = rts->value; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (rts->disabled || !rts->fixed) 132262306a36Sopenharmony_ci val = ZD1201_RTSMAX; 132362306a36Sopenharmony_ci if (val > ZD1201_RTSMAX) 132462306a36Sopenharmony_ci return -EINVAL; 132562306a36Sopenharmony_ci if (val < 0) 132662306a36Sopenharmony_ci return -EINVAL; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val); 132962306a36Sopenharmony_ci if (err) 133062306a36Sopenharmony_ci return err; 133162306a36Sopenharmony_ci return zd1201_mac_reset(zd); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, 133562306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct iw_param *rts = &wrqu->rts; 133862306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 133962306a36Sopenharmony_ci short rtst; 134062306a36Sopenharmony_ci int err; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst); 134362306a36Sopenharmony_ci if (err) 134462306a36Sopenharmony_ci return err; 134562306a36Sopenharmony_ci rts->value = rtst; 134662306a36Sopenharmony_ci rts->disabled = (rts->value == ZD1201_RTSMAX); 134762306a36Sopenharmony_ci rts->fixed = 1; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci return 0; 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_cistatic int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, 135362306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci struct iw_param *frag = &wrqu->frag; 135662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 135762306a36Sopenharmony_ci int err; 135862306a36Sopenharmony_ci short val = frag->value; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci if (frag->disabled || !frag->fixed) 136162306a36Sopenharmony_ci val = ZD1201_FRAGMAX; 136262306a36Sopenharmony_ci if (val > ZD1201_FRAGMAX) 136362306a36Sopenharmony_ci return -EINVAL; 136462306a36Sopenharmony_ci if (val < ZD1201_FRAGMIN) 136562306a36Sopenharmony_ci return -EINVAL; 136662306a36Sopenharmony_ci if (val & 1) 136762306a36Sopenharmony_ci return -EINVAL; 136862306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val); 136962306a36Sopenharmony_ci if (err) 137062306a36Sopenharmony_ci return err; 137162306a36Sopenharmony_ci return zd1201_mac_reset(zd); 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cistatic int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, 137562306a36Sopenharmony_ci union iwreq_data *wrqu, char *extra) 137662306a36Sopenharmony_ci{ 137762306a36Sopenharmony_ci struct iw_param *frag = &wrqu->frag; 137862306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 137962306a36Sopenharmony_ci short fragt; 138062306a36Sopenharmony_ci int err; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt); 138362306a36Sopenharmony_ci if (err) 138462306a36Sopenharmony_ci return err; 138562306a36Sopenharmony_ci frag->value = fragt; 138662306a36Sopenharmony_ci frag->disabled = (frag->value == ZD1201_FRAGMAX); 138762306a36Sopenharmony_ci frag->fixed = 1; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci return 0; 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic int zd1201_set_retry(struct net_device *dev, 139362306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 139462306a36Sopenharmony_ci{ 139562306a36Sopenharmony_ci return 0; 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_cistatic int zd1201_get_retry(struct net_device *dev, 139962306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci return 0; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic int zd1201_set_encode(struct net_device *dev, 140562306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *key) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci struct iw_point *erq = &wrqu->encoding; 140862306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 140962306a36Sopenharmony_ci short i; 141062306a36Sopenharmony_ci int err, rid; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (erq->length > ZD1201_MAXKEYLEN) 141362306a36Sopenharmony_ci return -EINVAL; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci i = (erq->flags & IW_ENCODE_INDEX)-1; 141662306a36Sopenharmony_ci if (i == -1) { 141762306a36Sopenharmony_ci err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i); 141862306a36Sopenharmony_ci if (err) 141962306a36Sopenharmony_ci return err; 142062306a36Sopenharmony_ci } else { 142162306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i); 142262306a36Sopenharmony_ci if (err) 142362306a36Sopenharmony_ci return err; 142462306a36Sopenharmony_ci } 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (i < 0 || i >= ZD1201_NUMKEYS) 142762306a36Sopenharmony_ci return -EINVAL; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci rid = ZD1201_RID_CNFDEFAULTKEY0 + i; 143062306a36Sopenharmony_ci err = zd1201_setconfig(zd, rid, key, erq->length, 1); 143162306a36Sopenharmony_ci if (err) 143262306a36Sopenharmony_ci return err; 143362306a36Sopenharmony_ci zd->encode_keylen[i] = erq->length; 143462306a36Sopenharmony_ci memcpy(zd->encode_keys[i], key, erq->length); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci i=0; 143762306a36Sopenharmony_ci if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) { 143862306a36Sopenharmony_ci i |= 0x01; 143962306a36Sopenharmony_ci zd->encode_enabled = 1; 144062306a36Sopenharmony_ci } else 144162306a36Sopenharmony_ci zd->encode_enabled = 0; 144262306a36Sopenharmony_ci if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) { 144362306a36Sopenharmony_ci i |= 0x02; 144462306a36Sopenharmony_ci zd->encode_restricted = 1; 144562306a36Sopenharmony_ci } else 144662306a36Sopenharmony_ci zd->encode_restricted = 0; 144762306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i); 144862306a36Sopenharmony_ci if (err) 144962306a36Sopenharmony_ci return err; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci if (zd->encode_enabled) 145262306a36Sopenharmony_ci i = ZD1201_CNFAUTHENTICATION_SHAREDKEY; 145362306a36Sopenharmony_ci else 145462306a36Sopenharmony_ci i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; 145562306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i); 145662306a36Sopenharmony_ci if (err) 145762306a36Sopenharmony_ci return err; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci return zd1201_mac_reset(zd); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic int zd1201_get_encode(struct net_device *dev, 146362306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *key) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci struct iw_point *erq = &wrqu->encoding; 146662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 146762306a36Sopenharmony_ci short i; 146862306a36Sopenharmony_ci int err; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (zd->encode_enabled) 147162306a36Sopenharmony_ci erq->flags = IW_ENCODE_ENABLED; 147262306a36Sopenharmony_ci else 147362306a36Sopenharmony_ci erq->flags = IW_ENCODE_DISABLED; 147462306a36Sopenharmony_ci if (zd->encode_restricted) 147562306a36Sopenharmony_ci erq->flags |= IW_ENCODE_RESTRICTED; 147662306a36Sopenharmony_ci else 147762306a36Sopenharmony_ci erq->flags |= IW_ENCODE_OPEN; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci i = (erq->flags & IW_ENCODE_INDEX) -1; 148062306a36Sopenharmony_ci if (i == -1) { 148162306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i); 148262306a36Sopenharmony_ci if (err) 148362306a36Sopenharmony_ci return err; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci if (i<0 || i>= ZD1201_NUMKEYS) 148662306a36Sopenharmony_ci return -EINVAL; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci erq->flags |= i+1; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci erq->length = zd->encode_keylen[i]; 149162306a36Sopenharmony_ci memcpy(key, zd->encode_keys[i], erq->length); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci return 0; 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int zd1201_set_power(struct net_device *dev, 149762306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci struct iw_param *vwrq = &wrqu->power; 150062306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 150162306a36Sopenharmony_ci short enabled, duration, level; 150262306a36Sopenharmony_ci int err; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci enabled = vwrq->disabled ? 0 : 1; 150562306a36Sopenharmony_ci if (enabled) { 150662306a36Sopenharmony_ci if (vwrq->flags & IW_POWER_PERIOD) { 150762306a36Sopenharmony_ci duration = vwrq->value; 150862306a36Sopenharmony_ci err = zd1201_setconfig16(zd, 150962306a36Sopenharmony_ci ZD1201_RID_CNFMAXSLEEPDURATION, duration); 151062306a36Sopenharmony_ci if (err) 151162306a36Sopenharmony_ci return err; 151262306a36Sopenharmony_ci goto out; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci if (vwrq->flags & IW_POWER_TIMEOUT) { 151562306a36Sopenharmony_ci err = zd1201_getconfig16(zd, 151662306a36Sopenharmony_ci ZD1201_RID_CNFMAXSLEEPDURATION, &duration); 151762306a36Sopenharmony_ci if (err) 151862306a36Sopenharmony_ci return err; 151962306a36Sopenharmony_ci level = vwrq->value * 4 / duration; 152062306a36Sopenharmony_ci if (level > 4) 152162306a36Sopenharmony_ci level = 4; 152262306a36Sopenharmony_ci if (level < 0) 152362306a36Sopenharmony_ci level = 0; 152462306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS, 152562306a36Sopenharmony_ci level); 152662306a36Sopenharmony_ci if (err) 152762306a36Sopenharmony_ci return err; 152862306a36Sopenharmony_ci goto out; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci return -EINVAL; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ciout: 153362306a36Sopenharmony_ci return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled); 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic int zd1201_get_power(struct net_device *dev, 153762306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci struct iw_param *vwrq = &wrqu->power; 154062306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 154162306a36Sopenharmony_ci short enabled, level, duration; 154262306a36Sopenharmony_ci int err; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled); 154562306a36Sopenharmony_ci if (err) 154662306a36Sopenharmony_ci return err; 154762306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level); 154862306a36Sopenharmony_ci if (err) 154962306a36Sopenharmony_ci return err; 155062306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration); 155162306a36Sopenharmony_ci if (err) 155262306a36Sopenharmony_ci return err; 155362306a36Sopenharmony_ci vwrq->disabled = enabled ? 0 : 1; 155462306a36Sopenharmony_ci if (vwrq->flags & IW_POWER_TYPE) { 155562306a36Sopenharmony_ci if (vwrq->flags & IW_POWER_PERIOD) { 155662306a36Sopenharmony_ci vwrq->value = duration; 155762306a36Sopenharmony_ci vwrq->flags = IW_POWER_PERIOD; 155862306a36Sopenharmony_ci } else { 155962306a36Sopenharmony_ci vwrq->value = duration * level / 4; 156062306a36Sopenharmony_ci vwrq->flags = IW_POWER_TIMEOUT; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci if (vwrq->flags & IW_POWER_MODE) { 156462306a36Sopenharmony_ci if (enabled && level) 156562306a36Sopenharmony_ci vwrq->flags = IW_POWER_UNICAST_R; 156662306a36Sopenharmony_ci else 156762306a36Sopenharmony_ci vwrq->flags = IW_POWER_ALL_R; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci return 0; 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_cistatic const iw_handler zd1201_iw_handler[] = 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit), 157762306a36Sopenharmony_ci IW_HANDLER(SIOCGIWNAME, zd1201_get_name), 157862306a36Sopenharmony_ci IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq), 157962306a36Sopenharmony_ci IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq), 158062306a36Sopenharmony_ci IW_HANDLER(SIOCSIWMODE, zd1201_set_mode), 158162306a36Sopenharmony_ci IW_HANDLER(SIOCGIWMODE, zd1201_get_mode), 158262306a36Sopenharmony_ci IW_HANDLER(SIOCGIWRANGE, zd1201_get_range), 158362306a36Sopenharmony_ci IW_HANDLER(SIOCGIWAP, zd1201_get_wap), 158462306a36Sopenharmony_ci IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan), 158562306a36Sopenharmony_ci IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan), 158662306a36Sopenharmony_ci IW_HANDLER(SIOCSIWESSID, zd1201_set_essid), 158762306a36Sopenharmony_ci IW_HANDLER(SIOCGIWESSID, zd1201_get_essid), 158862306a36Sopenharmony_ci IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick), 158962306a36Sopenharmony_ci IW_HANDLER(SIOCSIWRATE, zd1201_set_rate), 159062306a36Sopenharmony_ci IW_HANDLER(SIOCGIWRATE, zd1201_get_rate), 159162306a36Sopenharmony_ci IW_HANDLER(SIOCSIWRTS, zd1201_set_rts), 159262306a36Sopenharmony_ci IW_HANDLER(SIOCGIWRTS, zd1201_get_rts), 159362306a36Sopenharmony_ci IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag), 159462306a36Sopenharmony_ci IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag), 159562306a36Sopenharmony_ci IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry), 159662306a36Sopenharmony_ci IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry), 159762306a36Sopenharmony_ci IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode), 159862306a36Sopenharmony_ci IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode), 159962306a36Sopenharmony_ci IW_HANDLER(SIOCSIWPOWER, zd1201_set_power), 160062306a36Sopenharmony_ci IW_HANDLER(SIOCGIWPOWER, zd1201_get_power), 160162306a36Sopenharmony_ci}; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic int zd1201_set_hostauth(struct net_device *dev, 160462306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci struct iw_param *rrq = &wrqu->param; 160762306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci if (!zd->ap) 161062306a36Sopenharmony_ci return -EOPNOTSUPP; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value); 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistatic int zd1201_get_hostauth(struct net_device *dev, 161662306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 161762306a36Sopenharmony_ci{ 161862306a36Sopenharmony_ci struct iw_param *rrq = &wrqu->param; 161962306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 162062306a36Sopenharmony_ci short hostauth; 162162306a36Sopenharmony_ci int err; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (!zd->ap) 162462306a36Sopenharmony_ci return -EOPNOTSUPP; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth); 162762306a36Sopenharmony_ci if (err) 162862306a36Sopenharmony_ci return err; 162962306a36Sopenharmony_ci rrq->value = hostauth; 163062306a36Sopenharmony_ci rrq->fixed = 1; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci return 0; 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic int zd1201_auth_sta(struct net_device *dev, 163662306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 163762306a36Sopenharmony_ci{ 163862306a36Sopenharmony_ci struct sockaddr *sta = &wrqu->ap_addr; 163962306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 164062306a36Sopenharmony_ci unsigned char buffer[10]; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (!zd->ap) 164362306a36Sopenharmony_ci return -EOPNOTSUPP; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci memcpy(buffer, sta->sa_data, ETH_ALEN); 164662306a36Sopenharmony_ci *(short*)(buffer+6) = 0; /* 0==success, 1==failure */ 164762306a36Sopenharmony_ci *(short*)(buffer+8) = 0; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1); 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic int zd1201_set_maxassoc(struct net_device *dev, 165362306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci struct iw_param *rrq = &wrqu->param; 165662306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci if (!zd->ap) 165962306a36Sopenharmony_ci return -EOPNOTSUPP; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value); 166262306a36Sopenharmony_ci} 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_cistatic int zd1201_get_maxassoc(struct net_device *dev, 166562306a36Sopenharmony_ci struct iw_request_info *info, union iwreq_data *wrqu, char *extra) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct iw_param *rrq = &wrqu->param; 166862306a36Sopenharmony_ci struct zd1201 *zd = netdev_priv(dev); 166962306a36Sopenharmony_ci short maxassoc; 167062306a36Sopenharmony_ci int err; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (!zd->ap) 167362306a36Sopenharmony_ci return -EOPNOTSUPP; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc); 167662306a36Sopenharmony_ci if (err) 167762306a36Sopenharmony_ci return err; 167862306a36Sopenharmony_ci rrq->value = maxassoc; 167962306a36Sopenharmony_ci rrq->fixed = 1; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci return 0; 168262306a36Sopenharmony_ci} 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_cistatic const iw_handler zd1201_private_handler[] = { 168562306a36Sopenharmony_ci zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */ 168662306a36Sopenharmony_ci zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */ 168762306a36Sopenharmony_ci zd1201_auth_sta, /* ZD1201SIWAUTHSTA */ 168862306a36Sopenharmony_ci NULL, /* nothing to get */ 168962306a36Sopenharmony_ci zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */ 169062306a36Sopenharmony_ci zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */ 169162306a36Sopenharmony_ci}; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic const struct iw_priv_args zd1201_private_args[] = { 169462306a36Sopenharmony_ci { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 169562306a36Sopenharmony_ci IW_PRIV_TYPE_NONE, "sethostauth" }, 169662306a36Sopenharmony_ci { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE, 169762306a36Sopenharmony_ci IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" }, 169862306a36Sopenharmony_ci { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 169962306a36Sopenharmony_ci IW_PRIV_TYPE_NONE, "authstation" }, 170062306a36Sopenharmony_ci { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 170162306a36Sopenharmony_ci IW_PRIV_TYPE_NONE, "setmaxassoc" }, 170262306a36Sopenharmony_ci { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE, 170362306a36Sopenharmony_ci IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" }, 170462306a36Sopenharmony_ci}; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_cistatic const struct iw_handler_def zd1201_iw_handlers = { 170762306a36Sopenharmony_ci .num_standard = ARRAY_SIZE(zd1201_iw_handler), 170862306a36Sopenharmony_ci .num_private = ARRAY_SIZE(zd1201_private_handler), 170962306a36Sopenharmony_ci .num_private_args = ARRAY_SIZE(zd1201_private_args), 171062306a36Sopenharmony_ci .standard = zd1201_iw_handler, 171162306a36Sopenharmony_ci .private = zd1201_private_handler, 171262306a36Sopenharmony_ci .private_args = (struct iw_priv_args *) zd1201_private_args, 171362306a36Sopenharmony_ci .get_wireless_stats = zd1201_get_wireless_stats, 171462306a36Sopenharmony_ci}; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_cistatic const struct net_device_ops zd1201_netdev_ops = { 171762306a36Sopenharmony_ci .ndo_open = zd1201_net_open, 171862306a36Sopenharmony_ci .ndo_stop = zd1201_net_stop, 171962306a36Sopenharmony_ci .ndo_start_xmit = zd1201_hard_start_xmit, 172062306a36Sopenharmony_ci .ndo_tx_timeout = zd1201_tx_timeout, 172162306a36Sopenharmony_ci .ndo_set_rx_mode = zd1201_set_multicast, 172262306a36Sopenharmony_ci .ndo_set_mac_address = zd1201_set_mac_address, 172362306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 172462306a36Sopenharmony_ci}; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_cistatic int zd1201_probe(struct usb_interface *interface, 172762306a36Sopenharmony_ci const struct usb_device_id *id) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci struct zd1201 *zd; 173062306a36Sopenharmony_ci struct net_device *dev; 173162306a36Sopenharmony_ci struct usb_device *usb; 173262306a36Sopenharmony_ci int err; 173362306a36Sopenharmony_ci short porttype; 173462306a36Sopenharmony_ci char buf[IW_ESSID_MAX_SIZE+2]; 173562306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci usb = interface_to_usbdev(interface); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(*zd)); 174062306a36Sopenharmony_ci if (!dev) 174162306a36Sopenharmony_ci return -ENOMEM; 174262306a36Sopenharmony_ci zd = netdev_priv(dev); 174362306a36Sopenharmony_ci zd->dev = dev; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci zd->ap = ap; 174662306a36Sopenharmony_ci zd->usb = usb; 174762306a36Sopenharmony_ci zd->removed = 0; 174862306a36Sopenharmony_ci init_waitqueue_head(&zd->rxdataq); 174962306a36Sopenharmony_ci INIT_HLIST_HEAD(&zd->fraglist); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci err = zd1201_fw_upload(usb, zd->ap); 175262306a36Sopenharmony_ci if (err) { 175362306a36Sopenharmony_ci dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err); 175462306a36Sopenharmony_ci goto err_zd; 175562306a36Sopenharmony_ci } 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci zd->endp_in = 1; 175862306a36Sopenharmony_ci zd->endp_out = 1; 175962306a36Sopenharmony_ci zd->endp_out2 = 2; 176062306a36Sopenharmony_ci zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 176162306a36Sopenharmony_ci zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 176262306a36Sopenharmony_ci if (!zd->rx_urb || !zd->tx_urb) { 176362306a36Sopenharmony_ci err = -ENOMEM; 176462306a36Sopenharmony_ci goto err_zd; 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci mdelay(100); 176862306a36Sopenharmony_ci err = zd1201_drvr_start(zd); 176962306a36Sopenharmony_ci if (err) 177062306a36Sopenharmony_ci goto err_zd; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312); 177362306a36Sopenharmony_ci if (err) 177462306a36Sopenharmony_ci goto err_start; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, 177762306a36Sopenharmony_ci ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11); 177862306a36Sopenharmony_ci if (err) 177962306a36Sopenharmony_ci goto err_start; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci dev->netdev_ops = &zd1201_netdev_ops; 178262306a36Sopenharmony_ci dev->wireless_handlers = &zd1201_iw_handlers; 178362306a36Sopenharmony_ci dev->watchdog_timeo = ZD1201_TX_TIMEOUT; 178462306a36Sopenharmony_ci strcpy(dev->name, "wlan%d"); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN); 178762306a36Sopenharmony_ci if (err) 178862306a36Sopenharmony_ci goto err_start; 178962306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci /* Set wildcard essid to match zd->essid */ 179262306a36Sopenharmony_ci *(__le16 *)buf = cpu_to_le16(0); 179362306a36Sopenharmony_ci err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, 179462306a36Sopenharmony_ci IW_ESSID_MAX_SIZE+2, 1); 179562306a36Sopenharmony_ci if (err) 179662306a36Sopenharmony_ci goto err_start; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (zd->ap) 179962306a36Sopenharmony_ci porttype = ZD1201_PORTTYPE_AP; 180062306a36Sopenharmony_ci else 180162306a36Sopenharmony_ci porttype = ZD1201_PORTTYPE_BSS; 180262306a36Sopenharmony_ci err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); 180362306a36Sopenharmony_ci if (err) 180462306a36Sopenharmony_ci goto err_start; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &usb->dev); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci err = register_netdev(dev); 180962306a36Sopenharmony_ci if (err) 181062306a36Sopenharmony_ci goto err_start; 181162306a36Sopenharmony_ci dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", 181262306a36Sopenharmony_ci dev->name); 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci usb_set_intfdata(interface, zd); 181562306a36Sopenharmony_ci zd1201_enable(zd); /* zd1201 likes to startup enabled, */ 181662306a36Sopenharmony_ci zd1201_disable(zd); /* interfering with all the wifis in range */ 181762306a36Sopenharmony_ci return 0; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_cierr_start: 182062306a36Sopenharmony_ci /* Leave the device in reset state */ 182162306a36Sopenharmony_ci zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); 182262306a36Sopenharmony_cierr_zd: 182362306a36Sopenharmony_ci usb_free_urb(zd->tx_urb); 182462306a36Sopenharmony_ci usb_free_urb(zd->rx_urb); 182562306a36Sopenharmony_ci free_netdev(dev); 182662306a36Sopenharmony_ci return err; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cistatic void zd1201_disconnect(struct usb_interface *interface) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct zd1201 *zd = usb_get_intfdata(interface); 183262306a36Sopenharmony_ci struct hlist_node *node2; 183362306a36Sopenharmony_ci struct zd1201_frag *frag; 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (!zd) 183662306a36Sopenharmony_ci return; 183762306a36Sopenharmony_ci usb_set_intfdata(interface, NULL); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) { 184062306a36Sopenharmony_ci hlist_del_init(&frag->fnode); 184162306a36Sopenharmony_ci kfree_skb(frag->skb); 184262306a36Sopenharmony_ci kfree(frag); 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (zd->tx_urb) { 184662306a36Sopenharmony_ci usb_kill_urb(zd->tx_urb); 184762306a36Sopenharmony_ci usb_free_urb(zd->tx_urb); 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci if (zd->rx_urb) { 185062306a36Sopenharmony_ci usb_kill_urb(zd->rx_urb); 185162306a36Sopenharmony_ci usb_free_urb(zd->rx_urb); 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (zd->dev) { 185562306a36Sopenharmony_ci unregister_netdev(zd->dev); 185662306a36Sopenharmony_ci free_netdev(zd->dev); 185762306a36Sopenharmony_ci } 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci#ifdef CONFIG_PM 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_cistatic int zd1201_suspend(struct usb_interface *interface, 186362306a36Sopenharmony_ci pm_message_t message) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci struct zd1201 *zd = usb_get_intfdata(interface); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci netif_device_detach(zd->dev); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci zd->was_enabled = zd->mac_enabled; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci if (zd->was_enabled) 187262306a36Sopenharmony_ci return zd1201_disable(zd); 187362306a36Sopenharmony_ci else 187462306a36Sopenharmony_ci return 0; 187562306a36Sopenharmony_ci} 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cistatic int zd1201_resume(struct usb_interface *interface) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci struct zd1201 *zd = usb_get_intfdata(interface); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci if (!zd || !zd->dev) 188262306a36Sopenharmony_ci return -ENODEV; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci netif_device_attach(zd->dev); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci if (zd->was_enabled) 188762306a36Sopenharmony_ci return zd1201_enable(zd); 188862306a36Sopenharmony_ci else 188962306a36Sopenharmony_ci return 0; 189062306a36Sopenharmony_ci} 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci#else 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci#define zd1201_suspend NULL 189562306a36Sopenharmony_ci#define zd1201_resume NULL 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci#endif 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_cistatic struct usb_driver zd1201_usb = { 190062306a36Sopenharmony_ci .name = "zd1201", 190162306a36Sopenharmony_ci .probe = zd1201_probe, 190262306a36Sopenharmony_ci .disconnect = zd1201_disconnect, 190362306a36Sopenharmony_ci .id_table = zd1201_table, 190462306a36Sopenharmony_ci .suspend = zd1201_suspend, 190562306a36Sopenharmony_ci .resume = zd1201_resume, 190662306a36Sopenharmony_ci .disable_hub_initiated_lpm = 1, 190762306a36Sopenharmony_ci}; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_cimodule_usb_driver(zd1201_usb); 1910