From patchwork Mon Oct 23 13:19:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 13432846 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0ED75C00A8F for ; Mon, 23 Oct 2023 13:20:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=qWGLO1Z60NgiOGACI+6uhKnOzvVHT0P4MM7OzGJlc6I=; b=F6hcORILs010aC E8atnEiAkhSrZOyXnz7sHjnUpeBky2s3dUGWhkz/QINSGyPxOh+EWOMkplGWDC4oc482hGamJVGkK joAHh5bSmR+e1zt7cMNVWwDo5DIe4VyHwk/kZfRzBZStBJKYRpk1KvODbWLXRQm/iJLHIsc4OJzGB Rm0Q0nn6C3bwYvJ/9ZLv11rMlVSOfVH+vD27qRdxIwdZV6I6dMUv4m8710ngN9wxW6XTRQM0Lq+IL vtd+FcloUJvVFNuci//9rPo/IrYo0+ww6iOXtpCwzHxDqVNbH2TUrokPrlxrIyHfs/3u0vbNgT4t2 XkB3423Z7yl9nP32TSww==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1quur6-007QDp-33; Mon, 23 Oct 2023 13:20:28 +0000 Received: from dfw.source.kernel.org ([139.178.84.217]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1quur0-007QBw-2M for linux-arm-kernel@lists.infradead.org; Mon, 23 Oct 2023 13:20:26 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 00A126250A; Mon, 23 Oct 2023 13:20:21 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2A9DAC433CB; Mon, 23 Oct 2023 13:20:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698067220; bh=1uQ3UftdNupi6GUCKesLQ+YGYpGJU/qknE1j++WyrxM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bO1s2x5VfooPhrxLEwameiNn7g4M+tqgaujfL3cIgQXaUI1GK3BtN/qmxeh9S6gO+ 9bJSZfGRZCZGOMNKIuJccflxlFNxIsVxLdp5wLYbo1I2IYF4IdWvnQJcCg4QKBZGKJ 5OiGFqJGCtPN5t3c+z1vHNs7QFrgXk6yJdU5CMOH4c9cfvD3t8yz/0K2ZVgLSdJMWb 43Aiq4m4RxtpPCp2i/NGjxlzYHo1OBkCo42McMPlRXDQ+Hjv+qesshpSSAgvmupSo7 rqTdXHI74HgEz9jgR0M+Ylh62S93YEo7b8cHfdv2vIMPQmyUqrNHLa1bHapUoICG6O ZnnMjqFCvFT1w== From: Arnd Bergmann To: Kalle Valo Subject: [PATCH 01/10] wifi: libertas: drop 16-bit PCMCIA support Date: Mon, 23 Oct 2023 15:19:43 +0200 Message-Id: <20231023131953.2876682-2-arnd@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231023131953.2876682-1-arnd@kernel.org> References: <20231023131953.2876682-1-arnd@kernel.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231023_062022_863496_9D23DE05 X-CRM114-Status: GOOD ( 35.94 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stanislaw Gruszka , Alexandre Belloni , linux-staging@lists.linux.dev, linux-kernel@vger.kernel.org, Arnd Bergmann , Geoff Levand , Greg Kroah-Hartman , linuxppc-dev , linux-wireless@vger.kernel.org, Claudiu Beznea , Geert Uytterhoeven , Pavel Machek , Gregory Greenman , Jakub Kicinski , Johannes Berg , Jeff Johnson , "David S . Miller" , linux-arm-kernel@lists.infradead.org, Larry Finger Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Arnd Bergmann With all the other PCMCIA WLAN adapters gone from the kernel, this is now the last remaining device with this interface, but as far as I can tell, all the actual libertas users were actually using either SDIO or USB. Signed-off-by: Arnd Bergmann --- drivers/net/wireless/marvell/libertas/Kconfig | 7 +- .../net/wireless/marvell/libertas/Makefile | 1 - drivers/net/wireless/marvell/libertas/if_cs.c | 957 ------------------ 3 files changed, 1 insertion(+), 964 deletions(-) delete mode 100644 drivers/net/wireless/marvell/libertas/if_cs.c diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 6d62ab49aa8d4..5bc92cb6b0fed 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" + depends on USB || SDIO || SPI depends on CFG80211 select WIRELESS_EXT select WEXT_SPY @@ -15,12 +16,6 @@ config LIBERTAS_USB help A driver for Marvell Libertas 8388 USB devices. -config LIBERTAS_CS - tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP - help - A driver for Marvell Libertas 8385 CompactFlash devices. - config LIBERTAS_SDIO tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" depends on LIBERTAS && MMC diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile index 41b9b440a5422..2ac04f4d61a52 100644 --- a/drivers/net/wireless/marvell/libertas/Makefile +++ b/drivers/net/wireless/marvell/libertas/Makefile @@ -17,6 +17,5 @@ libertas_spi-objs += if_spi.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o -obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c deleted file mode 100644 index 4103f15bca6bf..0000000000000 --- a/drivers/net/wireless/marvell/libertas/if_cs.c +++ /dev/null @@ -1,957 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - - Driver for the Marvell 8385 based compact flash WLAN cards. - - (C) 2007 by Holger Schurig - - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define DRV_NAME "libertas_cs" - -#include "decl.h" -#include "defs.h" -#include "dev.h" - - -/********************************************************************/ -/* Module stuff */ -/********************************************************************/ - -MODULE_AUTHOR("Holger Schurig "); -MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards"); -MODULE_LICENSE("GPL"); - - - -/********************************************************************/ -/* Data structures */ -/********************************************************************/ - -struct if_cs_card { - struct pcmcia_device *p_dev; - struct lbs_private *priv; - void __iomem *iobase; - bool align_regs; - u32 model; -}; - - -enum { - MODEL_UNKNOWN = 0x00, - MODEL_8305 = 0x01, - MODEL_8381 = 0x02, - MODEL_8385 = 0x03 -}; - -static const struct lbs_fw_table fw_table[] = { - { MODEL_8305, "libertas/cf8305.bin", NULL }, - { MODEL_8305, "libertas_cs_helper.fw", NULL }, - { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" }, - { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" }, - { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" }, - { 0, NULL, NULL } -}; -MODULE_FIRMWARE("libertas/cf8305.bin"); -MODULE_FIRMWARE("libertas/cf8381_helper.bin"); -MODULE_FIRMWARE("libertas/cf8381.bin"); -MODULE_FIRMWARE("libertas/cf8385_helper.bin"); -MODULE_FIRMWARE("libertas/cf8385.bin"); -MODULE_FIRMWARE("libertas_cs_helper.fw"); -MODULE_FIRMWARE("libertas_cs.fw"); - - -/********************************************************************/ -/* Hardware access */ -/********************************************************************/ - -/* This define enables wrapper functions which allow you - to dump all register accesses. You normally won't this, - except for development */ -/* #define DEBUG_IO */ - -#ifdef DEBUG_IO -static int debug_output = 0; -#else -/* This way the compiler optimizes the printk's away */ -#define debug_output 0 -#endif - -static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread8(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inb %08x<%02x\n", reg, val); - return val; -} -static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) -{ - unsigned int val = ioread16(card->iobase + reg); - if (debug_output) - printk(KERN_INFO "inw %08x<%04x\n", reg, val); - return val; -} -static inline void if_cs_read16_rep( - struct if_cs_card *card, - uint reg, - void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "insw %08x<(0x%lx words)\n", - reg, count); - ioread16_rep(card->iobase + reg, buf, count); -} - -static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) -{ - if (debug_output) - printk(KERN_INFO "outb %08x>%02x\n", reg, val); - iowrite8(val, card->iobase + reg); -} - -static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) -{ - if (debug_output) - printk(KERN_INFO "outw %08x>%04x\n", reg, val); - iowrite16(val, card->iobase + reg); -} - -static inline void if_cs_write16_rep( - struct if_cs_card *card, - uint reg, - const void *buf, - unsigned long count) -{ - if (debug_output) - printk(KERN_INFO "outsw %08x>(0x%lx words)\n", - reg, count); - iowrite16_rep(card->iobase + reg, buf, count); -} - - -/* - * I know that polling/delaying is frowned upon. However, this procedure - * with polling is needed while downloading the firmware. At this stage, - * the hardware does unfortunately not create any interrupts. - * - * Fortunately, this function is never used once the firmware is in - * the card. :-) - * - * As a reference, see the "Firmware Specification v5.1", page 18 - * and 19. I did not follow their suggested timing to the word, - * but this works nice & fast anyway. - */ -static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg) -{ - int i; - - for (i = 0; i < 100000; i++) { - u8 val = if_cs_read8(card, addr); - if (val == reg) - return 0; - udelay(5); - } - return -ETIME; -} - - - -/* - * First the bitmasks for the host/card interrupt/status registers: - */ -#define IF_CS_BIT_TX 0x0001 -#define IF_CS_BIT_RX 0x0002 -#define IF_CS_BIT_COMMAND 0x0004 -#define IF_CS_BIT_RESP 0x0008 -#define IF_CS_BIT_EVENT 0x0010 -#define IF_CS_BIT_MASK 0x001f - - - -/* - * It's not really clear to me what the host status register is for. It - * needs to be set almost in union with "host int cause". The following - * bits from above are used: - * - * IF_CS_BIT_TX driver downloaded a data packet - * IF_CS_BIT_RX driver got a data packet - * IF_CS_BIT_COMMAND driver downloaded a command - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT driver read a host event - */ -#define IF_CS_HOST_STATUS 0x00000000 - -/* - * With the host int cause register can the host (that is, Linux) cause - * an interrupt in the firmware, to tell the firmware about those events: - * - * IF_CS_BIT_TX a data packet has been downloaded - * IF_CS_BIT_RX a received data packet has retrieved - * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded - * IF_CS_BIT_RESP not used (has some meaning with powerdown) - * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved - */ -#define IF_CS_HOST_INT_CAUSE 0x00000002 - -/* - * The host int mask register is used to enable/disable interrupt. However, - * I have the suspicion that disabled interrupts are lost. - */ -#define IF_CS_HOST_INT_MASK 0x00000004 - -/* - * Used to send or receive data packets: - */ -#define IF_CS_WRITE 0x00000016 -#define IF_CS_WRITE_LEN 0x00000014 -#define IF_CS_READ 0x00000010 -#define IF_CS_READ_LEN 0x00000024 - -/* - * Used to send commands (and to send firmware block) and to - * receive command responses: - */ -#define IF_CS_CMD 0x0000001A -#define IF_CS_CMD_LEN 0x00000018 -#define IF_CS_RESP 0x00000012 -#define IF_CS_RESP_LEN 0x00000030 - -/* - * The card status registers shows what the card/firmware actually - * accepts: - * - * IF_CS_BIT_TX you may send a data packet - * IF_CS_BIT_RX you may retrieve a data packet - * IF_CS_BIT_COMMAND you may send a command - * IF_CS_BIT_RESP you may retrieve a command response - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - * - * When reading this register several times, you will get back the same - * results --- with one exception: the IF_CS_BIT_EVENT clear itself - * automatically. - * - * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because - * we handle this via the card int cause register. - */ -#define IF_CS_CARD_STATUS 0x00000020 -#define IF_CS_CARD_STATUS_MASK 0x7f00 - -/* - * The card int cause register is used by the card/firmware to notify us - * about the following events: - * - * IF_CS_BIT_TX a data packet has successfully been sentx - * IF_CS_BIT_RX a data packet has been received and can be retrieved - * IF_CS_BIT_COMMAND not used - * IF_CS_BIT_RESP the firmware has a command response for us - * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc) - */ -#define IF_CS_CARD_INT_CAUSE 0x00000022 - -/* - * This is used to for handshaking with the card's bootloader/helper image - * to synchronize downloading of firmware blocks. - */ -#define IF_CS_SQ_READ_LOW 0x00000028 -#define IF_CS_SQ_HELPER_OK 0x10 - -/* - * The scratch register tells us ... - * - * IF_CS_SCRATCH_BOOT_OK the bootloader runs - * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs - */ -#define IF_CS_SCRATCH 0x0000003F -#define IF_CS_SCRATCH_BOOT_OK 0x00 -#define IF_CS_SCRATCH_HELPER_OK 0x5a - -/* - * Used to detect ancient chips: - */ -#define IF_CS_PRODUCT_ID 0x0000001C -#define IF_CS_CF8385_B1_REV 0x12 -#define IF_CS_CF8381_B3_REV 0x04 -#define IF_CS_CF8305_B1_REV 0x03 - -/* - * Used to detect other cards than CF8385 since their revisions of silicon - * doesn't match those from CF8385, eg. CF8381 B3 works with this driver. - */ -#define CF8305_MANFID 0x02db -#define CF8305_CARDID 0x8103 -#define CF8381_MANFID 0x02db -#define CF8381_CARDID 0x6064 -#define CF8385_MANFID 0x02df -#define CF8385_CARDID 0x8103 - -/* - * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when - * that gets fixed. Currently there's no way to access it from the probe hook. - */ -static inline u32 get_model(u16 manf_id, u16 card_id) -{ - /* NOTE: keep in sync with if_cs_ids */ - if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID) - return MODEL_8305; - else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID) - return MODEL_8381; - else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID) - return MODEL_8385; - return MODEL_UNKNOWN; -} - -/********************************************************************/ -/* I/O and interrupt handling */ -/********************************************************************/ - -static inline void if_cs_enable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); -} - -static inline void if_cs_disable_ints(struct if_cs_card *card) -{ - if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK); -} - -/* - * Called from if_cs_host_to_card to send a command to the hardware - */ -static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - int ret = -1; - int loops = 0; - - if_cs_disable_ints(card); - - /* Is hardware ready? */ - while (1) { - u16 status = if_cs_read16(card, IF_CS_CARD_STATUS); - if (status & IF_CS_BIT_COMMAND) - break; - if (++loops > 100) { - netdev_err(priv->dev, "card not ready for commands\n"); - goto done; - } - mdelay(1); - } - - if_cs_write16(card, IF_CS_CMD_LEN, nb); - - if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2); - /* Are we supposed to transfer an odd amount of bytes? */ - if (nb & 1) - if_cs_write8(card, IF_CS_CMD, buf[nb-1]); - - /* "Assert the download over interrupt command in the Host - * status register" */ - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - ret = 0; - -done: - if_cs_enable_ints(card); - return ret; -} - -/* - * Called from if_cs_host_to_card to send a data to the hardware - */ -static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) -{ - struct if_cs_card *card = (struct if_cs_card *)priv->card; - u16 status; - - if_cs_disable_ints(card); - - status = if_cs_read16(card, IF_CS_CARD_STATUS); - BUG_ON((status & IF_CS_BIT_TX) == 0); - - if_cs_write16(card, IF_CS_WRITE_LEN, nb); - - /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2); - if (nb & 1) - if_cs_write8(card, IF_CS_WRITE, buf[nb-1]); - - if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX); - if_cs_enable_ints(card); -} - -/* - * Get the command result out of the card. - */ -static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) -{ - unsigned long flags; - int ret = -1; - u16 status; - - /* is hardware ready? */ - status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if ((status & IF_CS_BIT_RESP) == 0) { - netdev_err(priv->dev, "no cmd response in card\n"); - *len = 0; - goto out; - } - - *len = if_cs_read16(priv->card, IF_CS_RESP_LEN); - if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { - netdev_err(priv->dev, - "card cmd buffer has invalid # of bytes (%d)\n", - *len); - goto out; - } - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16)); - if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP); - - /* This is a workaround for a firmware that reports too much - * bytes */ - *len -= 8; - ret = 0; - - /* Clear this flag again */ - spin_lock_irqsave(&priv->driver_lock, flags); - priv->dnld_sent = DNLD_RES_RECEIVED; - spin_unlock_irqrestore(&priv->driver_lock, flags); - -out: - return ret; -} - -static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) -{ - struct sk_buff *skb = NULL; - u16 len; - u8 *data; - - len = if_cs_read16(priv->card, IF_CS_READ_LEN); - if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { - netdev_err(priv->dev, - "card data buffer has invalid # of bytes (%d)\n", - len); - priv->dev->stats.rx_dropped++; - goto dat_err; - } - - skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); - if (!skb) - goto out; - skb_put(skb, len); - skb_reserve(skb, 2);/* 16 byte align */ - data = skb->data; - - /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); - if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_READ); - -dat_err: - if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX); - -out: - return skb; -} - -static irqreturn_t if_cs_interrupt(int irq, void *data) -{ - struct if_cs_card *card = data; - struct lbs_private *priv = card->priv; - u16 cause; - - /* Ask card interrupt cause register if there is something for us */ - cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); - lbs_deb_cs("cause 0x%04x\n", cause); - - if (cause == 0) { - /* Not for us */ - return IRQ_NONE; - } - - if (cause == 0xffff) { - /* Read in junk, the card has probably been removed */ - card->priv->surpriseremoved = 1; - return IRQ_HANDLED; - } - - if (cause & IF_CS_BIT_RX) { - struct sk_buff *skb; - lbs_deb_cs("rx packet\n"); - skb = if_cs_receive_data(priv); - if (skb) - lbs_process_rxed_packet(priv, skb); - } - - if (cause & IF_CS_BIT_TX) { - lbs_deb_cs("tx done\n"); - lbs_host_to_card_done(priv); - } - - if (cause & IF_CS_BIT_RESP) { - unsigned long flags; - u8 i; - - lbs_deb_cs("cmd resp\n"); - spin_lock_irqsave(&priv->driver_lock, flags); - i = (priv->resp_idx == 0) ? 1 : 0; - spin_unlock_irqrestore(&priv->driver_lock, flags); - - BUG_ON(priv->resp_len[i]); - if_cs_receive_cmdres(priv, priv->resp_buf[i], - &priv->resp_len[i]); - - spin_lock_irqsave(&priv->driver_lock, flags); - lbs_notify_command_response(priv, i); - spin_unlock_irqrestore(&priv->driver_lock, flags); - } - - if (cause & IF_CS_BIT_EVENT) { - u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); - if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, - IF_CS_BIT_EVENT); - lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8); - } - - /* Clear interrupt cause */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK); - - return IRQ_HANDLED; -} - - - - -/********************************************************************/ -/* Firmware */ -/********************************************************************/ - -/* - * Tries to program the helper firmware. - * - * Return 0 on success - */ -static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int sent = 0; - u8 scratch; - - /* - * This is the only place where an unaligned register access happens on - * the CF8305 card, therefore for the sake of speed of the driver, we do - * the alignment correction here. - */ - if (card->align_regs) - scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8; - else - scratch = if_cs_read8(card, IF_CS_SCRATCH); - - /* "If the value is 0x5a, the firmware is already - * downloaded successfully" - */ - if (scratch == IF_CS_SCRATCH_HELPER_OK) - goto done; - - /* "If the value is != 00, it is invalid value of register */ - if (scratch != IF_CS_SCRATCH_BOOT_OK) { - ret = -ENODEV; - goto done; - } - - lbs_deb_cs("helper size %td\n", fw->size); - - /* "Set the 5 bytes of the helper image to 0" */ - /* Not needed, this contains an ARM branch instruction */ - - for (;;) { - /* "the number of bytes to send is 256" */ - int count = 256; - int remain = fw->size - sent; - - if (remain < count) - count = remain; - - /* - * "write the number of bytes to be sent to the I/O Command - * write length register" - */ - if_cs_write16(card, IF_CS_CMD_LEN, count); - - /* "write this to I/O Command port register as 16 bit writes */ - if (count) - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - count >> 1); - - /* - * "Assert the download over interrupt command in the Host - * status register" - */ - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - - /* - * "Assert the download over interrupt command in the Card - * interrupt case register" - */ - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - /* - * "The host polls the Card Status register ... for 50 ms before - * declaring a failure" - */ - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download helper at 0x%x, ret %d\n", - sent, ret); - goto done; - } - - if (count == 0) - break; - - sent += count; - } - -done: - return ret; -} - - -static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw) -{ - int ret = 0; - int retry = 0; - int len = 0; - int sent; - - lbs_deb_cs("fw size %td\n", fw->size); - - ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW, - IF_CS_SQ_HELPER_OK); - if (ret < 0) { - pr_err("helper firmware doesn't answer\n"); - goto done; - } - - for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_SQ_READ_LOW); - if (len & 1) { - retry++; - pr_info("odd, need to retry this firmware block\n"); - } else { - retry = 0; - } - - if (retry > 20) { - pr_err("could not download firmware\n"); - ret = -ENODEV; - goto done; - } - if (retry) { - sent -= len; - } - - - if_cs_write16(card, IF_CS_CMD_LEN, len); - - if_cs_write16_rep(card, IF_CS_CMD, - &fw->data[sent], - (len+1) >> 1); - if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - - ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, - IF_CS_BIT_COMMAND); - if (ret < 0) { - pr_err("can't download firmware at 0x%x\n", sent); - goto done; - } - } - - ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); - if (ret < 0) - pr_err("firmware download failed\n"); - -done: - return ret; -} - -static void if_cs_prog_firmware(struct lbs_private *priv, int ret, - const struct firmware *helper, - const struct firmware *mainfw) -{ - struct if_cs_card *card = priv->card; - - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - return; - } - - /* Load the firmware */ - ret = if_cs_prog_helper(card, helper); - if (ret == 0 && (card->model != MODEL_8305)) - ret = if_cs_prog_real(card, mainfw); - if (ret) - return; - - /* Now actually get the IRQ */ - ret = request_irq(card->p_dev->irq, if_cs_interrupt, - IRQF_SHARED, DRV_NAME, card); - if (ret) { - pr_err("error in request_irq\n"); - return; - } - - /* - * Clear any interrupt cause that happened while sending - * firmware/initializing card - */ - if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); - if_cs_enable_ints(card); - - /* And finally bring the card up */ - priv->fw_ready = 1; - if (lbs_start_card(priv) != 0) { - pr_err("could not activate card\n"); - free_irq(card->p_dev->irq, card); - } -} - - -/********************************************************************/ -/* Callback functions for libertas.ko */ -/********************************************************************/ - -/* Send commands or data packets to the card */ -static int if_cs_host_to_card(struct lbs_private *priv, - u8 type, - u8 *buf, - u16 nb) -{ - int ret = -1; - - switch (type) { - case MVMS_DAT: - priv->dnld_sent = DNLD_DATA_SENT; - if_cs_send_data(priv, buf, nb); - ret = 0; - break; - case MVMS_CMD: - priv->dnld_sent = DNLD_CMD_SENT; - ret = if_cs_send_cmd(priv, buf, nb); - break; - default: - netdev_err(priv->dev, "%s: unsupported type %d\n", - __func__, type); - } - - return ret; -} - - -static void if_cs_release(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - free_irq(p_dev->irq, card); - pcmcia_disable_device(p_dev); - if (card->iobase) - ioport_unmap(card->iobase); -} - - -static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if (p_dev->resource[1]->end) { - pr_err("wrong CIS (check number of IO windows)\n"); - return -ENODEV; - } - - /* This reserves IO space but doesn't actually enable it */ - return pcmcia_request_io(p_dev); -} - -static int if_cs_probe(struct pcmcia_device *p_dev) -{ - int ret = -ENOMEM; - unsigned int prod_id; - struct lbs_private *priv; - struct if_cs_card *card; - - card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL); - if (!card) - goto out; - - card->p_dev = p_dev; - p_dev->priv = card; - - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) { - pr_err("error in pcmcia_loop_config\n"); - goto out1; - } - - /* - * Allocate an interrupt line. Note that this does not assign - * a handler to the interrupt, unless the 'Handler' member of - * the irq structure is initialized. - */ - if (!p_dev->irq) - goto out1; - - /* Initialize io access */ - card->iobase = ioport_map(p_dev->resource[0]->start, - resource_size(p_dev->resource[0])); - if (!card->iobase) { - pr_err("error in ioport_map\n"); - ret = -EIO; - goto out1; - } - - ret = pcmcia_enable_device(p_dev); - if (ret) { - pr_err("error in pcmcia_enable_device\n"); - goto out2; - } - - /* Finally, report what we've done */ - lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]); - - /* - * Most of the libertas cards can do unaligned register access, but some - * weird ones cannot. That's especially true for the CF8305 card. - */ - card->align_regs = false; - - card->model = get_model(p_dev->manf_id, p_dev->card_id); - if (card->model == MODEL_UNKNOWN) { - pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n", - p_dev->manf_id, p_dev->card_id); - ret = -ENODEV; - goto out2; - } - - /* Check if we have a current silicon */ - prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID); - if (card->model == MODEL_8305) { - card->align_regs = true; - if (prod_id < IF_CS_CF8305_B1_REV) { - pr_err("8305 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - } - - if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) { - pr_err("8381 rev B2 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) { - pr_err("8385 rev B0 and older are not supported\n"); - ret = -ENODEV; - goto out2; - } - - /* Make this card known to the libertas driver */ - priv = lbs_add_card(card, &p_dev->dev); - if (IS_ERR(priv)) { - ret = PTR_ERR(priv); - goto out2; - } - - /* Set up fields in lbs_private */ - card->priv = priv; - priv->card = card; - priv->hw_host_to_card = if_cs_host_to_card; - priv->enter_deep_sleep = NULL; - priv->exit_deep_sleep = NULL; - priv->reset_deep_sleep_wakeup = NULL; - - /* Get firmware */ - ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table, - if_cs_prog_firmware); - if (ret) { - pr_err("failed to find firmware (%d)\n", ret); - goto out3; - } - - goto out; - -out3: - lbs_remove_card(priv); -out2: - ioport_unmap(card->iobase); -out1: - pcmcia_disable_device(p_dev); -out: - return ret; -} - - -static void if_cs_detach(struct pcmcia_device *p_dev) -{ - struct if_cs_card *card = p_dev->priv; - - lbs_stop_card(card->priv); - lbs_remove_card(card->priv); - if_cs_disable_ints(card); - if_cs_release(p_dev); - kfree(card); -} - - - -/********************************************************************/ -/* Module initialization */ -/********************************************************************/ - -static const struct pcmcia_device_id if_cs_ids[] = { - PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), - PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), - /* NOTE: keep in sync with get_model() */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); - -static struct pcmcia_driver lbs_driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .probe = if_cs_probe, - .remove = if_cs_detach, - .id_table = if_cs_ids, -}; -module_pcmcia_driver(lbs_driver); From patchwork Mon Oct 23 13:19:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 13432847 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D7A51CDB474 for ; Mon, 23 Oct 2023 13:21:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=A6JU7BHHRm1SxMg1+AgdsSMRJ3c5ARjKS57MG1NqWvU=; b=A64MH8e1tXoRSA zuuOvkqd1NNi7bJ5CLmEfjeWL8c27CUPG0T0IfUoPZJ1fgPHtxFn09OE0ozrdOIm+zKdF+jGff3q8 NDX+eXUywAhA+TSErtbdVv3bwXUxCsqTfcbpTJRGVe+lMl14FiPq44weqYb1M7+rx0NQVPB6IO+vt PRqXP2ty40WmWvPNrnFGlg08QOhWxkg6RprbHLAYDYZZho1s6QSvdJjXjqrDo6Ju06XXW1GCNC48n ynTUH8HvJ7C2Ih9kMrOXa6XRyk0ZI1QRzGepXIEFOOlRAGxfC2caYLacZgv+Xr3Ihjlr423RLDJsq VMy6zYfTSRjVwt4xwegg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1quurZ-007QOc-11; Mon, 23 Oct 2023 13:20:57 +0000 Received: from sin.source.kernel.org ([2604:1380:40e1:4800::1]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1quurK-007QI1-1x for linux-arm-kernel@lists.infradead.org; Mon, 23 Oct 2023 13:20:55 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 8C4C3CE248A; Mon, 23 Oct 2023 13:20:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 92809C433CA; Mon, 23 Oct 2023 13:20:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698067239; bh=++bBb8IK3w/0hHMylV43PpVYsba57W8n3rqjGv7Qsmo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XgH4l+a5tCTcZFYv03qJmawOlnP3VZhGy6ADnXvjHgF0D+2COoe9PMadrxlurk5aC /xmJQzJ+WV2aF+ArRSntvEGynwRocxFt1844GNYPwgw+QVivNXfpNl0r6//ieU8Uje iLEvA6Q3WNicaTbsAWBjmCyGceX1redIAWOByTCKHLNWXr4kZedC1iGnqRxtgpypVw PHtIyf9ShxuezVkNqt1BMiD+jJj4xA3ZWxgt8nH+oMk4ViIczgPQ2aEJaiaWZEie+0 SVBztTNos5qfwYiHmDLIsRcrATAEAhn5+cjNmt/xrn//3lyt77DjJzdPGPLwiS7o5R Ovs22+s+uQXHA== From: Arnd Bergmann To: Kalle Valo Subject: [PATCH 05/10] wifi: remove orphaned zd1201 driver Date: Mon, 23 Oct 2023 15:19:47 +0200 Message-Id: <20231023131953.2876682-6-arnd@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231023131953.2876682-1-arnd@kernel.org> References: <20231023131953.2876682-1-arnd@kernel.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231023_062043_193443_CA296CCB X-CRM114-Status: GOOD ( 29.84 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stanislaw Gruszka , Alexandre Belloni , linux-staging@lists.linux.dev, linux-kernel@vger.kernel.org, Arnd Bergmann , Geoff Levand , Greg Kroah-Hartman , linuxppc-dev , linux-wireless@vger.kernel.org, Claudiu Beznea , Geert Uytterhoeven , Pavel Machek , Gregory Greenman , Jakub Kicinski , Johannes Berg , Jeff Johnson , "David S . Miller" , linux-arm-kernel@lists.infradead.org, Larry Finger Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Arnd Bergmann This is a wireless extensions style driver for 802.11b USB dongles, with partial support for cfg80211 interfaces. As these are all external dongles, there are probably few users that have not yet replaced them with cheap 802.11n devices that work better. Signed-off-by: Arnd Bergmann --- MAINTAINERS | 6 - drivers/net/wireless/zydas/Kconfig | 19 - drivers/net/wireless/zydas/Makefile | 2 - drivers/net/wireless/zydas/zd1201.c | 1909 --------------------------- drivers/net/wireless/zydas/zd1201.h | 144 -- 5 files changed, 2080 deletions(-) delete mode 100644 drivers/net/wireless/zydas/zd1201.c delete mode 100644 drivers/net/wireless/zydas/zd1201.h diff --git a/MAINTAINERS b/MAINTAINERS index 78fa9932ba28f..be59dc66c8133 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22426,12 +22426,6 @@ S: Supported F: drivers/usb/host/pci-quirks* F: drivers/usb/host/xhci* -USB ZD1201 DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://linux-lc100020.sourceforge.net -F: drivers/net/wireless/zydas/zd1201.* - USER DATAGRAM PROTOCOL (UDP) M: Willem de Bruijn S: Maintained diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig index 08574433df66f..839e1217e855c 100644 --- a/drivers/net/wireless/zydas/Kconfig +++ b/drivers/net/wireless/zydas/Kconfig @@ -12,25 +12,6 @@ config WLAN_VENDOR_ZYDAS if WLAN_VENDOR_ZYDAS -config USB_ZD1201 - tristate "USB ZD1201 based Wireless device support" - depends on CFG80211 && USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - help - Say Y if you want to use wireless LAN adapters based on the ZyDAS - ZD1201 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on wlan0. - - The zd1201 device requires external firmware to be loaded. - This can be found at http://linux-lc100020.sourceforge.net/ - - To compile this driver as a module, choose M here: the - module will be called zd1201. - source "drivers/net/wireless/zydas/zd1211rw/Kconfig" endif # WLAN_VENDOR_ZYDAS diff --git a/drivers/net/wireless/zydas/Makefile b/drivers/net/wireless/zydas/Makefile index c70003d30a8fb..3e0a51db98742 100644 --- a/drivers/net/wireless/zydas/Makefile +++ b/drivers/net/wireless/zydas/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_ZD1211RW) += zd1211rw/ - -obj-$(CONFIG_USB_ZD1201) += zd1201.o diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c deleted file mode 100644 index 2814df1ecc78f..0000000000000 --- a/drivers/net/wireless/zydas/zd1201.c +++ /dev/null @@ -1,1909 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for ZyDAS zd1201 based USB wireless devices. - * - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. They also made documentation available, thanks! - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "zd1201.h" - -static const struct usb_device_id zd1201_table[] = { - {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */ - {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */ - {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ - {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ - {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ - {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ - {} -}; - -static int ap; /* Are we an AP or a normal station? */ - -#define ZD1201_VERSION "0.15" - -MODULE_AUTHOR("Jeroen Vreeken "); -MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters"); -MODULE_VERSION(ZD1201_VERSION); -MODULE_LICENSE("GPL"); -module_param(ap, int, 0); -MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded"); -MODULE_DEVICE_TABLE(usb, zd1201_table); - - -static int zd1201_fw_upload(struct usb_device *dev, int apfw) -{ - const struct firmware *fw_entry; - const char *data; - unsigned long len; - int err; - unsigned char ret; - char *buf; - char *fwfile; - - if (apfw) - fwfile = "zd1201-ap.fw"; - else - fwfile = "zd1201.fw"; - - err = request_firmware(&fw_entry, fwfile, &dev->dev); - if (err) { - dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile); - dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n"); - dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n"); - return err; - } - - data = fw_entry->data; - len = fw_entry->size; - - buf = kmalloc(1024, GFP_ATOMIC); - if (!buf) { - err = -ENOMEM; - goto exit; - } - - while (len > 0) { - int translen = (len > 1024) ? 1024 : len; - memcpy(buf, data, translen); - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, - USB_DIR_OUT | 0x40, 0, 0, buf, translen, - ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - len -= translen; - data += translen; - } - - err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2, - USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, - USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT); - if (err < 0) - goto exit; - - memcpy(&ret, buf, sizeof(ret)); - - if (ret & 0x80) { - err = -EIO; - goto exit; - } - - err = 0; -exit: - kfree(buf); - release_firmware(fw_entry); - return err; -} - -MODULE_FIRMWARE("zd1201-ap.fw"); -MODULE_FIRMWARE("zd1201.fw"); - -static void zd1201_usbfree(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: urb failed: %d\n", - zd->dev->name, urb->status); - } - - kfree(urb->transfer_buffer); - usb_free_urb(urb); -} - -/* cmdreq message: - u32 type - u16 cmd - u16 parm0 - u16 parm1 - u16 parm2 - u8 pad[4] - - total: 4 + 2 + 2 + 2 + 2 + 4 = 16 -*/ -static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0, - int parm1, int parm2) -{ - unsigned char *command; - int ret; - struct urb *urb; - - command = kmalloc(16, GFP_ATOMIC); - if (!command) - return -ENOMEM; - - *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&command[4]) = cpu_to_le16(cmd); - *((__le16*)&command[6]) = cpu_to_le16(parm0); - *((__le16*)&command[8]) = cpu_to_le16(parm1); - *((__le16*)&command[10])= cpu_to_le16(parm2); - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(command); - return -ENOMEM; - } - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - command, 16, zd1201_usbfree, zd); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - kfree(command); - usb_free_urb(urb); - } - - return ret; -} - -/* Callback after sending out a packet */ -static void zd1201_usbtx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - netif_wake_queue(zd->dev); -} - -/* Incoming data */ -static void zd1201_usbrx(struct urb *urb) -{ - struct zd1201 *zd = urb->context; - int free = 0; - unsigned char *data = urb->transfer_buffer; - struct sk_buff *skb; - unsigned char type; - - if (!zd) - return; - - switch(urb->status) { - case -EILSEQ: - case -ENODEV: - case -ETIME: - case -ENOENT: - case -EPIPE: - case -EOVERFLOW: - case -ESHUTDOWN: - dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n", - zd->dev->name, urb->status); - free = 1; - goto exit; - } - - if (urb->status != 0 || urb->actual_length == 0) - goto resubmit; - - type = data[0]; - if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) { - memcpy(zd->rxdata, data, urb->actual_length); - zd->rxlen = urb->actual_length; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - /* Info frame */ - if (type == ZD1201_PACKET_INQUIRE) { - int i = 0; - unsigned short infotype, copylen; - infotype = le16_to_cpu(*(__le16*)&data[6]); - - if (infotype == ZD1201_INF_LINKSTATUS) { - short linkstatus; - - linkstatus = le16_to_cpu(*(__le16*)&data[8]); - switch(linkstatus) { - case 1: - netif_carrier_on(zd->dev); - break; - case 2: - netif_carrier_off(zd->dev); - break; - case 3: - netif_carrier_off(zd->dev); - break; - case 4: - netif_carrier_on(zd->dev); - break; - default: - netif_carrier_off(zd->dev); - } - goto resubmit; - } - if (infotype == ZD1201_INF_ASSOCSTATUS) { - short status = le16_to_cpu(*(__le16*)(data+8)); - int event; - union iwreq_data wrqu; - - switch (status) { - case ZD1201_ASSOCSTATUS_STAASSOC: - case ZD1201_ASSOCSTATUS_REASSOC: - event = IWEVREGISTERED; - break; - case ZD1201_ASSOCSTATUS_DISASSOC: - case ZD1201_ASSOCSTATUS_ASSOCFAIL: - case ZD1201_ASSOCSTATUS_AUTHFAIL: - default: - event = IWEVEXPIRED; - } - memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - - /* Send event to user space */ - wireless_send_event(zd->dev, event, &wrqu, NULL); - - goto resubmit; - } - if (infotype == ZD1201_INF_AUTHREQ) { - union iwreq_data wrqu; - - memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - /* There isn't a event that trully fits this request. - We assume that userspace will be smart enough to - see a new station being expired and sends back a - authstation ioctl to authorize it. */ - wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL); - goto resubmit; - } - /* Other infotypes are handled outside this handler */ - zd->rxlen = 0; - while (i < urb->actual_length) { - copylen = le16_to_cpu(*(__le16*)&data[i+2]); - /* Sanity check, sometimes we get junk */ - if (copylen+zd->rxlen > sizeof(zd->rxdata)) - break; - memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen); - zd->rxlen += copylen; - i += 64; - } - if (i >= urb->actual_length) { - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - } - goto resubmit; - } - /* Actual data */ - if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) { - int datalen = urb->actual_length-1; - unsigned short len, fc, seq; - - len = ntohs(*(__be16 *)&data[datalen-2]); - if (len>datalen) - len=datalen; - fc = le16_to_cpu(*(__le16 *)&data[datalen-16]); - seq = le16_to_cpu(*(__le16 *)&data[datalen-24]); - - if (zd->monitor) { - if (datalen < 24) - goto resubmit; - if (!(skb = dev_alloc_skb(datalen+24))) - goto resubmit; - - skb_put_data(skb, &data[datalen - 16], 2); - skb_put_data(skb, &data[datalen - 2], 2); - skb_put_data(skb, &data[datalen - 14], 6); - skb_put_data(skb, &data[datalen - 22], 6); - skb_put_data(skb, &data[datalen - 8], 6); - skb_put_data(skb, &data[datalen - 24], 2); - skb_put_data(skb, data, len); - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - goto resubmit; - } - - if ((seq & IEEE80211_SCTL_FRAG) || - (fc & IEEE80211_FCTL_MOREFRAGS)) { - struct zd1201_frag *frag = NULL; - char *ptr; - - if (datalen<14) - goto resubmit; - if ((seq & IEEE80211_SCTL_FRAG) == 0) { - frag = kmalloc(sizeof(*frag), GFP_ATOMIC); - if (!frag) - goto resubmit; - skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); - if (!skb) { - kfree(frag); - goto resubmit; - } - frag->skb = skb; - frag->seq = seq & IEEE80211_SCTL_SEQ; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - hlist_add_head(&frag->fnode, &zd->fraglist); - goto resubmit; - } - hlist_for_each_entry(frag, &zd->fraglist, fnode) - if (frag->seq == (seq&IEEE80211_SCTL_SEQ)) - break; - if (!frag) - goto resubmit; - skb = frag->skb; - ptr = skb_put(skb, len); - if (ptr) - memcpy(ptr, data+8, len); - if (fc & IEEE80211_FCTL_MOREFRAGS) - goto resubmit; - hlist_del_init(&frag->fnode); - kfree(frag); - } else { - if (datalen<14) - goto resubmit; - skb = dev_alloc_skb(len + 14 + 2); - if (!skb) - goto resubmit; - skb_reserve(skb, 2); - skb_put_data(skb, &data[datalen - 14], 12); - skb_put_data(skb, &data[6], 2); - skb_put_data(skb, data + 8, len); - } - skb->protocol = eth_type_trans(skb, zd->dev); - zd->dev->stats.rx_packets++; - zd->dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -resubmit: - memset(data, 0, ZD1201_RXSIZE); - - urb->status = 0; - urb->dev = zd->usb; - if(usb_submit_urb(urb, GFP_ATOMIC)) - free = 1; - -exit: - if (free) { - zd->rxlen = 0; - zd->rxdatas = 1; - wake_up(&zd->rxdataq); - kfree(urb->transfer_buffer); - } -} - -static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata, - unsigned int riddatalen) -{ - int err; - int i = 0; - int code; - int rid_fid; - int length; - unsigned char *pdata; - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - code = le16_to_cpu(*(__le16*)(&zd->rxdata[4])); - rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6])); - length = le16_to_cpu(*(__le16*)(&zd->rxdata[8])); - if (length > zd->rxlen) - length = zd->rxlen-6; - - /* If access bit is not on, then error */ - if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid ) - return -EINVAL; - - /* Not enough buffer for allocating data */ - if (riddatalen != (length - 4)) { - dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n", - riddatalen, zd->rxlen, length, rid, rid_fid); - return -ENODATA; - } - - zd->rxdatas = 0; - /* Issue SetRxRid commnd */ - err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length); - if (err) - return err; - - /* Receive RID record from resource packets */ - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) { - dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n", - zd->rxdata[zd->rxlen-1]); - return -EINVAL; - } - - /* Set the data pointer and received data length */ - pdata = zd->rxdata; - length = zd->rxlen; - - do { - int actual_length; - - actual_length = (length > 64) ? 64 : length; - - if (pdata[0] != 0x3) { - dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n", - pdata[0]); - return -EINVAL; - } - - if (actual_length != 64) { - /* Trim the last packet type byte */ - actual_length--; - } - - /* Skip the 4 bytes header (RID length and RID) */ - if (i == 0) { - pdata += 8; - actual_length -= 8; - } else { - pdata += 4; - actual_length -= 4; - } - - memcpy(riddata, pdata, actual_length); - riddata += actual_length; - pdata += actual_length; - length -= 64; - i++; - } while (length > 0); - - return 0; -} - -/* - * resreq: - * byte type - * byte sequence - * u16 reserved - * byte data[12] - * total: 16 - */ -static int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait) -{ - int err; - unsigned char *request; - int reqlen; - char seq=0; - struct urb *urb; - gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC; - - len += 4; /* first 4 are for header */ - - zd->rxdatas = 0; - zd->rxlen = 0; - for (seq=0; len > 0; seq++) { - request = kzalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - reqlen = len>12 ? 12 : len; - request[0] = ZD1201_USB_RESREQ; - request[1] = seq; - request[2] = 0; - request[3] = 0; - if (request[1] == 0) { - /* add header */ - *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2); - *(__le16*)&request[6] = cpu_to_le16(rid); - memcpy(request+8, buf, reqlen-4); - buf += reqlen-4; - } else { - memcpy(request+4, buf, reqlen); - buf += reqlen; - } - - len -= reqlen; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, - zd->endp_out2), request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - } - - request = kmalloc(16, gfp_mask); - if (!request) - return -ENOMEM; - urb = usb_alloc_urb(0, gfp_mask); - if (!urb) { - kfree(request); - return -ENOMEM; - } - *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ); - *((__le16*)&request[4]) = - cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT); - *((__le16*)&request[6]) = cpu_to_le16(rid); - *((__le16*)&request[8]) = cpu_to_le16(0); - *((__le16*)&request[10]) = cpu_to_le16(0); - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2), - request, 16, zd1201_usbfree, zd); - err = usb_submit_urb(urb, gfp_mask); - if (err) - goto err; - - if (wait) { - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) { - dev_dbg(&zd->usb->dev, "wrong or no RID received\n"); - } - } - - return 0; -err: - kfree(request); - usb_free_urb(urb); - return err; -} - -static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val) -{ - int err; - __le16 zdval; - - err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16)); - if (err) - return err; - *val = le16_to_cpu(zdval); - return 0; -} - -static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val) -{ - __le16 zdval = cpu_to_le16(val); - return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1)); -} - -static int zd1201_drvr_start(struct zd1201 *zd) -{ - int err, i; - short max; - __le16 zdmax; - unsigned char *buffer; - - buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - usb_fill_bulk_urb(zd->rx_urb, zd->usb, - usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE, - zd1201_usbrx, zd); - - err = usb_submit_urb(zd->rx_urb, GFP_KERNEL); - if (err) - goto err_buffer; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); - if (err) - goto err_urb; - - err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax, - sizeof(__le16)); - if (err) - goto err_urb; - - max = le16_to_cpu(zdmax); - for (i=0; irx_urb); - return err; -err_buffer: - kfree(buffer); - return err; -} - -/* Magic alert: The firmware doesn't seem to like the MAC state being - * toggled in promisc (aka monitor) mode. - * (It works a number of times, but will halt eventually) - * So we turn it of before disabling and on after enabling if needed. - */ -static int zd1201_enable(struct zd1201 *zd) -{ - int err; - - if (zd->mac_enabled) - return 0; - - err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 1; - - if (zd->monitor) - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1); - - return err; -} - -static int zd1201_disable(struct zd1201 *zd) -{ - int err; - - if (!zd->mac_enabled) - return 0; - if (zd->monitor) { - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - } - - err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0); - if (!err) - zd->mac_enabled = 0; - return err; -} - -static int zd1201_mac_reset(struct zd1201 *zd) -{ - if (!zd->mac_enabled) - return 0; - zd1201_disable(zd); - return zd1201_enable(zd); -} - -static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) -{ - int err, val; - char buf[IW_ESSID_MAX_SIZE+2]; - - err = zd1201_disable(zd); - if (err) - return err; - - val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val); - if (err) - return err; - - *(__le16 *)buf = cpu_to_le16(essidlen); - memcpy(buf+2, essid, essidlen); - if (!zd->ap) { /* Normal station */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } else { /* AP */ - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len, 1); - if (err) - return err; - - err = zd1201_enable(zd); - if (err) - return err; - - msleep(100); - return 0; -} - -static int zd1201_net_open(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - /* Start MAC with wildcard if no essid set */ - if (!zd->mac_enabled) - zd1201_join(zd, zd->essid, zd->essidlen); - netif_start_queue(dev); - - return 0; -} - -static int zd1201_net_stop(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -/* - RFC 1042 encapsulates Ethernet frames in 802.11 frames - by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0 - (0x00, 0x00, 0x00). Zd requires an additional padding, copy - of ethernet addresses, length of the standard RFC 1042 packet - and a command byte (which is nul for tx). - - tx frame (from Wlan NG): - RFC 1042: - llc 0xAA 0xAA 0x03 (802.2 LLC) - snap 0x00 0x00 0x00 (Ethernet encapsulated) - type 2 bytes, Ethernet type field - payload (minus eth header) - Zydas specific: - padding 1B if (skb->len+8+1)%64==0 - Eth MAC addr 12 bytes, Ethernet MAC addresses - length 2 bytes, RFC 1042 packet length - (llc+snap+type+payload) - zd 1 null byte, zd1201 packet type - */ -static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - unsigned char *txbuf = zd->txdata; - int txbuflen, pad = 0, err; - struct urb *urb = zd->tx_urb; - - if (!zd->mac_enabled || zd->monitor) { - dev->stats.tx_dropped++; - kfree_skb(skb); - return NETDEV_TX_OK; - } - netif_stop_queue(dev); - - txbuflen = skb->len + 8 + 1; - if (txbuflen%64 == 0) { - pad = 1; - txbuflen++; - } - txbuf[0] = 0xAA; - txbuf[1] = 0xAA; - txbuf[2] = 0x03; - txbuf[3] = 0x00; /* rfc1042 */ - txbuf[4] = 0x00; - txbuf[5] = 0x00; - - skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12); - if (pad) - txbuf[skb->len-12+6]=0; - skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12); - *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6); - txbuf[txbuflen-1] = 0; - - usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out), - txbuf, txbuflen, zd1201_usbtx, zd); - - err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC); - if (err) { - dev->stats.tx_errors++; - netif_start_queue(dev); - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - } - kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct zd1201 *zd = netdev_priv(dev); - - if (!zd) - return; - dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n", - dev->name); - usb_unlink_urb(zd->tx_urb); - dev->stats.tx_errors++; - /* Restart the timeout to quiet the watchdog: */ - netif_trans_update(dev); /* prevent tx timeout */ -} - -static int zd1201_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - struct zd1201 *zd = netdev_priv(dev); - int err; - - if (!zd) - return -ENODEV; - - err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, - addr->sa_data, dev->addr_len, 1); - if (err) - return err; - eth_hw_addr_set(dev, addr->sa_data); - - return zd1201_mac_reset(zd); -} - -static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - - return &zd->iwstats; -} - -static void zd1201_set_multicast(struct net_device *dev) -{ - struct zd1201 *zd = netdev_priv(dev); - struct netdev_hw_addr *ha; - unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; - int i; - - if (netdev_mc_count(dev) > ZD1201_MAXMULTI) - return; - - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN); - zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf, - netdev_mc_count(dev) * ETH_ALEN, 0); -} - -static int zd1201_config_commit(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct zd1201 *zd = netdev_priv(dev); - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_name(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - strcpy(wrqu->name, "IEEE 802.11b"); - return 0; -} - -static int zd1201_set_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel = 0; - int err; - - if (freq->e == 0) - channel = freq->m; - else - channel = ieee80211_frequency_to_channel(freq->m); - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel); - if (err) - return err; - - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_freq(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_freq *freq = &wrqu->freq; - struct zd1201 *zd = netdev_priv(dev); - short channel; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel); - if (err) - return err; - freq->e = 0; - freq->m = channel; - - return 0; -} - -static int zd1201_set_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype, monitor = 0; - unsigned char buffer[IW_ESSID_MAX_SIZE+2]; - int err; - - if (zd->ap) { - if (*mode != IW_MODE_MASTER) - return -EINVAL; - return 0; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0); - if (err) - return err; - zd->dev->type = ARPHRD_ETHER; - switch(*mode) { - case IW_MODE_MONITOR: - monitor = 1; - zd->dev->type = ARPHRD_IEEE80211; - /* Make sure we are no longer associated with by - setting an 'impossible' essid. - (otherwise we mess up firmware) - */ - zd1201_join(zd, "\0-*#\0", 5); - /* Put port in pIBSS */ - fallthrough; - case 8: /* No pseudo-IBSS in wireless extensions (yet) */ - porttype = ZD1201_PORTTYPE_PSEUDOIBSS; - break; - case IW_MODE_ADHOC: - porttype = ZD1201_PORTTYPE_IBSS; - break; - case IW_MODE_INFRA: - porttype = ZD1201_PORTTYPE_BSS; - break; - default: - return -EINVAL; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - return err; - if (zd->monitor && !monitor) { - zd1201_disable(zd); - *(__le16 *)buffer = cpu_to_le16(zd->essidlen); - memcpy(buffer+2, zd->essid, zd->essidlen); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, - buffer, IW_ESSID_MAX_SIZE+2, 1); - if (err) - return err; - } - zd->monitor = monitor; - /* If monitor mode is set we don't actually turn it on here since it - * is done during mac reset anyway (see zd1201_mac_enable). - */ - zd1201_mac_reset(zd); - - return 0; -} - -static int zd1201_get_mode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - __u32 *mode = &wrqu->mode; - struct zd1201 *zd = netdev_priv(dev); - short porttype; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype); - if (err) - return err; - switch(porttype) { - case ZD1201_PORTTYPE_IBSS: - *mode = IW_MODE_ADHOC; - break; - case ZD1201_PORTTYPE_BSS: - *mode = IW_MODE_INFRA; - break; - case ZD1201_PORTTYPE_WDS: - *mode = IW_MODE_REPEAT; - break; - case ZD1201_PORTTYPE_PSEUDOIBSS: - *mode = 8;/* No Pseudo-IBSS... */ - break; - case ZD1201_PORTTYPE_AP: - *mode = IW_MODE_MASTER; - break; - default: - dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n", - porttype); - *mode = IW_MODE_AUTO; - } - if (zd->monitor) - *mode = IW_MODE_MONITOR; - - return 0; -} - -static int zd1201_get_range(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *wrq = &wrqu->data; - struct iw_range *range = (struct iw_range *)extra; - - wrq->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = WIRELESS_EXT; - - range->max_qual.qual = 128; - range->max_qual.level = 128; - range->max_qual.noise = 128; - range->max_qual.updated = 7; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = ZD1201_NUMKEYS; - - range->num_bitrates = 4; - range->bitrate[0] = 1000000; - range->bitrate[1] = 2000000; - range->bitrate[2] = 5500000; - range->bitrate[3] = 11000000; - - range->min_rts = 0; - range->min_frag = ZD1201_FRAGMIN; - range->max_rts = ZD1201_RTSMAX; - range->min_frag = ZD1201_FRAGMAX; - - return 0; -} - -/* Little bit of magic here: we only get the quality if we poll - * for it, and we never get an actual request to trigger such - * a poll. Therefore we 'assume' that the user will soon ask for - * the stats after asking the bssid. - */ -static int zd1201_get_wap(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *ap_addr = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[6]; - - if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { - /* Unfortunately the quality and noise reported is useless. - they seem to be accumulators that increase until you - read them, unless we poll on a fixed interval we can't - use them - */ - /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/ - zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]); - /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/ - zd->iwstats.qual.updated = 2; - } - - return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6); -} - -static int zd1201_set_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - /* We do everything in get_scan */ - return 0; -} - -static int zd1201_get_scan(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_point *srq = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - int err, i, j, enabled_save; - struct iw_event iwe; - char *cev = extra; - char *end_buf = extra + IW_SCAN_MAX_DATA; - - /* No scanning in AP mode */ - if (zd->ap) - return -EOPNOTSUPP; - - /* Scan doesn't seem to work if disabled */ - enabled_save = zd->mac_enabled; - zd1201_enable(zd); - - zd->rxdatas = 0; - err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE, - ZD1201_INQ_SCANRESULTS, 0, 0); - if (err) - return err; - - wait_event_interruptible(zd->rxdataq, zd->rxdatas); - if (!zd->rxlen) - return -EIO; - - if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS) - return -EIO; - - for(i=8; irxlen; i+=62) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6); - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_ADDR_LEN); - - iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = zd->rxdata[i+16]; - iwe.u.data.flags = 1; - cev = iwe_stream_add_point(info, cev, end_buf, - &iwe, zd->rxdata+i+18); - - iwe.cmd = SIOCGIWMODE; - if (zd->rxdata[i+14]&0x01) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_UINT_LEN); - - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = zd->rxdata[i+0]; - iwe.u.freq.e = 0; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_FREQ_LEN); - - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.disabled = 0; - for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) { - iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_PARAM_LEN); - } - - iwe.cmd = SIOCGIWENCODE; - iwe.u.data.length = 0; - if (zd->rxdata[i+14]&0x10) - iwe.u.data.flags = IW_ENCODE_ENABLED; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL); - - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = zd->rxdata[i+4]; - iwe.u.qual.noise= zd->rxdata[i+2]/10-100; - iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100; - iwe.u.qual.updated = 7; - cev = iwe_stream_add_event(info, cev, end_buf, - &iwe, IW_EV_QUAL_LEN); - } - - if (!enabled_save) - zd1201_disable(zd); - - srq->length = cev - extra; - srq->flags = 0; - - return 0; -} - -static int zd1201_set_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - if (data->length > IW_ESSID_MAX_SIZE) - return -EINVAL; - if (data->length < 1) - data->length = 1; - zd->essidlen = data->length; - memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1); - memcpy(zd->essid, essid, data->length); - return zd1201_join(zd, zd->essid, zd->essidlen); -} - -static int zd1201_get_essid(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *essid) -{ - struct iw_point *data = &wrqu->data; - struct zd1201 *zd = netdev_priv(dev); - - memcpy(essid, zd->essid, zd->essidlen); - data->flags = 1; - data->length = zd->essidlen; - - return 0; -} - -static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *nick) -{ - struct iw_point *data = &wrqu->data; - strcpy(nick, "zd1201"); - data->flags = 1; - data->length = strlen(nick); - return 0; -} - -static int zd1201_set_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - switch (rrq->value) { - case 1000000: - rate = ZD1201_RATEB1; - break; - case 2000000: - rate = ZD1201_RATEB2; - break; - case 5500000: - rate = ZD1201_RATEB5; - break; - case 11000000: - default: - rate = ZD1201_RATEB11; - break; - } - if (!rrq->fixed) { /* Also enable all lower bitrates */ - rate |= rate-1; - } - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rate(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->bitrate; - struct zd1201 *zd = netdev_priv(dev); - short rate; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate); - if (err) - return err; - - switch(rate) { - case 1: - rrq->value = 1000000; - break; - case 2: - rrq->value = 2000000; - break; - case 5: - rrq->value = 5500000; - break; - case 11: - rrq->value = 11000000; - break; - default: - rrq->value = 0; - } - rrq->fixed = 0; - rrq->disabled = 0; - - return 0; -} - -static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = rts->value; - - if (rts->disabled || !rts->fixed) - val = ZD1201_RTSMAX; - if (val > ZD1201_RTSMAX) - return -EINVAL; - if (val < 0) - return -EINVAL; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rts = &wrqu->rts; - struct zd1201 *zd = netdev_priv(dev); - short rtst; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst); - if (err) - return err; - rts->value = rtst; - rts->disabled = (rts->value == ZD1201_RTSMAX); - rts->fixed = 1; - - return 0; -} - -static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - int err; - short val = frag->value; - - if (frag->disabled || !frag->fixed) - val = ZD1201_FRAGMAX; - if (val > ZD1201_FRAGMAX) - return -EINVAL; - if (val < ZD1201_FRAGMIN) - return -EINVAL; - if (val & 1) - return -EINVAL; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val); - if (err) - return err; - return zd1201_mac_reset(zd); -} - -static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_param *frag = &wrqu->frag; - struct zd1201 *zd = netdev_priv(dev); - short fragt; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt); - if (err) - return err; - frag->value = fragt; - frag->disabled = (frag->value == ZD1201_FRAGMAX); - frag->fixed = 1; - - return 0; -} - -static int zd1201_set_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_get_retry(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int zd1201_set_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err, rid; - - if (erq->length > ZD1201_MAXKEYLEN) - return -EINVAL; - - i = (erq->flags & IW_ENCODE_INDEX)-1; - if (i == -1) { - err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i); - if (err) - return err; - } else { - err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i); - if (err) - return err; - } - - if (i < 0 || i >= ZD1201_NUMKEYS) - return -EINVAL; - - rid = ZD1201_RID_CNFDEFAULTKEY0 + i; - err = zd1201_setconfig(zd, rid, key, erq->length, 1); - if (err) - return err; - zd->encode_keylen[i] = erq->length; - memcpy(zd->encode_keys[i], key, erq->length); - - i=0; - if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) { - i |= 0x01; - zd->encode_enabled = 1; - } else - zd->encode_enabled = 0; - if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) { - i |= 0x02; - zd->encode_restricted = 1; - } else - zd->encode_restricted = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i); - if (err) - return err; - - if (zd->encode_enabled) - i = ZD1201_CNFAUTHENTICATION_SHAREDKEY; - else - i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i); - if (err) - return err; - - return zd1201_mac_reset(zd); -} - -static int zd1201_get_encode(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *key) -{ - struct iw_point *erq = &wrqu->encoding; - struct zd1201 *zd = netdev_priv(dev); - short i; - int err; - - if (zd->encode_enabled) - erq->flags = IW_ENCODE_ENABLED; - else - erq->flags = IW_ENCODE_DISABLED; - if (zd->encode_restricted) - erq->flags |= IW_ENCODE_RESTRICTED; - else - erq->flags |= IW_ENCODE_OPEN; - - i = (erq->flags & IW_ENCODE_INDEX) -1; - if (i == -1) { - err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i); - if (err) - return err; - } - if (i<0 || i>= ZD1201_NUMKEYS) - return -EINVAL; - - erq->flags |= i+1; - - erq->length = zd->encode_keylen[i]; - memcpy(key, zd->encode_keys[i], erq->length); - - return 0; -} - -static int zd1201_set_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, duration, level; - int err; - - enabled = vwrq->disabled ? 0 : 1; - if (enabled) { - if (vwrq->flags & IW_POWER_PERIOD) { - duration = vwrq->value; - err = zd1201_setconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, duration); - if (err) - return err; - goto out; - } - if (vwrq->flags & IW_POWER_TIMEOUT) { - err = zd1201_getconfig16(zd, - ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - level = vwrq->value * 4 / duration; - if (level > 4) - level = 4; - if (level < 0) - level = 0; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS, - level); - if (err) - return err; - goto out; - } - return -EINVAL; - } -out: - return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled); -} - -static int zd1201_get_power(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *vwrq = &wrqu->power; - struct zd1201 *zd = netdev_priv(dev); - short enabled, level, duration; - int err; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level); - if (err) - return err; - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration); - if (err) - return err; - vwrq->disabled = enabled ? 0 : 1; - if (vwrq->flags & IW_POWER_TYPE) { - if (vwrq->flags & IW_POWER_PERIOD) { - vwrq->value = duration; - vwrq->flags = IW_POWER_PERIOD; - } else { - vwrq->value = duration * level / 4; - vwrq->flags = IW_POWER_TIMEOUT; - } - } - if (vwrq->flags & IW_POWER_MODE) { - if (enabled && level) - vwrq->flags = IW_POWER_UNICAST_R; - else - vwrq->flags = IW_POWER_ALL_R; - } - - return 0; -} - - -static const iw_handler zd1201_iw_handler[] = -{ - IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit), - IW_HANDLER(SIOCGIWNAME, zd1201_get_name), - IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq), - IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq), - IW_HANDLER(SIOCSIWMODE, zd1201_set_mode), - IW_HANDLER(SIOCGIWMODE, zd1201_get_mode), - IW_HANDLER(SIOCGIWRANGE, zd1201_get_range), - IW_HANDLER(SIOCGIWAP, zd1201_get_wap), - IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan), - IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan), - IW_HANDLER(SIOCSIWESSID, zd1201_set_essid), - IW_HANDLER(SIOCGIWESSID, zd1201_get_essid), - IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick), - IW_HANDLER(SIOCSIWRATE, zd1201_set_rate), - IW_HANDLER(SIOCGIWRATE, zd1201_get_rate), - IW_HANDLER(SIOCSIWRTS, zd1201_set_rts), - IW_HANDLER(SIOCGIWRTS, zd1201_get_rts), - IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag), - IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag), - IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry), - IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry), - IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode), - IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode), - IW_HANDLER(SIOCSIWPOWER, zd1201_set_power), - IW_HANDLER(SIOCGIWPOWER, zd1201_get_power), -}; - -static int zd1201_set_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value); -} - -static int zd1201_get_hostauth(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short hostauth; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth); - if (err) - return err; - rrq->value = hostauth; - rrq->fixed = 1; - - return 0; -} - -static int zd1201_auth_sta(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct sockaddr *sta = &wrqu->ap_addr; - struct zd1201 *zd = netdev_priv(dev); - unsigned char buffer[10]; - - if (!zd->ap) - return -EOPNOTSUPP; - - memcpy(buffer, sta->sa_data, ETH_ALEN); - *(short*)(buffer+6) = 0; /* 0==success, 1==failure */ - *(short*)(buffer+8) = 0; - - return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1); -} - -static int zd1201_set_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - - if (!zd->ap) - return -EOPNOTSUPP; - - return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value); -} - -static int zd1201_get_maxassoc(struct net_device *dev, - struct iw_request_info *info, union iwreq_data *wrqu, char *extra) -{ - struct iw_param *rrq = &wrqu->param; - struct zd1201 *zd = netdev_priv(dev); - short maxassoc; - int err; - - if (!zd->ap) - return -EOPNOTSUPP; - - err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc); - if (err) - return err; - rrq->value = maxassoc; - rrq->fixed = 1; - - return 0; -} - -static const iw_handler zd1201_private_handler[] = { - zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */ - zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */ - zd1201_auth_sta, /* ZD1201SIWAUTHSTA */ - NULL, /* nothing to get */ - zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */ - zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */ -}; - -static const struct iw_priv_args zd1201_private_args[] = { - { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "sethostauth" }, - { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" }, - { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "authstation" }, - { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_NONE, "setmaxassoc" }, - { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" }, -}; - -static const struct iw_handler_def zd1201_iw_handlers = { - .num_standard = ARRAY_SIZE(zd1201_iw_handler), - .num_private = ARRAY_SIZE(zd1201_private_handler), - .num_private_args = ARRAY_SIZE(zd1201_private_args), - .standard = zd1201_iw_handler, - .private = zd1201_private_handler, - .private_args = (struct iw_priv_args *) zd1201_private_args, - .get_wireless_stats = zd1201_get_wireless_stats, -}; - -static const struct net_device_ops zd1201_netdev_ops = { - .ndo_open = zd1201_net_open, - .ndo_stop = zd1201_net_stop, - .ndo_start_xmit = zd1201_hard_start_xmit, - .ndo_tx_timeout = zd1201_tx_timeout, - .ndo_set_rx_mode = zd1201_set_multicast, - .ndo_set_mac_address = zd1201_set_mac_address, - .ndo_validate_addr = eth_validate_addr, -}; - -static int zd1201_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct zd1201 *zd; - struct net_device *dev; - struct usb_device *usb; - int err; - short porttype; - char buf[IW_ESSID_MAX_SIZE+2]; - u8 addr[ETH_ALEN]; - - usb = interface_to_usbdev(interface); - - dev = alloc_etherdev(sizeof(*zd)); - if (!dev) - return -ENOMEM; - zd = netdev_priv(dev); - zd->dev = dev; - - zd->ap = ap; - zd->usb = usb; - zd->removed = 0; - init_waitqueue_head(&zd->rxdataq); - INIT_HLIST_HEAD(&zd->fraglist); - - err = zd1201_fw_upload(usb, zd->ap); - if (err) { - dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err); - goto err_zd; - } - - zd->endp_in = 1; - zd->endp_out = 1; - zd->endp_out2 = 2; - zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!zd->rx_urb || !zd->tx_urb) { - err = -ENOMEM; - goto err_zd; - } - - mdelay(100); - err = zd1201_drvr_start(zd); - if (err) - goto err_zd; - - err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312); - if (err) - goto err_start; - - err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, - ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11); - if (err) - goto err_start; - - dev->netdev_ops = &zd1201_netdev_ops; - dev->wireless_handlers = &zd1201_iw_handlers; - dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - strcpy(dev->name, "wlan%d"); - - err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN); - if (err) - goto err_start; - eth_hw_addr_set(dev, addr); - - /* Set wildcard essid to match zd->essid */ - *(__le16 *)buf = cpu_to_le16(0); - err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, - IW_ESSID_MAX_SIZE+2, 1); - if (err) - goto err_start; - - if (zd->ap) - porttype = ZD1201_PORTTYPE_AP; - else - porttype = ZD1201_PORTTYPE_BSS; - err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); - if (err) - goto err_start; - - SET_NETDEV_DEV(dev, &usb->dev); - - err = register_netdev(dev); - if (err) - goto err_start; - dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - dev->name); - - usb_set_intfdata(interface, zd); - zd1201_enable(zd); /* zd1201 likes to startup enabled, */ - zd1201_disable(zd); /* interfering with all the wifis in range */ - return 0; - -err_start: - /* Leave the device in reset state */ - zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); -err_zd: - usb_free_urb(zd->tx_urb); - usb_free_urb(zd->rx_urb); - free_netdev(dev); - return err; -} - -static void zd1201_disconnect(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - struct hlist_node *node2; - struct zd1201_frag *frag; - - if (!zd) - return; - usb_set_intfdata(interface, NULL); - - hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) { - hlist_del_init(&frag->fnode); - kfree_skb(frag->skb); - kfree(frag); - } - - if (zd->tx_urb) { - usb_kill_urb(zd->tx_urb); - usb_free_urb(zd->tx_urb); - } - if (zd->rx_urb) { - usb_kill_urb(zd->rx_urb); - usb_free_urb(zd->rx_urb); - } - - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } -} - -#ifdef CONFIG_PM - -static int zd1201_suspend(struct usb_interface *interface, - pm_message_t message) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - netif_device_detach(zd->dev); - - zd->was_enabled = zd->mac_enabled; - - if (zd->was_enabled) - return zd1201_disable(zd); - else - return 0; -} - -static int zd1201_resume(struct usb_interface *interface) -{ - struct zd1201 *zd = usb_get_intfdata(interface); - - if (!zd || !zd->dev) - return -ENODEV; - - netif_device_attach(zd->dev); - - if (zd->was_enabled) - return zd1201_enable(zd); - else - return 0; -} - -#else - -#define zd1201_suspend NULL -#define zd1201_resume NULL - -#endif - -static struct usb_driver zd1201_usb = { - .name = "zd1201", - .probe = zd1201_probe, - .disconnect = zd1201_disconnect, - .id_table = zd1201_table, - .suspend = zd1201_suspend, - .resume = zd1201_resume, - .disable_hub_initiated_lpm = 1, -}; - -module_usb_driver(zd1201_usb); diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h deleted file mode 100644 index c46ac87550d1b..0000000000000 --- a/drivers/net/wireless/zydas/zd1201.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org) - * - * Parts of this driver have been derived from a wlan-ng version - * modified by ZyDAS. - * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - */ - -#ifndef _INCLUDE_ZD1201_H_ -#define _INCLUDE_ZD1201_H_ - -#define ZD1201_NUMKEYS 4 -#define ZD1201_MAXKEYLEN 13 -#define ZD1201_MAXMULTI 16 -#define ZD1201_FRAGMAX 2500 -#define ZD1201_FRAGMIN 256 -#define ZD1201_RTSMAX 2500 - -#define ZD1201_RXSIZE 3000 - -struct zd1201 { - struct usb_device *usb; - int removed; - struct net_device *dev; - struct iw_statistics iwstats; - - int endp_in; - int endp_out; - int endp_out2; - struct urb *rx_urb; - struct urb *tx_urb; - - unsigned char rxdata[ZD1201_RXSIZE]; - int rxlen; - wait_queue_head_t rxdataq; - int rxdatas; - struct hlist_head fraglist; - unsigned char txdata[ZD1201_RXSIZE]; - - int ap; - char essid[IW_ESSID_MAX_SIZE+1]; - int essidlen; - int mac_enabled; - int was_enabled; - int monitor; - int encode_enabled; - int encode_restricted; - unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN]; - int encode_keylen[ZD1201_NUMKEYS]; -}; - -struct zd1201_frag { - struct hlist_node fnode; - int seq; - struct sk_buff *skb; -}; - -#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV -#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1 -#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2 -#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4 -#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1 - -#define ZD1201_FW_TIMEOUT (1000) - -#define ZD1201_TX_TIMEOUT (2000) - -#define ZD1201_USB_CMDREQ 0 -#define ZD1201_USB_RESREQ 1 - -#define ZD1201_CMDCODE_INIT 0x00 -#define ZD1201_CMDCODE_ENABLE 0x01 -#define ZD1201_CMDCODE_DISABLE 0x02 -#define ZD1201_CMDCODE_ALLOC 0x0a -#define ZD1201_CMDCODE_INQUIRE 0x11 -#define ZD1201_CMDCODE_SETRXRID 0x17 -#define ZD1201_CMDCODE_ACCESS 0x21 - -#define ZD1201_PACKET_EVENTSTAT 0x0 -#define ZD1201_PACKET_RXDATA 0x1 -#define ZD1201_PACKET_INQUIRE 0x2 -#define ZD1201_PACKET_RESOURCE 0x3 - -#define ZD1201_ACCESSBIT 0x0100 - -#define ZD1201_RID_CNFPORTTYPE 0xfc00 -#define ZD1201_RID_CNFOWNMACADDR 0xfc01 -#define ZD1201_RID_CNFDESIREDSSID 0xfc02 -#define ZD1201_RID_CNFOWNCHANNEL 0xfc03 -#define ZD1201_RID_CNFOWNSSID 0xfc04 -#define ZD1201_RID_CNFMAXDATALEN 0xfc07 -#define ZD1201_RID_CNFPMENABLED 0xfc09 -#define ZD1201_RID_CNFPMEPS 0xfc0a -#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c -#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23 -#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24 -#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25 -#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26 -#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27 -#define ZD1201_RID_CNFWEBFLAGS 0xfc28 -#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a -#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b -#define ZD1201_RID_CNFHOSTAUTH 0xfc2e -#define ZD1201_RID_CNFGROUPADDRESS 0xfc80 -#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82 -#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83 -#define ZD1201_RID_TXRATECNTL 0xfc84 -#define ZD1201_RID_PROMISCUOUSMODE 0xfc85 -#define ZD1201_RID_CNFBASICRATES 0xfcb3 -#define ZD1201_RID_AUTHENTICATESTA 0xfce3 -#define ZD1201_RID_CURRENTBSSID 0xfd42 -#define ZD1201_RID_COMMSQUALITY 0xfd43 -#define ZD1201_RID_CURRENTTXRATE 0xfd44 -#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0 -#define ZD1201_RID_CURRENTCHANNEL 0xfdc1 - -#define ZD1201_INQ_SCANRESULTS 0xf101 - -#define ZD1201_INF_LINKSTATUS 0xf200 -#define ZD1201_INF_ASSOCSTATUS 0xf201 -#define ZD1201_INF_AUTHREQ 0xf202 - -#define ZD1201_ASSOCSTATUS_STAASSOC 0x1 -#define ZD1201_ASSOCSTATUS_REASSOC 0x2 -#define ZD1201_ASSOCSTATUS_DISASSOC 0x3 -#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4 -#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5 - -#define ZD1201_PORTTYPE_IBSS 0 -#define ZD1201_PORTTYPE_BSS 1 -#define ZD1201_PORTTYPE_WDS 2 -#define ZD1201_PORTTYPE_PSEUDOIBSS 3 -#define ZD1201_PORTTYPE_AP 6 - -#define ZD1201_RATEB1 1 -#define ZD1201_RATEB2 2 -#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */ -#define ZD1201_RATEB11 8 - -#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0x0001 -#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 0x0002 - -#endif /* _INCLUDE_ZD1201_H_ */ From patchwork Mon Oct 23 13:19:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 13432848 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C19A4CDB474 for ; Mon, 23 Oct 2023 13:21:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=SqOYqtzQY2FwM+z+YIvEoM26yvjqibtbbHDfmsA/y9s=; b=IWMDY1JttqrfJx ZkW+K4Twjv1cPzwW+H72e9UtGPnpPt+yyjY3m43J8qjngeC8BVH+z25pD3LM+z4W8dVSS1ShDZrhR G7517Ff4mC18X0+xzoRAak+6S6jH35ddSGEzH0H/EBlO0E4j2dShlZdgMjom48Z97kw4EZUOhvHlj +gzBqSRayIJp/THMzEhoTmjKEmLJinFEI7+BnGXld+yaI3E1fZDor01oybQMHlfOR/JL1J+idHeAR DR+ep+I2dR0PogdPumpzXIICwQJohsHphW3TdGwNsNPnF9tpCeZnZGVgl3ga+pUmFncZdj5w9BYou +UhBSB7TZk424xIJu5+A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1quurl-007QT3-2e; Mon, 23 Oct 2023 13:21:09 +0000 Received: from sin.source.kernel.org ([2604:1380:40e1:4800::1]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1quurY-007QOH-39 for linux-arm-kernel@lists.infradead.org; Mon, 23 Oct 2023 13:21:07 +0000 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id B1323CE2490; Mon, 23 Oct 2023 13:20:54 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B5033C433D9; Mon, 23 Oct 2023 13:20:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1698067254; bh=4WVKISKuHonsID6Tr7gWujfI8PUL6m78F6A9q3ZhcH0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fDKGNa2xt2Ptpj/X+xvgPzK/TZ/UF1ga0COuJJLRuL8Kw7tD4qwTHmMqvwgeLs7sF 1CvQ0LuF6I8uNhhETfyg9jmk4agKLi6GB8xlr+xMx4RtKCnCqY+qdilqSCMx0MjFRk bt4kOcbU65DyUdmlY5/o5x57SrGe5yel1OApwhHoLpQXrkTxrcGyilyvDZbgL2ejpc y6bXNsHg7Sc4UIHlTvRM8ZnAWIkzqMy6BJGhTv7a7HFb3EhEciaqOzGnaJ8y6R4edY 5OOf4bVc2xQTxunq+xlKoQCJNqB6Y+NmGPPv0OtSdktGWVIfzEb7I2XuXm5exyQVT6 LJ1+hTbolZzGw== From: Arnd Bergmann To: Kalle Valo Subject: [PATCH 08/10] wifi: remove orphaned wl3501 driver Date: Mon, 23 Oct 2023 15:19:50 +0200 Message-Id: <20231023131953.2876682-9-arnd@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20231023131953.2876682-1-arnd@kernel.org> References: <20231023131953.2876682-1-arnd@kernel.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20231023_062057_614222_8C3EC967 X-CRM114-Status: GOOD ( 18.72 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Stanislaw Gruszka , Alexandre Belloni , linux-staging@lists.linux.dev, linux-kernel@vger.kernel.org, Arnd Bergmann , Geoff Levand , Greg Kroah-Hartman , linuxppc-dev , linux-wireless@vger.kernel.org, Claudiu Beznea , Geert Uytterhoeven , Pavel Machek , Gregory Greenman , Jakub Kicinski , Johannes Berg , Jeff Johnson , "David S . Miller" , linux-arm-kernel@lists.infradead.org, Larry Finger Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Arnd Bergmann Planet WL3501 is another PCMCIA driver for pre-802.11b interfaces (2Mbit/s) with incomplete CFG80211 support. This was marked as orphaned in 2017 but has been unmaintained for a long time before that. Signed-off-by: Arnd Bergmann --- MAINTAINERS | 5 - drivers/net/wireless/legacy/Kconfig | 10 - drivers/net/wireless/legacy/Makefile | 3 - drivers/net/wireless/legacy/wl3501.h | 615 ------- drivers/net/wireless/legacy/wl3501_cs.c | 2036 ----------------------- 5 files changed, 2669 deletions(-) delete mode 100644 drivers/net/wireless/legacy/wl3501.h delete mode 100644 drivers/net/wireless/legacy/wl3501_cs.c diff --git a/MAINTAINERS b/MAINTAINERS index 3123c955bb7f5..ee3c96de689c0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23221,11 +23221,6 @@ M: Miloslav Trmac S: Maintained F: drivers/input/misc/wistron_btns.c -WL3501 WIRELESS PCMCIA CARD DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/wl3501* - WMI BINARY MOF DRIVER M: Armin Wolf R: Thomas Weißschuh diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig index 1d77d53d64409..b4e0e516f2faa 100644 --- a/drivers/net/wireless/legacy/Kconfig +++ b/drivers/net/wireless/legacy/Kconfig @@ -1,13 +1,3 @@ -config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - help - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. - config USB_NET_RNDIS_WLAN tristate "Wireless RNDIS USB support" depends on USB diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile index d8705ccc5cf5d..1ed83f33ad20e 100644 --- a/drivers/net/wireless/legacy/Makefile +++ b/drivers/net/wireless/legacy/Makefile @@ -1,5 +1,2 @@ -# 16-bit wireless PCMCIA client drivers -obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o - obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o diff --git a/drivers/net/wireless/legacy/wl3501.h b/drivers/net/wireless/legacy/wl3501.h deleted file mode 100644 index 91f276dd22a1b..0000000000000 --- a/drivers/net/wireless/legacy/wl3501.h +++ /dev/null @@ -1,615 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __WL3501_H__ -#define __WL3501_H__ - -#include -#include - -/* define for WLA 2.0 */ -#define WL3501_BLKSZ 256 -/* - * ID for input Signals of DRIVER block - * bit[7-5] is block ID: 000 - * bit[4-0] is signal ID -*/ -enum wl3501_signals { - WL3501_SIG_ALARM, - WL3501_SIG_MD_CONFIRM, - WL3501_SIG_MD_IND, - WL3501_SIG_ASSOC_CONFIRM, - WL3501_SIG_ASSOC_IND, - WL3501_SIG_AUTH_CONFIRM, - WL3501_SIG_AUTH_IND, - WL3501_SIG_DEAUTH_CONFIRM, - WL3501_SIG_DEAUTH_IND, - WL3501_SIG_DISASSOC_CONFIRM, - WL3501_SIG_DISASSOC_IND, - WL3501_SIG_GET_CONFIRM, - WL3501_SIG_JOIN_CONFIRM, - WL3501_SIG_PWR_MGMT_CONFIRM, - WL3501_SIG_REASSOC_CONFIRM, - WL3501_SIG_REASSOC_IND, - WL3501_SIG_SCAN_CONFIRM, - WL3501_SIG_SET_CONFIRM, - WL3501_SIG_START_CONFIRM, - WL3501_SIG_RESYNC_CONFIRM, - WL3501_SIG_SITE_CONFIRM, - WL3501_SIG_SAVE_CONFIRM, - WL3501_SIG_RFTEST_CONFIRM, -/* - * ID for input Signals of MLME block - * bit[7-5] is block ID: 010 - * bit[4-0] is signal ID - */ - WL3501_SIG_ASSOC_REQ = 0x20, - WL3501_SIG_AUTH_REQ, - WL3501_SIG_DEAUTH_REQ, - WL3501_SIG_DISASSOC_REQ, - WL3501_SIG_GET_REQ, - WL3501_SIG_JOIN_REQ, - WL3501_SIG_PWR_MGMT_REQ, - WL3501_SIG_REASSOC_REQ, - WL3501_SIG_SCAN_REQ, - WL3501_SIG_SET_REQ, - WL3501_SIG_START_REQ, - WL3501_SIG_MD_REQ, - WL3501_SIG_RESYNC_REQ, - WL3501_SIG_SITE_REQ, - WL3501_SIG_SAVE_REQ, - WL3501_SIG_RF_TEST_REQ, - WL3501_SIG_MM_CONFIRM = 0x60, - WL3501_SIG_MM_IND, -}; - -enum wl3501_mib_attribs { - WL3501_MIB_ATTR_STATION_ID, - WL3501_MIB_ATTR_AUTH_ALGORITHMS, - WL3501_MIB_ATTR_AUTH_TYPE, - WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT, - WL3501_MIB_ATTR_CF_POLLABLE, - WL3501_MIB_ATTR_CFP_PERIOD, - WL3501_MIB_ATTR_CFPMAX_DURATION, - WL3501_MIB_ATTR_AUTH_RESP_TMOUT, - WL3501_MIB_ATTR_RX_DTIMS, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - WL3501_MIB_ATTR_PRIV_INVOKED, - WL3501_MIB_ATTR_WEP_DEFAULT_KEYS, - WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - WL3501_MIB_ATTR_MAC_ADDR, - WL3501_MIB_ATTR_GROUP_ADDRS, - WL3501_MIB_ATTR_RTS_THRESHOLD, - WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - WL3501_MIB_ATTR_FRAG_THRESHOLD, - WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME, - WL3501_MIB_ATTR_MAX_RX_LIFETIME, - WL3501_MIB_ATTR_MANUFACTURER_ID, - WL3501_MIB_ATTR_PRODUCT_ID, - WL3501_MIB_ATTR_TX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT, - WL3501_MIB_ATTR_FAILED_COUNT, - WL3501_MIB_ATTR_RX_FRAG_COUNT, - WL3501_MIB_ATTR_MULTICAST_RX_COUNT, - WL3501_MIB_ATTR_FCS_ERROR_COUNT, - WL3501_MIB_ATTR_RETRY_COUNT, - WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT, - WL3501_MIB_ATTR_RTS_SUCCESS_COUNT, - WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - WL3501_MIB_ATTR_PHY_TYPE, - WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT, - WL3501_MIB_ATTR_CURRENT_REG_DOMAIN, - WL3501_MIB_ATTR_SLOT_TIME, - WL3501_MIB_ATTR_CCA_TIME, - WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME, - WL3501_MIB_ATTR_TX_PLCP_DELAY, - WL3501_MIB_ATTR_RX_TX_SWITCH_TIME, - WL3501_MIB_ATTR_TX_RAMP_ON_TIME, - WL3501_MIB_ATTR_TX_RF_DELAY, - WL3501_MIB_ATTR_SIFS_TIME, - WL3501_MIB_ATTR_RX_RF_DELAY, - WL3501_MIB_ATTR_RX_PLCP_DELAY, - WL3501_MIB_ATTR_MAC_PROCESSING_DELAY, - WL3501_MIB_ATTR_TX_RAMP_OFF_TIME, - WL3501_MIB_ATTR_PREAMBLE_LEN, - WL3501_MIB_ATTR_PLCP_HEADER_LEN, - WL3501_MIB_ATTR_MPDU_DURATION_FACTOR, - WL3501_MIB_ATTR_AIR_PROPAGATION_TIME, - WL3501_MIB_ATTR_TEMP_TYPE, - WL3501_MIB_ATTR_CW_MIN, - WL3501_MIB_ATTR_CW_MAX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX, - WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX, - WL3501_MIB_ATTR_MPDU_MAX_LEN, - WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS, - WL3501_MIB_ATTR_CURRENT_TX_ANTENNA, - WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS, - WL3501_MIB_ATTR_DIVERSITY_SUPPORT, - WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS, - WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS, - WL3501_MIB_ATTR_TX_PWR_LEVEL1, - WL3501_MIB_ATTR_TX_PWR_LEVEL2, - WL3501_MIB_ATTR_TX_PWR_LEVEL3, - WL3501_MIB_ATTR_TX_PWR_LEVEL4, - WL3501_MIB_ATTR_TX_PWR_LEVEL5, - WL3501_MIB_ATTR_TX_PWR_LEVEL6, - WL3501_MIB_ATTR_TX_PWR_LEVEL7, - WL3501_MIB_ATTR_TX_PWR_LEVEL8, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - WL3501_MIB_ATTR_CURRENT_CHAN, - WL3501_MIB_ATTR_CCA_MODE_SUPPORTED, - WL3501_MIB_ATTR_CURRENT_CCA_MODE, - WL3501_MIB_ATTR_ED_THRESHOLD, - WL3501_MIB_ATTR_SINTHESIZER_LOCKED, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - WL3501_MIB_ATTR_DOZE_TURNON_TIME, - WL3501_MIB_ATTR_RCR33, - WL3501_MIB_ATTR_DEFAULT_CHAN, - WL3501_MIB_ATTR_SSID, - WL3501_MIB_ATTR_PWR_MGMT_ENABLE, - WL3501_MIB_ATTR_NET_CAPABILITY, - WL3501_MIB_ATTR_ROUTING, -}; - -enum wl3501_net_type { - WL3501_NET_TYPE_INFRA, - WL3501_NET_TYPE_ADHOC, - WL3501_NET_TYPE_ANY_BSS, -}; - -enum wl3501_scan_type { - WL3501_SCAN_TYPE_ACTIVE, - WL3501_SCAN_TYPE_PASSIVE, -}; - -enum wl3501_tx_result { - WL3501_TX_RESULT_SUCCESS, - WL3501_TX_RESULT_NO_BSS, - WL3501_TX_RESULT_RETRY_LIMIT, -}; - -enum wl3501_sys_type { - WL3501_SYS_TYPE_OPEN, - WL3501_SYS_TYPE_SHARE_KEY, -}; - -enum wl3501_status { - WL3501_STATUS_SUCCESS, - WL3501_STATUS_INVALID, - WL3501_STATUS_TIMEOUT, - WL3501_STATUS_REFUSED, - WL3501_STATUS_MANY_REQ, - WL3501_STATUS_ALREADY_BSS, -}; - -#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */ -#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */ -#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */ -#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */ - -#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */ -#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */ -#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */ -#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */ -#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */ -#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ -#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */ -#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */ - -#define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */ - -enum iw_mgmt_rate_labels { - IW_MGMT_RATE_LABEL_1MBIT = 2, - IW_MGMT_RATE_LABEL_2MBIT = 4, - IW_MGMT_RATE_LABEL_5_5MBIT = 11, - IW_MGMT_RATE_LABEL_11MBIT = 22, -}; - -enum iw_mgmt_info_element_ids { - IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */ - IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET, - IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */ - IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - /* 7-15: Reserved, unused */ - IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16, - /* 17-31 Reserved for challenge text extension */ - /* 32-255 Reserved, unused */ -}; - -struct iw_mgmt_info_element { - u8 id; /* one of enum iw_mgmt_info_element_ids, - but sizeof(enum) > sizeof(u8) :-( */ - u8 len; - u8 data[]; -} __packed; - -struct iw_mgmt_essid_pset { - struct iw_mgmt_info_element el; - u8 essid[IW_ESSID_MAX_SIZE]; -} __packed; - -/* - * According to 802.11 Wireless Networks, the definitive guide - O'Reilly - * Pg 75 - */ -#define IW_DATA_RATE_MAX_LABELS 8 - -struct iw_mgmt_data_rset { - struct iw_mgmt_info_element el; - u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS]; -} __packed; - -struct iw_mgmt_ds_pset { - struct iw_mgmt_info_element el; - u8 chan; -} __packed; - -struct iw_mgmt_cf_pset { - struct iw_mgmt_info_element el; - u8 cfp_count; - u8 cfp_period; - u16 cfp_max_duration; - u16 cfp_dur_remaining; -} __packed; - -struct iw_mgmt_ibss_pset { - struct iw_mgmt_info_element el; - u16 atim_window; -} __packed; - -struct wl3501_tx_hdr { - u16 tx_cnt; - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctrl; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_rx_hdr { - u16 rx_next_blk; - u16 rc_next_frame_blk; - u8 rx_blk_ctrl; - u8 rx_next_frame; - u8 rx_next_frame1; - u8 rssi; - char time[8]; - u8 signal; - u8 service; - u16 len; - u16 crc16; - u16 frame_ctrl; - u16 duration; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq; - u8 addr4[ETH_ALEN]; -}; - -struct wl3501_start_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 beacon_period; - u16 dtim_period; - u16 probe_delay; - u16 cap_info; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_data_rset bss_basic_rset; - struct iw_mgmt_data_rset operational_rset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_ibss_pset ibss_pset; -}; - -struct wl3501_assoc_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 timeout; - u16 cap_info; - u16 listen_interval; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_assoc_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_assoc_ind { - u16 next_blk; - u8 sig_id; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 timeout; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_auth_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 type; - u16 status; - u8 mac_addr[ETH_ALEN]; -}; - -struct wl3501_get_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_attrib; -}; - -struct wl3501_get_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 mib_status; - u16 mib_attrib; - u8 mib_value[100]; -}; - -struct wl3501_req { - u16 beacon_period; - u16 dtim_period; - u16 cap_info; - u8 bss_type; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - struct iw_mgmt_ds_pset ds_pset; - struct iw_mgmt_cf_pset cf_pset; - struct iw_mgmt_ibss_pset ibss_pset; - struct iw_mgmt_data_rset bss_basic_rset; -}; - -struct wl3501_join_req { - u16 next_blk; - u8 sig_id; - u8 reserved; - struct iw_mgmt_data_rset operational_rset; - u16 reserved2; - u16 timeout; - u16 probe_delay; - u8 timestamp[8]; - u8 local_time[8]; - struct wl3501_req req; -}; - -struct wl3501_join_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_pwr_mgmt_req { - u16 next_blk; - u8 sig_id; - u8 pwr_save; - u8 wake_up; - u8 receive_dtims; -}; - -struct wl3501_pwr_mgmt_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_scan_req { - u16 next_blk; - u8 sig_id; - u8 bss_type; - u16 probe_delay; - u16 min_chan_time; - u16 max_chan_time; - u8 chan_list[14]; - u8 bssid[ETH_ALEN]; - struct iw_mgmt_essid_pset ssid; - enum wl3501_scan_type scan_type; -}; - -struct wl3501_scan_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; - char timestamp[8]; - char localtime[8]; - struct wl3501_req req; - u8 rssi; -}; - -struct wl3501_start_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 status; -}; - -struct wl3501_md_req { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_ind { - u16 next_blk; - u8 sig_id; - u8 routing; - u16 data; - u16 size; - u8 reception; - u8 pri; - u8 service_class; - struct { - u8 daddr[ETH_ALEN]; - u8 saddr[ETH_ALEN]; - } addr; -}; - -struct wl3501_md_confirm { - u16 next_blk; - u8 sig_id; - u8 reserved; - u16 data; - u8 status; - u8 pri; - u8 service_class; -}; - -struct wl3501_resync_req { - u16 next_blk; - u8 sig_id; -}; - -/* Definitions for supporting clone adapters. */ -/* System Interface Registers (SIR space) */ -#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */ -#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */ -#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */ -#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */ -#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */ -#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */ -#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */ -#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */ - -/* Bits in GCR */ -#define WL3501_GCR_SWRESET ((u8)0x80) -#define WL3501_GCR_CORESET ((u8)0x40) -#define WL3501_GCR_DISPWDN ((u8)0x20) -#define WL3501_GCR_ECWAIT ((u8)0x10) -#define WL3501_GCR_ECINT ((u8)0x08) -#define WL3501_GCR_INT2EC ((u8)0x04) -#define WL3501_GCR_ENECINT ((u8)0x02) -#define WL3501_GCR_DAM ((u8)0x01) - -/* Bits in BSS (Bank Switching Select Register) */ -#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */ -#define WL3501_BSS_FPAGE1 ((u8)0x28) -#define WL3501_BSS_FPAGE2 ((u8)0x30) -#define WL3501_BSS_FPAGE3 ((u8)0x38) -#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */ -#define WL3501_BSS_SPAGE1 ((u8)0x08) -#define WL3501_BSS_SPAGE2 ((u8)0x10) -#define WL3501_BSS_SPAGE3 ((u8)0x18) - -/* Define Driver Interface */ -/* Refer IEEE 802.11 */ -/* Tx packet header, include PLCP and MPDU */ -/* Tx PLCP Header */ -struct wl3501_80211_tx_plcp_hdr { - u8 sync[16]; - u16 sfd; - u8 signal; - u8 service; - u16 len; - u16 crc16; -} __packed; - -struct wl3501_80211_tx_hdr { - struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr mac_hdr; -} __packed __aligned(2); - -/* - Reserve the beginning Tx space for descriptor use. - - TxBlockOffset --> *----*----*----*----* \ - (TxFreeDesc) | 0 | 1 | 2 | 3 | \ - | 4 | 5 | 6 | 7 | | - | 8 | 9 | 10 | 11 | TX_DESC * 20 - | 12 | 13 | 14 | 15 | | - | 16 | 17 | 18 | 19 | / - TxBufferBegin --> *----*----*----*----* / - (TxBufferHead) | | - (TxBufferTail) | | - | Send Buffer | - | | - | | - *-------------------* - TxBufferEnd -------------------------/ - -*/ - -struct wl3501_card { - int base_addr; - u8 mac_addr[ETH_ALEN]; - spinlock_t lock; - wait_queue_head_t wait; - struct wl3501_get_confirm sig_get_confirm; - struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm; - u16 tx_buffer_size; - u16 tx_buffer_head; - u16 tx_buffer_tail; - u16 tx_buffer_cnt; - u16 esbq_req_start; - u16 esbq_req_end; - u16 esbq_req_head; - u16 esbq_req_tail; - u16 esbq_confirm_start; - u16 esbq_confirm_end; - u16 esbq_confirm; - struct iw_mgmt_essid_pset essid; - struct iw_mgmt_essid_pset keep_essid; - u8 bssid[ETH_ALEN]; - int net_type; - char nick[32]; - char card_name[32]; - char firmware_date[32]; - u8 chan; - u8 cap_info; - u16 start_seg; - u16 bss_cnt; - u16 join_sta_bss; - u8 rssi; - u8 adhoc_times; - u8 reg_domain; - u8 version[2]; - struct wl3501_scan_confirm bss_set[20]; - - struct iw_statistics wstats; - struct iw_spy_data spy_data; - struct iw_public_data wireless_data; - struct pcmcia_device *p_dev; -}; -#endif diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c deleted file mode 100644 index c45c4b7cbbaf1..0000000000000 --- a/drivers/net/wireless/legacy/wl3501_cs.c +++ /dev/null @@ -1,2036 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WL3501 Wireless LAN PCMCIA Card Driver for Linux - * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw - * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo - * Wireless extensions in 2.4 by Gustavo Niemeyer - * - * References used by Fox Chen while writing the original driver for 2.0.30: - * - * 1. WL24xx packet drivers (tooasm.asm) - * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO - * 3. IEEE 802.11 - * 4. Linux network driver (/usr/src/linux/drivers/net) - * 5. ISA card driver - wl24.c - * 6. Linux PCMCIA skeleton driver - skeleton.c - * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c - * - * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12 - * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode. - * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null - * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct - * ETHER/IP/UDP/TCP header, and acknowledgement overhead) - * - * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode, - * 173 Kbytes/s in TCP. - * - * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode - * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#include "wl3501.h" - -#ifndef __i386__ -#define slow_down_io() -#endif - -/* For rough constant delay */ -#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); } - - - -#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); } -#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); } -#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); } - -#define WL3501_RELEASE_TIMEOUT (25 * HZ) -#define WL3501_MAX_ADHOC_TRIES 16 - -#define WL3501_RESUME 0 -#define WL3501_SUSPEND 1 - -static int wl3501_config(struct pcmcia_device *link); -static void wl3501_release(struct pcmcia_device *link); - -static const struct { - int reg_domain; - int min, max, deflt; -} iw_channel_table[] = { - { - .reg_domain = IW_REG_DOMAIN_FCC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_DOC, - .min = 1, - .max = 11, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ETSI, - .min = 1, - .max = 13, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_SPAIN, - .min = 10, - .max = 11, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_FRANCE, - .min = 10, - .max = 13, - .deflt = 10, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK, - .min = 14, - .max = 14, - .deflt = 14, - }, - { - .reg_domain = IW_REG_DOMAIN_MKK1, - .min = 1, - .max = 14, - .deflt = 1, - }, - { - .reg_domain = IW_REG_DOMAIN_ISRAEL, - .min = 3, - .max = 9, - .deflt = 9, - }, -}; - -/** - * iw_valid_channel - validate channel in regulatory domain - * @reg_domain: regulatory domain - * @channel: channel to validate - * - * Returns 0 if invalid in the specified regulatory domain, non-zero if valid. - */ -static int iw_valid_channel(int reg_domain, int channel) -{ - int i, rc = 0; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = channel >= iw_channel_table[i].min && - channel <= iw_channel_table[i].max; - break; - } - return rc; -} - -/** - * iw_default_channel - get default channel for a regulatory domain - * @reg_domain: regulatory domain - * - * Returns the default channel for a regulatory domain - */ -static int iw_default_channel(int reg_domain) -{ - int i, rc = 1; - - for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++) - if (reg_domain == iw_channel_table[i].reg_domain) { - rc = iw_channel_table[i].deflt; - break; - } - return rc; -} - -static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id, - struct iw_mgmt_info_element *el, - void *value, int len) -{ - el->id = id; - el->len = len; - memcpy(el->data, value, len); -} - -static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, - struct iw_mgmt_info_element *from) -{ - iw_set_mgmt_info_element(from->id, to, from->data, from->len); -} - -static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) -{ - wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); -} - -/* - * Get Ethernet MAC address. - * - * WARNING: We switch to FPAGE0 and switc back again. - * Making sure there is no other WL function beening called by ISR. - */ -static int wl3501_get_flash_mac_addr(struct wl3501_card *this) -{ - int base_addr = this->base_addr; - - /* get MAC addr */ - wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */ - wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */ - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */ - - /* wait for reading EEPROM */ - WL3501_NOPLOOP(100); - this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->reg_domain = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS); - wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL); - wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); - WL3501_NOPLOOP(100); - this->version[0] = inb(base_addr + WL3501_NIC_IODPA); - WL3501_NOPLOOP(100); - this->version[1] = inb(base_addr + WL3501_NIC_IODPA); - /* switch to SRAM Page 0 (for safety) */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - - /* The MAC addr should be 00:60:... */ - return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60; -} - -/** - * wl3501_set_to_wla - Move 'size' bytes from PC to card - * @this: Card - * @dest: Card addressing space - * @src: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from PC to card. (Shouldn't be interrupted) - */ -static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH); - - /* rep out to Port A */ - wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size); -} - -/** - * wl3501_get_from_wla - Move 'size' bytes from card to PC - * @this: Card - * @src: Card addressing space - * @dest: PC addressing space - * @size: Bytes to move - * - * Move 'size' bytes from card to PC. (Shouldn't be interrupted) - */ -static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, - int size) -{ - /* switch to SRAM Page 0 */ - wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 : - WL3501_BSS_SPAGE0); - /* set LMAL and LMAH */ - wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL); - wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH); - - /* rep get from Port A */ - insb(this->base_addr + WL3501_NIC_IODPA, dest, size); -} - -/* - * Get/Allocate a free Tx Data Buffer - * - * *--------------*-----------------*----------------------------------* - * | PLCP | MAC Header | DST SRC Data ... | - * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) | - * *--------------*-----------------*----------------------------------* - * \ \- IEEE 802.11 -/ \-------------- len --------------/ - * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ - * - * Return = Position in Card - */ -static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) -{ - u16 next, blk_cnt = 0, zero = 0; - u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len; - u16 ret = 0; - - if (full_len > this->tx_buffer_cnt * 254) - goto out; - ret = this->tx_buffer_head; - while (full_len) { - if (full_len < 254) - full_len = 0; - else - full_len -= 254; - wl3501_get_from_wla(this, this->tx_buffer_head, &next, - sizeof(next)); - if (!full_len) - wl3501_set_to_wla(this, this->tx_buffer_head, &zero, - sizeof(zero)); - this->tx_buffer_head = next; - blk_cnt++; - /* if buffer is not enough */ - if (!next && full_len) { - this->tx_buffer_head = ret; - ret = 0; - goto out; - } - } - this->tx_buffer_cnt -= blk_cnt; -out: - return ret; -} - -/* - * Free an allocated Tx Buffer. ptr must be correct position. - */ -static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr) -{ - /* check if all space is not free */ - if (!this->tx_buffer_head) - this->tx_buffer_head = ptr; - else - wl3501_set_to_wla(this, this->tx_buffer_tail, - &ptr, sizeof(ptr)); - while (ptr) { - u16 next; - - this->tx_buffer_cnt++; - wl3501_get_from_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; - ptr = next; - } -} - -static int wl3501_esbq_req_test(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr) -{ - u16 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2); - wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp)); - this->esbq_req_head += 4; - if (this->esbq_req_head >= this->esbq_req_end) - this->esbq_req_head = this->esbq_req_start; -} - -static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size) -{ - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sig_size); - if (ptr) { - wl3501_set_to_wla(this, ptr, sig, sig_size); - wl3501_esbq_req(this, &ptr); - rc = 0; - } - } - return rc; -} - -static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf) -{ - struct wl3501_get_req sig = { - .sig_id = WL3501_SIG_GET_REQ, - .mib_attrib = index, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_get_confirm.mib_status = 255; - rc = 0; - } - } - spin_unlock_irqrestore(&this->lock, flags); - - return rc; -} - -static int wl3501_get_mib_value(struct wl3501_card *this, u8 index, - void *bf, int size) -{ - int rc; - - rc = wl3501_request_mib(this, index, bf); - if (rc) - return rc; - - rc = wait_event_interruptible(this->wait, - this->sig_get_confirm.mib_status != 255); - if (rc) - return rc; - - memcpy(bf, this->sig_get_confirm.mib_value, size); - return 0; -} - -static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend) -{ - struct wl3501_pwr_mgmt_req sig = { - .sig_id = WL3501_SIG_PWR_MGMT_REQ, - .pwr_save = suspend, - .wake_up = !suspend, - .receive_dtims = 10, - }; - unsigned long flags; - int rc = -EIO; - - spin_lock_irqsave(&this->lock, flags); - if (wl3501_esbq_req_test(this)) { - u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig)); - if (ptr) { - wl3501_set_to_wla(this, ptr, &sig, sizeof(sig)); - wl3501_esbq_req(this, &ptr); - this->sig_pwr_mgmt_confirm.status = 255; - spin_unlock_irqrestore(&this->lock, flags); - rc = wait_event_interruptible(this->wait, - this->sig_pwr_mgmt_confirm.status != 255); - printk(KERN_INFO "%s: %s status=%d\n", __func__, - suspend ? "suspend" : "resume", - this->sig_pwr_mgmt_confirm.status); - goto out; - } - } - spin_unlock_irqrestore(&this->lock, flags); -out: - return rc; -} - -/** - * wl3501_send_pkt - Send a packet. - * @this: Card - * @data: Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr, - * data[6] - data[11] is Src MAC Addr) - * @len: Packet length - * Ref: IEEE 802.11 - */ -static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len) -{ - u16 bf, sig_bf, next, tmplen, pktlen; - struct wl3501_md_req sig = { - .sig_id = WL3501_SIG_MD_REQ, - }; - size_t sig_addr_len = sizeof(sig.addr); - u8 *pdata = (char *)data; - int rc = -EIO; - - if (wl3501_esbq_req_test(this)) { - sig_bf = wl3501_get_tx_buffer(this, sizeof(sig)); - rc = -ENOMEM; - if (!sig_bf) /* No free buffer available */ - goto out; - bf = wl3501_get_tx_buffer(this, len + 26 + 24); - if (!bf) { - /* No free buffer available */ - wl3501_free_tx_buffer(this, sig_bf); - goto out; - } - rc = 0; - memcpy(&sig.addr, pdata, sig_addr_len); - pktlen = len - sig_addr_len; - pdata += sig_addr_len; - sig.data = bf; - if (((*pdata) * 256 + (*(pdata + 1))) > 1500) { - u8 addr4[ETH_ALEN] = { - [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00, - }; - - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - addr4, sizeof(addr4)); - sig.size = pktlen + 24 + 4 + 6; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr); - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, - bf + 2 + sizeof(struct wl3501_tx_hdr), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } else { - sig.size = pktlen + 24 + 4 - 2; - pdata += 2; - pktlen -= 2; - if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) { - tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6; - pktlen -= tmplen; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2 + - offsetof(struct wl3501_tx_hdr, addr4), - pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - while (pktlen > 0) { - if (pktlen > 254) { - tmplen = 254; - pktlen -= 254; - } else { - tmplen = pktlen; - pktlen = 0; - } - wl3501_set_to_wla(this, bf + 2, pdata, tmplen); - pdata += tmplen; - wl3501_get_from_wla(this, bf, &next, sizeof(next)); - bf = next; - } - wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig)); - wl3501_esbq_req(this, &sig_bf); - } -out: - return rc; -} - -static int wl3501_mgmt_resync(struct wl3501_card *this) -{ - struct wl3501_resync_req sig = { - .sig_id = WL3501_SIG_RESYNC_REQ, - }; - - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static inline int wl3501_fw_bss_type(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA : - WL3501_NET_TYPE_ADHOC; -} - -static inline int wl3501_fw_cap_info(struct wl3501_card *this) -{ - return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS : - WL3501_MGMT_CAPABILITY_IBSS; -} - -static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time) -{ - struct wl3501_scan_req sig = { - .sig_id = WL3501_SIG_SCAN_REQ, - .scan_type = WL3501_SCAN_TYPE_ACTIVE, - .probe_delay = 0x10, - .min_chan_time = chan_time, - .max_chan_time = chan_time, - .bss_type = wl3501_fw_bss_type(this), - }; - - this->bss_cnt = this->join_sta_bss = 0; - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas) -{ - struct wl3501_join_req sig = { - .sig_id = WL3501_SIG_JOIN_REQ, - .timeout = 10, - .req.ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - }; - - memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req)); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_start(struct wl3501_card *this) -{ - struct wl3501_start_req sig = { - .sig_id = WL3501_SIG_START_REQ, - .beacon_period = 400, - .dtim_period = 1, - .ds_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET, - .len = 1, - }, - .chan = this->chan, - }, - .bss_basic_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .operational_rset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES, - .len = 2, - }, - .data_rate_labels = { - [0] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_1MBIT, - [1] = IW_MGMT_RATE_LABEL_MANDATORY | - IW_MGMT_RATE_LABEL_2MBIT, - }, - }, - .ibss_pset = { - .el = { - .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET, - .len = 2, - }, - .atim_window = 10, - }, - .bss_type = wl3501_fw_bss_type(this), - .cap_info = wl3501_fw_cap_info(this), - }; - - iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el); - iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr) -{ - u16 i = 0; - int matchflag = 0; - struct wl3501_scan_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - pr_debug("success"); - if ((this->net_type == IW_MODE_INFRA && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) || - (this->net_type == IW_MODE_ADHOC && - (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) || - this->net_type == IW_MODE_AUTO) { - if (!this->essid.el.len) - matchflag = 1; - else if (this->essid.el.len == 3 && - !memcmp(this->essid.essid, "ANY", 3)) - matchflag = 1; - else if (this->essid.el.len != sig.req.ssid.el.len) - matchflag = 0; - else if (memcmp(this->essid.essid, sig.req.ssid.essid, - this->essid.el.len)) - matchflag = 0; - else - matchflag = 1; - if (matchflag) { - for (i = 0; i < this->bss_cnt; i++) { - if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid, - sig.req.bssid)) { - matchflag = 0; - break; - } - } - } - if (matchflag && (i < 20)) { - memcpy(&this->bss_set[i].req, - &sig.req, sizeof(sig.req)); - this->bss_cnt++; - this->rssi = sig.rssi; - this->bss_set[i].rssi = sig.rssi; - } - } - } else if (sig.status == WL3501_STATUS_TIMEOUT) { - pr_debug("timeout"); - this->join_sta_bss = 0; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -/** - * wl3501_block_interrupt - Mask interrupt from SUTRO - * @this: Card - * - * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_block_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC | - WL3501_GCR_ENECINT)); - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_unblock_interrupt - Enable interrupt from SUTRO - * @this: Card - * - * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST) - * Return: 1 if interrupt is originally enabled - */ -static int wl3501_unblock_interrupt(struct wl3501_card *this) -{ - u8 old = inb(this->base_addr + WL3501_NIC_GCR); - u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) | - WL3501_GCR_ENECINT; - - wl3501_outb(new, this->base_addr + WL3501_NIC_GCR); - return old & WL3501_GCR_ENECINT; -} - -/** - * wl3501_receive - Receive data from Receive Queue. - * - * Receive data from Receive Queue. - * - * @this: card - * @bf: address of host - * @size: size of buffer. - */ -static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size) -{ - u16 next_addr, next_addr1; - u8 *data = bf + 12; - - size -= 12; - wl3501_get_from_wla(this, this->start_seg + 2, - &next_addr, sizeof(next_addr)); - if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), data, - WL3501_BLKSZ - - sizeof(struct wl3501_rx_hdr)); - size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr); - } else { - wl3501_get_from_wla(this, - this->start_seg + - sizeof(struct wl3501_rx_hdr), - data, size); - size = 0; - } - while (size > 0) { - if (size > WL3501_BLKSZ - 5) { - wl3501_get_from_wla(this, next_addr + 5, data, - WL3501_BLKSZ - 5); - size -= WL3501_BLKSZ - 5; - data += WL3501_BLKSZ - 5; - wl3501_get_from_wla(this, next_addr + 2, &next_addr1, - sizeof(next_addr1)); - next_addr = next_addr1; - } else { - wl3501_get_from_wla(this, next_addr + 5, data, size); - size = 0; - } - } - return 0; -} - -static void wl3501_esbq_req_free(struct wl3501_card *this) -{ - u8 tmp; - u16 addr; - - if (this->esbq_req_head == this->esbq_req_tail) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp)); - if (!(tmp & 0x80)) - goto out; - wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr)); - wl3501_free_tx_buffer(this, addr); - this->esbq_req_tail += 4; - if (this->esbq_req_tail >= this->esbq_req_end) - this->esbq_req_tail = this->esbq_req_start; -out: - return; -} - -static int wl3501_esbq_confirm(struct wl3501_card *this) -{ - u8 tmp; - - wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - return tmp & 0x80; -} - -static void wl3501_online(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", - dev->name, this->bssid); - netif_wake_queue(dev); -} - -static void wl3501_esbq_confirm_done(struct wl3501_card *this) -{ - u8 tmp = 0; - - wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp)); - this->esbq_confirm += 4; - if (this->esbq_confirm >= this->esbq_confirm_end) - this->esbq_confirm = this->esbq_confirm_start; -} - -static int wl3501_mgmt_auth(struct wl3501_card *this) -{ - struct wl3501_auth_req sig = { - .sig_id = WL3501_SIG_AUTH_REQ, - .type = WL3501_SYS_TYPE_OPEN, - .timeout = 1000, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static int wl3501_mgmt_association(struct wl3501_card *this) -{ - struct wl3501_assoc_req sig = { - .sig_id = WL3501_SIG_ASSOC_REQ, - .timeout = 1000, - .listen_interval = 5, - .cap_info = this->cap_info, - }; - - pr_debug("entry"); - memcpy(sig.mac_addr, this->bssid, ETH_ALEN); - return wl3501_esbq_exec(this, &sig, sizeof(sig)); -} - -static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_join_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) { - if (this->net_type == IW_MODE_INFRA) { - if (this->join_sta_bss < this->bss_cnt) { - const int i = this->join_sta_bss; - memcpy(this->bssid, - this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_mgmt_auth(this); - } - } else { - const int i = this->join_sta_bss; - - memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN); - this->chan = this->bss_set[i].req.ds_pset.chan; - iw_copy_mgmt_info_element(&this->keep_essid.el, - &this->bss_set[i].req.ssid.el); - wl3501_online(dev); - } - } else { - int i; - this->join_sta_bss++; - for (i = this->join_sta_bss; i < this->bss_cnt; i++) - if (!wl3501_mgmt_join(this, i)) - break; - this->join_sta_bss = i; - if (this->join_sta_bss == this->bss_cnt) { - if (this->net_type == IW_MODE_INFRA) - wl3501_mgmt_scan(this, 100); - else { - this->adhoc_times++; - if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES) - wl3501_mgmt_start(this); - else - wl3501_mgmt_scan(this, 100); - } - } - } -} - -static inline void wl3501_alarm_interrupt(struct net_device *dev, - struct wl3501_card *this) -{ - if (this->net_type == IW_MODE_INFRA) { - printk(KERN_INFO "Wireless LAN offline\n"); - netif_stop_queue(dev); - wl3501_mgmt_resync(this); - } -} - -static inline void wl3501_md_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_md_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - wl3501_free_tx_buffer(this, sig.data); - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -static inline void wl3501_md_ind_interrupt(struct net_device *dev, - struct wl3501_card *this, u16 addr) -{ - struct wl3501_md_ind sig; - struct sk_buff *skb; - u8 rssi, addr4[ETH_ALEN]; - u16 pkt_len; - - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - this->start_seg = sig.data; - wl3501_get_from_wla(this, - sig.data + offsetof(struct wl3501_rx_hdr, rssi), - &rssi, sizeof(rssi)); - this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255; - - wl3501_get_from_wla(this, - sig.data + - offsetof(struct wl3501_rx_hdr, addr4), - &addr4, sizeof(addr4)); - if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && - addr4[2] == 0x03 && addr4[4] == 0x00)) { - printk(KERN_INFO "Unsupported packet type!\n"); - return; - } - pkt_len = sig.size + 12 - 24 - 4 - 6; - - skb = dev_alloc_skb(pkt_len + 5); - - if (!skb) { - printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n", - dev->name, pkt_len); - dev->stats.rx_dropped++; - } else { - skb->dev = dev; - skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */ - skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr, - sizeof(sig.addr)); - wl3501_receive(this, skb->data, pkt_len); - skb_put(skb, pkt_len); - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - netif_rx(skb); - } -} - -static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this, - u16 addr, void *sig, int size) -{ - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - wake_up(&this->wait); -} - -static inline void wl3501_start_confirm_interrupt(struct net_device *dev, - struct wl3501_card *this, - u16 addr) -{ - struct wl3501_start_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - if (sig.status == WL3501_STATUS_SUCCESS) - netif_wake_queue(dev); -} - -static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev, - u16 addr) -{ - struct wl3501_card *this = netdev_priv(dev); - struct wl3501_assoc_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_online(dev); -} - -static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this, - u16 addr) -{ - struct wl3501_auth_confirm sig; - - pr_debug("entry"); - wl3501_get_from_wla(this, addr, &sig, sizeof(sig)); - - if (sig.status == WL3501_STATUS_SUCCESS) - wl3501_mgmt_association(this); - else - wl3501_mgmt_resync(this); -} - -static inline void wl3501_rx_interrupt(struct net_device *dev) -{ - int morepkts; - u16 addr; - u8 sig_id; - struct wl3501_card *this = netdev_priv(dev); - - pr_debug("entry"); -loop: - morepkts = 0; - if (!wl3501_esbq_confirm(this)) - goto free; - wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr)); - wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id)); - - switch (sig_id) { - case WL3501_SIG_DEAUTH_IND: - case WL3501_SIG_DISASSOC_IND: - case WL3501_SIG_ALARM: - wl3501_alarm_interrupt(dev, this); - break; - case WL3501_SIG_MD_CONFIRM: - wl3501_md_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_MD_IND: - wl3501_md_ind_interrupt(dev, this, addr); - break; - case WL3501_SIG_GET_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_get_confirm, - sizeof(this->sig_get_confirm)); - break; - case WL3501_SIG_PWR_MGMT_CONFIRM: - wl3501_get_confirm_interrupt(this, addr, - &this->sig_pwr_mgmt_confirm, - sizeof(this->sig_pwr_mgmt_confirm)); - break; - case WL3501_SIG_START_CONFIRM: - wl3501_start_confirm_interrupt(dev, this, addr); - break; - case WL3501_SIG_SCAN_CONFIRM: - wl3501_mgmt_scan_confirm(this, addr); - break; - case WL3501_SIG_JOIN_CONFIRM: - wl3501_mgmt_join_confirm(dev, addr); - break; - case WL3501_SIG_ASSOC_CONFIRM: - wl3501_assoc_confirm_interrupt(dev, addr); - break; - case WL3501_SIG_AUTH_CONFIRM: - wl3501_auth_confirm_interrupt(this, addr); - break; - case WL3501_SIG_RESYNC_CONFIRM: - wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */ - break; - } - wl3501_esbq_confirm_done(this); - morepkts = 1; - /* free request if necessary */ -free: - wl3501_esbq_req_free(this); - if (morepkts) - goto loop; -} - -static inline void wl3501_ack_interrupt(struct wl3501_card *this) -{ - wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR); -} - -/** - * wl3501_interrupt - Hardware interrupt from card. - * @irq: Interrupt number - * @dev_id: net_device - * - * We must acknowledge the interrupt as soon as possible, and block the - * interrupt from the same card immediately to prevent re-entry. - * - * Before accessing the Control_Status_Block, we must lock SUTRO first. - * On the other hand, to prevent SUTRO from malfunctioning, we must - * unlock the SUTRO as soon as possible. - */ -static irqreturn_t wl3501_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct wl3501_card *this; - - this = netdev_priv(dev); - spin_lock(&this->lock); - wl3501_ack_interrupt(this); - wl3501_block_interrupt(this); - wl3501_rx_interrupt(dev); - wl3501_unblock_interrupt(this); - spin_unlock(&this->lock); - - return IRQ_HANDLED; -} - -static int wl3501_reset_board(struct wl3501_card *this) -{ - u8 tmp = 0; - int i, rc = 0; - - /* Coreset */ - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR); - - /* Reset SRAM 0x480 to zero */ - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - - /* Start up */ - wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR); - - WL3501_NOPLOOP(1024 * 50); - - wl3501_unblock_interrupt(this); /* acme: was commented */ - - /* Polling Self_Test_Status */ - for (i = 0; i < 10000; i++) { - wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp)); - - if (tmp == 'W') { - /* firmware complete all test successfully */ - tmp = 'A'; - wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp)); - goto out; - } - WL3501_NOPLOOP(10); - } - printk(KERN_WARNING "%s: failed to reset the board!\n", __func__); - rc = -ENODEV; -out: - return rc; -} - -static int wl3501_init_firmware(struct wl3501_card *this) -{ - u16 ptr, next; - int rc = wl3501_reset_board(this); - - if (rc) - goto fail; - this->card_name[0] = '\0'; - wl3501_get_from_wla(this, 0x1a00, - this->card_name, sizeof(this->card_name)); - this->card_name[sizeof(this->card_name) - 1] = '\0'; - this->firmware_date[0] = '\0'; - wl3501_get_from_wla(this, 0x1a40, - this->firmware_date, sizeof(this->firmware_date)); - this->firmware_date[sizeof(this->firmware_date) - 1] = '\0'; - /* Switch to SRAM Page 0 */ - wl3501_switch_page(this, WL3501_BSS_SPAGE0); - /* Read parameter from card */ - wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2); - wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2); - wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2); - wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2); - wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2); - wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2); - this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start; - this->esbq_req_end += this->esbq_req_start; - this->esbq_confirm = this->esbq_confirm_start; - this->esbq_confirm_end += this->esbq_confirm_start; - /* Initial Tx Buffer */ - this->tx_buffer_cnt = 1; - ptr = this->tx_buffer_head; - next = ptr + WL3501_BLKSZ; - while ((next - this->tx_buffer_head) < this->tx_buffer_size) { - this->tx_buffer_cnt++; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - ptr = next; - next = ptr + WL3501_BLKSZ; - } - rc = 0; - next = 0; - wl3501_set_to_wla(this, ptr, &next, sizeof(next)); - this->tx_buffer_tail = ptr; -out: - return rc; -fail: - printk(KERN_WARNING "%s: failed!\n", __func__); - goto out; -} - -static int wl3501_close(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - link->open--; - - /* Stop wl3501_hard_start_xmit() from now on */ - netif_stop_queue(dev); - wl3501_ack_interrupt(this); - - /* Mask interrupts from the SUTRO */ - wl3501_block_interrupt(this); - - printk(KERN_INFO "%s: WL3501 closed\n", dev->name); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -/** - * wl3501_reset - Reset the SUTRO. - * @dev: network device - * - * It is almost the same as wl3501_open(). In fact, we may just wl3501_close() - * and wl3501_open() again, but I wouldn't like to free_irq() when the driver - * is running. It seems to be dangerous. - */ -static int wl3501_reset(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -ENODEV; - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wl3501_block_interrupt(this); - - if (wl3501_init_firmware(this)) { - printk(KERN_WARNING "%s: Can't initialize Firmware!\n", - dev->name); - /* Free IRQ, and mark IRQ as unused */ - free_irq(dev->irq, dev); - goto out; - } - - /* - * Queue has to be started only when the Card is Started - */ - netif_stop_queue(dev); - this->adhoc_times = 0; - wl3501_ack_interrupt(this); - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - pr_debug("%s: device reset", dev->name); - rc = 0; -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -} - -static void wl3501_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct net_device_stats *stats = &dev->stats; - int rc; - - stats->tx_errors++; - rc = wl3501_reset(dev); - if (rc) - printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n", - dev->name, rc); - else { - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); - } -} - -/* - * Return : 0 - OK - * 1 - Could not transmit (dev_queue_xmit will queue it) - * and try to sent it later - */ -static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - int enabled, rc; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - enabled = wl3501_block_interrupt(this); - rc = wl3501_send_pkt(this, skb->data, skb->len); - if (enabled) - wl3501_unblock_interrupt(this); - if (rc) { - ++dev->stats.tx_dropped; - netif_stop_queue(dev); - } else { - ++dev->stats.tx_packets; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - - if (this->tx_buffer_cnt < 2) - netif_stop_queue(dev); - } - spin_unlock_irqrestore(&this->lock, flags); - return NETDEV_TX_OK; -} - -static int wl3501_open(struct net_device *dev) -{ - int rc = -ENODEV; - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link; - link = this->p_dev; - - spin_lock_irqsave(&this->lock, flags); - if (!pcmcia_dev_present(link)) - goto out; - netif_device_attach(dev); - link->open++; - - /* Initial WL3501 firmware */ - pr_debug("%s: Initialize WL3501 firmware...", dev->name); - if (wl3501_init_firmware(this)) - goto fail; - /* Initial device variables */ - this->adhoc_times = 0; - /* Acknowledge Interrupt, for cleaning last state */ - wl3501_ack_interrupt(this); - - /* Enable interrupt from card after all */ - wl3501_unblock_interrupt(this); - wl3501_mgmt_scan(this, 100); - rc = 0; - pr_debug("%s: WL3501 opened", dev->name); - printk(KERN_INFO "%s: Card Name: %s\n" - "%s: Firmware Date: %s\n", - dev->name, this->card_name, - dev->name, this->firmware_date); -out: - spin_unlock_irqrestore(&this->lock, flags); - return rc; -fail: - printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name); - goto out; -} - -static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev) -{ - struct wl3501_card *this = netdev_priv(dev); - struct iw_statistics *wstats = &this->wstats; - u32 value; /* size checked: it is u32 */ - - memset(wstats, 0, sizeof(*wstats)); - wstats->status = netif_running(dev); - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT, - &value, sizeof(value))) - wstats->discard.code += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT, - &value, sizeof(value))) - wstats->discard.retries = value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT, - &value, sizeof(value))) - wstats->discard.misc += value; - return wstats; -} - -/** - * wl3501_detach - deletes a driver "instance" - * @link: FILL_IN - * - * This deletes a driver "instance". The device is de-registered with Card - * Services. If it has been released, all local data structures are freed. - * Otherwise, the structures will be freed when the device is released. - */ -static void wl3501_detach(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - /* If the device is currently configured and active, we won't actually - * delete it yet. Instead, it is marked so that when the release() - * function is called, that will trigger a proper detach(). */ - - while (link->open > 0) - wl3501_close(dev); - - netif_device_detach(dev); - wl3501_release(link); - - unregister_netdev(dev); - free_netdev(dev); -} - -static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - strscpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name)); - return 0; -} - -static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int channel = wrqu->freq.m; - int rc = -EINVAL; - - if (iw_valid_channel(this->reg_domain, channel)) { - this->chan = channel; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->freq.m = 100000 * - ieee80211_channel_to_frequency(this->chan, NL80211_BAND_2GHZ); - wrqu->freq.e = 1; - return 0; -} - -static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int rc = -EINVAL; - - if (wrqu->mode == IW_MODE_INFRA || - wrqu->mode == IW_MODE_ADHOC || - wrqu->mode == IW_MODE_AUTO) { - struct wl3501_card *this = netdev_priv(dev); - - this->net_type = wrqu->mode; - rc = wl3501_reset(dev); - } - return rc; -} - -static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->mode = this->net_type; - return 0; -} - -static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->sens.value = this->rssi; - wrqu->sens.disabled = !wrqu->sens.value; - wrqu->sens.fixed = 1; - return 0; -} - -static int wl3501_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - /* Set the length (very important for backward compatibility) */ - wrqu->data.length = sizeof(*range); - - /* Set all the info we don't care or don't know about to zero */ - memset(range, 0, sizeof(*range)); - - /* Set the Wireless Extension versions */ - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 1; - range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */ - /* FIXME: study the code to fill in more fields... */ - return 0; -} - -static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int rc = -EINVAL; - - /* FIXME: we support other ARPHRDs...*/ - if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) - goto out; - if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) { - /* FIXME: rescan? */ - } else - memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); - /* FIXME: rescan? deassoc & scan? */ - rc = 0; -out: - return rc; -} - -static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN); - return 0; -} - -static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: trigger scanning with a reset, yes, I'm lazy - */ - return wl3501_reset(dev); -} - -static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - int i; - char *current_ev = extra; - struct iw_event iwe; - - for (i = 0; i < this->bss_cnt; ++i) { - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_ADDR_LEN); - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - iwe.u.data.length = this->bss_set[i].req.ssid.el.len; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, - this->bss_set[i].req.ssid.essid); - iwe.cmd = SIOCGIWMODE; - iwe.u.mode = this->bss_set[i].req.bss_type; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_UINT_LEN); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan; - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, IW_EV_FREQ_LEN); - iwe.cmd = SIOCGIWENCODE; - if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(info, current_ev, - extra + IW_SCAN_MAX_DATA, - &iwe, NULL); - } - /* Length of data */ - wrqu->data.length = (current_ev - extra); - wrqu->data.flags = 0; /* FIXME: set properly these flags */ - return 0; -} - -static int wl3501_set_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.flags) { - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, - extra, wrqu->data.length); - } else { /* We accept any ESSID */ - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, - &this->essid.el, "ANY", 3); - } - return wl3501_reset(dev); -} - -static int wl3501_get_essid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&this->lock, flags); - wrqu->essid.flags = 1; - wrqu->essid.length = this->essid.el.len; - memcpy(extra, this->essid.essid, this->essid.el.len); - spin_unlock_irqrestore(&this->lock, flags); - return 0; -} - -static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - if (wrqu->data.length > sizeof(this->nick)) - return -E2BIG; - strscpy(this->nick, extra, wrqu->data.length); - return 0; -} - -static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct wl3501_card *this = netdev_priv(dev); - - strscpy(extra, this->nick, 32); - wrqu->data.length = strlen(extra); - return 0; -} - -static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - /* - * FIXME: have to see from where to get this info, perhaps this card - * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most - * common with the Planet Access Points. -acme - */ - wrqu->bitrate.value = 2000000; - wrqu->bitrate.fixed = 1; - return 0; -} - -static int wl3501_get_rts_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->rts.value = threshold; - wrqu->rts.disabled = threshold >= 2347; - wrqu->rts.fixed = 1; - } - return rc; -} - -static int wl3501_get_frag_threshold(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 threshold; /* size checked: it is u16 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD, - &threshold, sizeof(threshold)); - if (!rc) { - wrqu->frag.value = threshold; - wrqu->frag.disabled = threshold >= 2346; - wrqu->frag.fixed = 1; - } - return rc; -} - -static int wl3501_get_txpow(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u16 txpow; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL, - &txpow, sizeof(txpow)); - if (!rc) { - wrqu->txpower.value = txpow; - wrqu->txpower.disabled = 0; - /* - * From the MIB values I think this can be configurable, - * as it lists several tx power levels -acme - */ - wrqu->txpower.fixed = 0; - wrqu->txpower.flags = IW_TXPOW_MWATT; - } - return rc; -} - -static int wl3501_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 retry; /* size checked: it is u8 */ - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_LONG_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - if (wrqu->retry.flags & IW_RETRY_LONG) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - goto set_value; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT, - &retry, sizeof(retry)); - if (rc) - goto out; - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; -set_value: - wrqu->retry.value = retry; - wrqu->retry.disabled = 0; -out: - return rc; -} - -static int wl3501_get_encode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 implemented, restricted, keys[100], len_keys, tocopy; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED, - &implemented, sizeof(implemented)); - if (rc) - goto out; - if (!implemented) { - wrqu->encoding.flags = IW_ENCODE_DISABLED; - goto out; - } - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED, - &restricted, sizeof(restricted)); - if (rc) - goto out; - wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED : - IW_ENCODE_OPEN; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN, - &len_keys, sizeof(len_keys)); - if (rc) - goto out; - rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS, - keys, len_keys); - if (rc) - goto out; - tocopy = min_t(u16, len_keys, wrqu->encoding.length); - tocopy = min_t(u8, tocopy, 100); - wrqu->encoding.length = tocopy; - memcpy(extra, keys, tocopy); -out: - return rc; -} - -static int wl3501_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 pwr_state; - struct wl3501_card *this = netdev_priv(dev); - int rc = wl3501_get_mib_value(this, - WL3501_MIB_ATTR_CURRENT_PWR_STATE, - &pwr_state, sizeof(pwr_state)); - if (rc) - goto out; - wrqu->power.disabled = !pwr_state; - wrqu->power.flags = IW_POWER_ON; -out: - return rc; -} - -static const iw_handler wl3501_handler[] = { - IW_HANDLER(SIOCGIWNAME, wl3501_get_name), - IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq), - IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq), - IW_HANDLER(SIOCSIWMODE, wl3501_set_mode), - IW_HANDLER(SIOCGIWMODE, wl3501_get_mode), - IW_HANDLER(SIOCGIWSENS, wl3501_get_sens), - IW_HANDLER(SIOCGIWRANGE, wl3501_get_range), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), - IW_HANDLER(SIOCSIWAP, wl3501_set_wap), - IW_HANDLER(SIOCGIWAP, wl3501_get_wap), - IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan), - IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan), - IW_HANDLER(SIOCSIWESSID, wl3501_set_essid), - IW_HANDLER(SIOCGIWESSID, wl3501_get_essid), - IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick), - IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick), - IW_HANDLER(SIOCGIWRATE, wl3501_get_rate), - IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold), - IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold), - IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow), - IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry), - IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode), - IW_HANDLER(SIOCGIWPOWER, wl3501_get_power), -}; - -static const struct iw_handler_def wl3501_handler_def = { - .num_standard = ARRAY_SIZE(wl3501_handler), - .standard = (iw_handler *)wl3501_handler, - .get_wireless_stats = wl3501_get_wireless_stats, -}; - -static const struct net_device_ops wl3501_netdev_ops = { - .ndo_open = wl3501_open, - .ndo_stop = wl3501_close, - .ndo_start_xmit = wl3501_hard_start_xmit, - .ndo_tx_timeout = wl3501_tx_timeout, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int wl3501_probe(struct pcmcia_device *p_dev) -{ - struct net_device *dev; - struct wl3501_card *this; - int ret; - - /* The io structure describes IO port mapping */ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8; - - /* General socket configuration */ - p_dev->config_flags = CONF_ENABLE_IRQ; - p_dev->config_index = 1; - - dev = alloc_etherdev(sizeof(struct wl3501_card)); - if (!dev) - return -ENOMEM; - - dev->netdev_ops = &wl3501_netdev_ops; - dev->watchdog_timeo = 5 * HZ; - - this = netdev_priv(dev); - this->wireless_data.spy_data = &this->spy_data; - this->p_dev = p_dev; - dev->wireless_data = &this->wireless_data; - dev->wireless_handlers = &wl3501_handler_def; - netif_stop_queue(dev); - p_dev->priv = dev; - - ret = wl3501_config(p_dev); - if (ret) - goto out_free_etherdev; - - return 0; - -out_free_etherdev: - free_netdev(dev); - return ret; -} - -static int wl3501_config(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - int i = 0, j, ret; - struct wl3501_card *this; - - /* Try allocating IO ports. This tries a few fixed addresses. If you - * want, you can also read the card's config table to pick addresses -- - * see the serial driver for an example. */ - link->io_lines = 5; - - for (j = 0x280; j < 0x400; j += 0x20) { - /* The '^0x300' is so that we probe 0x300-0x3ff first, then - * 0x200-0x2ff, and so on, because this seems safer */ - link->resource[0]->start = j; - link->resource[1]->start = link->resource[0]->start + 0x10; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - /* Now allocate an interrupt line. Note that this does not actually - * assign a handler to the interrupt. */ - - ret = pcmcia_request_irq(link, wl3501_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - SET_NETDEV_DEV(dev, &link->dev); - if (register_netdev(dev)) { - printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); - goto failed; - } - - this = netdev_priv(dev); - - this->base_addr = dev->base_addr; - - if (!wl3501_get_flash_mac_addr(this)) { - printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n", - dev->name); - unregister_netdev(dev); - goto failed; - } - - eth_hw_addr_set(dev, this->mac_addr); - - /* print probe information */ - printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%pM\n", - dev->name, this->base_addr, (int)dev->irq, - dev->dev_addr); - /* - * Initialize card parameters - added by jss - */ - this->net_type = IW_MODE_INFRA; - this->bss_cnt = 0; - this->join_sta_bss = 0; - this->adhoc_times = 0; - iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el, - "ANY", 3); - this->card_name[0] = '\0'; - this->firmware_date[0] = '\0'; - this->rssi = 255; - this->chan = iw_default_channel(this->reg_domain); - strscpy(this->nick, "Planet WL3501", sizeof(this->nick)); - spin_lock_init(&this->lock); - init_waitqueue_head(&this->wait); - netif_start_queue(dev); - return 0; - -failed: - wl3501_release(link); - return -ENODEV; -} - -static void wl3501_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static int wl3501_suspend(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND); - if (link->open) - netif_device_detach(dev); - - return 0; -} - -static int wl3501_resume(struct pcmcia_device *link) -{ - struct net_device *dev = link->priv; - - wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME); - if (link->open) { - wl3501_reset(dev); - netif_device_attach(dev); - } - - return 0; -} - - -static const struct pcmcia_device_id wl3501_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, wl3501_ids); - -static struct pcmcia_driver wl3501_driver = { - .owner = THIS_MODULE, - .name = "wl3501_cs", - .probe = wl3501_probe, - .remove = wl3501_detach, - .id_table = wl3501_ids, - .suspend = wl3501_suspend, - .resume = wl3501_resume, -}; -module_pcmcia_driver(wl3501_driver); - -MODULE_AUTHOR("Fox Chen , " - "Arnaldo Carvalho de Melo ," - "Gustavo Niemeyer "); -MODULE_DESCRIPTION("Planet wl3501 wireless driver"); -MODULE_LICENSE("GPL");