parent
a2af03953b
commit
2d620947c3
@ -0,0 +1,114 @@ |
||||
#
|
||||
# Copyright (C) 2007 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
# $Id: $
|
||||
|
||||
include $(TOPDIR)/rules.mk |
||||
include $(INCLUDE_DIR)/kernel.mk |
||||
|
||||
PKG_NAME:=p54
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_FWP54_NAME:=2.7.0.0.arm
|
||||
PKG_FWP54_URL:=http://prism54.org/firmware
|
||||
PKG_FWP54_MD5SUM:=09f9da7ea757173c9de1a0322a1f9782
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk |
||||
|
||||
define KernelPackage/p54/Default |
||||
SUBMENU:=Wireless Drivers
|
||||
TITLE:=Prism Wireless Support (mac80211)
|
||||
DEPENDS:=@LINUX_2_6 +kmod-mac80211
|
||||
endef |
||||
|
||||
define KernelPackage/p54-common |
||||
$(call KernelPackage/p54/Default) |
||||
TITLE+= (COMMON)
|
||||
DEPENDS+= @PCI_SUPPORT||USB_SUPPORT
|
||||
FILES:=$(PKG_BUILD_DIR)/p54common.$(LINUX_KMOD_SUFFIX)
|
||||
AUTOLOAD:=$(call AutoLoad,30,p54common)
|
||||
endef |
||||
|
||||
define KernelPackage/p54-pci |
||||
$(call KernelPackage/p54/Default) |
||||
TITLE+= (PCI)
|
||||
DEPENDS+= @PCI_SUPPORT +kmod-p54-common
|
||||
FILES:=$(PKG_BUILD_DIR)/p54pci.$(LINUX_KMOD_SUFFIX)
|
||||
AUTOLOAD:=$(call AutoLoad,31,p54pci)
|
||||
endef |
||||
|
||||
define KernelPackage/p54-usb |
||||
$(call KernelPackage/p54/Default) |
||||
TITLE+= (USB)
|
||||
DEPENDS+= @USB_SUPPORT +kmod-usb-core +kmod-p54-common
|
||||
FILES:=$(PKG_BUILD_DIR)/p54usb.$(LINUX_KMOD_SUFFIX)
|
||||
AUTOLOAD:=$(call AutoLoad,31,p54usb)
|
||||
endef |
||||
|
||||
define KernelPackage/p54/description |
||||
Kernel module for Prism54 chipsets (mac80211)
|
||||
endef |
||||
|
||||
$(STAMP_PREPARED): $(DL_DIR)/$(PKG_FWP54_NAME) |
||||
|
||||
$(DL_DIR)/$(PKG_FWP54_NAME): |
||||
$(SCRIPT_DIR)/download.pl "$(DL_DIR)" "$(PKG_FWP54_NAME)" "$(PKG_FWP54_MD5SUM)" $(PKG_FWP54_URL)
|
||||
|
||||
PKG_EXTRA_KCONFIG:= \
|
||||
CONFIG_P54_COMMON=m \
|
||||
|
||||
ifneq ($(CONFIG_PACKAGE_kmod-p54-pci),)
|
||||
PKG_EXTRA_KCONFIG+= CONFIG_P54_PCI=m
|
||||
endif
|
||||
ifneq ($(CONFIG_PACKAGE_kmod-p54-usb),)
|
||||
PKG_EXTRA_KCONFIG+= CONFIG_P54_USB=m
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS:= \
|
||||
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(PKG_EXTRA_KCONFIG)))) \
|
||||
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(PKG_EXTRA_KCONFIG)))) \
|
||||
|
||||
MAKE_OPTS:= \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
SUBDIRS="$(PKG_BUILD_DIR)" \
|
||||
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
|
||||
LINUXINCLUDE="-I$(STAGING_DIR)/usr/include/mac80211 -I$(LINUX_DIR)/include -include linux/autoconf.h" \
|
||||
$(PKG_EXTRA_KCONFIG)
|
||||
|
||||
ifneq ($(findstring 2.6.23,$(LINUX_VERSION)),) |
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
$(CP) $(DL_DIR)/$(PKG_FWP54_NAME) $(PKG_BUILD_DIR)
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C "$(LINUX_DIR)" \
|
||||
$(MAKE_OPTS) \
|
||||
modules
|
||||
endef
|
||||
else |
||||
override CONFIG_kmod-p54=
|
||||
endif |
||||
|
||||
define KernelPackage/p54-pci/install |
||||
$(INSTALL_DIR) $(1)/lib/firmware
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/2.7.0.0.arm $(1)/lib/firmware/isl3886
|
||||
endef |
||||
|
||||
define KernelPackage/p54-usb/install |
||||
$(INSTALL_DIR) $(1)/lib/firmware
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/2.7.0.0.arm $(1)/lib/firmware/isl3886
|
||||
endef |
||||
|
||||
|
||||
$(eval $(call KernelPackage,p54-common)) |
||||
$(eval $(call KernelPackage,p54-pci)) |
||||
$(eval $(call KernelPackage,p54-usb)) |
@ -0,0 +1,12 @@ |
||||
config P54_COMMON |
||||
tristate "Softmac Prism54 support" |
||||
depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL |
||||
|
||||
config P54_USB |
||||
tristate "Prism54 USB support" |
||||
depends on P54_COMMON && USB |
||||
select CRC32 |
||||
|
||||
config P54_PCI |
||||
tristate "Prism54 PCI support" |
||||
depends on P54_COMMON && PCI |
@ -0,0 +1,3 @@ |
||||
obj-$(CONFIG_P54_COMMON) += p54common.o
|
||||
obj-$(CONFIG_P54_USB) += p54usb.o
|
||||
obj-$(CONFIG_P54_PCI) += p54pci.o
|
@ -0,0 +1,452 @@ |
||||
#ifndef NET2280_H |
||||
#define NET2280_H |
||||
/*
|
||||
* NetChip 2280 high/full speed USB device controller. |
||||
* Unlike many such controllers, this one talks PCI. |
||||
*/ |
||||
|
||||
/*
|
||||
* Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
|
||||
* Copyright (C) 2003 David Brownell |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
/*-------------------------------------------------------------------------*/ |
||||
|
||||
/* NET2280 MEMORY MAPPED REGISTERS
|
||||
* |
||||
* The register layout came from the chip documentation, and the bit |
||||
* number definitions were extracted from chip specification. |
||||
* |
||||
* Use the shift operator ('<<') to build bit masks, with readl/writel |
||||
* to access the registers through PCI. |
||||
*/ |
||||
|
||||
/* main registers, BAR0 + 0x0000 */ |
||||
struct net2280_regs { |
||||
// offset 0x0000
|
||||
__le32 devinit; |
||||
#define LOCAL_CLOCK_FREQUENCY 8 |
||||
#define FORCE_PCI_RESET 7 |
||||
#define PCI_ID 6 |
||||
#define PCI_ENABLE 5 |
||||
#define FIFO_SOFT_RESET 4 |
||||
#define CFG_SOFT_RESET 3 |
||||
#define PCI_SOFT_RESET 2 |
||||
#define USB_SOFT_RESET 1 |
||||
#define M8051_RESET 0 |
||||
__le32 eectl; |
||||
#define EEPROM_ADDRESS_WIDTH 23 |
||||
#define EEPROM_CHIP_SELECT_ACTIVE 22 |
||||
#define EEPROM_PRESENT 21 |
||||
#define EEPROM_VALID 20 |
||||
#define EEPROM_BUSY 19 |
||||
#define EEPROM_CHIP_SELECT_ENABLE 18 |
||||
#define EEPROM_BYTE_READ_START 17 |
||||
#define EEPROM_BYTE_WRITE_START 16 |
||||
#define EEPROM_READ_DATA 8 |
||||
#define EEPROM_WRITE_DATA 0 |
||||
__le32 eeclkfreq; |
||||
u32 _unused0; |
||||
// offset 0x0010
|
||||
|
||||
__le32 pciirqenb0; /* interrupt PCI master ... */ |
||||
#define SETUP_PACKET_INTERRUPT_ENABLE 7 |
||||
#define ENDPOINT_F_INTERRUPT_ENABLE 6 |
||||
#define ENDPOINT_E_INTERRUPT_ENABLE 5 |
||||
#define ENDPOINT_D_INTERRUPT_ENABLE 4 |
||||
#define ENDPOINT_C_INTERRUPT_ENABLE 3 |
||||
#define ENDPOINT_B_INTERRUPT_ENABLE 2 |
||||
#define ENDPOINT_A_INTERRUPT_ENABLE 1 |
||||
#define ENDPOINT_0_INTERRUPT_ENABLE 0 |
||||
__le32 pciirqenb1; |
||||
#define PCI_INTERRUPT_ENABLE 31 |
||||
#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 |
||||
#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 |
||||
#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 |
||||
#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 |
||||
#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 |
||||
#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 |
||||
#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 |
||||
#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 |
||||
#define GPIO_INTERRUPT_ENABLE 13 |
||||
#define DMA_D_INTERRUPT_ENABLE 12 |
||||
#define DMA_C_INTERRUPT_ENABLE 11 |
||||
#define DMA_B_INTERRUPT_ENABLE 10 |
||||
#define DMA_A_INTERRUPT_ENABLE 9 |
||||
#define EEPROM_DONE_INTERRUPT_ENABLE 8 |
||||
#define VBUS_INTERRUPT_ENABLE 7 |
||||
#define CONTROL_STATUS_INTERRUPT_ENABLE 6 |
||||
#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 |
||||
#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 |
||||
#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 |
||||
#define RESUME_INTERRUPT_ENABLE 1 |
||||
#define SOF_INTERRUPT_ENABLE 0 |
||||
__le32 cpu_irqenb0; /* ... or onboard 8051 */ |
||||
#define SETUP_PACKET_INTERRUPT_ENABLE 7 |
||||
#define ENDPOINT_F_INTERRUPT_ENABLE 6 |
||||
#define ENDPOINT_E_INTERRUPT_ENABLE 5 |
||||
#define ENDPOINT_D_INTERRUPT_ENABLE 4 |
||||
#define ENDPOINT_C_INTERRUPT_ENABLE 3 |
||||
#define ENDPOINT_B_INTERRUPT_ENABLE 2 |
||||
#define ENDPOINT_A_INTERRUPT_ENABLE 1 |
||||
#define ENDPOINT_0_INTERRUPT_ENABLE 0 |
||||
__le32 cpu_irqenb1; |
||||
#define CPU_INTERRUPT_ENABLE 31 |
||||
#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 |
||||
#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 |
||||
#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 |
||||
#define PCI_INTA_INTERRUPT_ENABLE 24 |
||||
#define PCI_PME_INTERRUPT_ENABLE 23 |
||||
#define PCI_SERR_INTERRUPT_ENABLE 22 |
||||
#define PCI_PERR_INTERRUPT_ENABLE 21 |
||||
#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 |
||||
#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 |
||||
#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 |
||||
#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 |
||||
#define GPIO_INTERRUPT_ENABLE 13 |
||||
#define DMA_D_INTERRUPT_ENABLE 12 |
||||
#define DMA_C_INTERRUPT_ENABLE 11 |
||||
#define DMA_B_INTERRUPT_ENABLE 10 |
||||
#define DMA_A_INTERRUPT_ENABLE 9 |
||||
#define EEPROM_DONE_INTERRUPT_ENABLE 8 |
||||
#define VBUS_INTERRUPT_ENABLE 7 |
||||
#define CONTROL_STATUS_INTERRUPT_ENABLE 6 |
||||
#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 |
||||
#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 |
||||
#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 |
||||
#define RESUME_INTERRUPT_ENABLE 1 |
||||
#define SOF_INTERRUPT_ENABLE 0 |
||||
|
||||
// offset 0x0020
|
||||
u32 _unused1; |
||||
__le32 usbirqenb1; |
||||
#define USB_INTERRUPT_ENABLE 31 |
||||
#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 |
||||
#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 |
||||
#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 |
||||
#define PCI_INTA_INTERRUPT_ENABLE 24 |
||||
#define PCI_PME_INTERRUPT_ENABLE 23 |
||||
#define PCI_SERR_INTERRUPT_ENABLE 22 |
||||
#define PCI_PERR_INTERRUPT_ENABLE 21 |
||||
#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 |
||||
#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 |
||||
#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 |
||||
#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 |
||||
#define GPIO_INTERRUPT_ENABLE 13 |
||||
#define DMA_D_INTERRUPT_ENABLE 12 |
||||
#define DMA_C_INTERRUPT_ENABLE 11 |
||||
#define DMA_B_INTERRUPT_ENABLE 10 |
||||
#define DMA_A_INTERRUPT_ENABLE 9 |
||||
#define EEPROM_DONE_INTERRUPT_ENABLE 8 |
||||
#define VBUS_INTERRUPT_ENABLE 7 |
||||
#define CONTROL_STATUS_INTERRUPT_ENABLE 6 |
||||
#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 |
||||
#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 |
||||
#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 |
||||
#define RESUME_INTERRUPT_ENABLE 1 |
||||
#define SOF_INTERRUPT_ENABLE 0 |
||||
__le32 irqstat0; |
||||
#define INTA_ASSERTED 12 |
||||
#define SETUP_PACKET_INTERRUPT 7 |
||||
#define ENDPOINT_F_INTERRUPT 6 |
||||
#define ENDPOINT_E_INTERRUPT 5 |
||||
#define ENDPOINT_D_INTERRUPT 4 |
||||
#define ENDPOINT_C_INTERRUPT 3 |
||||
#define ENDPOINT_B_INTERRUPT 2 |
||||
#define ENDPOINT_A_INTERRUPT 1 |
||||
#define ENDPOINT_0_INTERRUPT 0 |
||||
__le32 irqstat1; |
||||
#define POWER_STATE_CHANGE_INTERRUPT 27 |
||||
#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 |
||||
#define PCI_PARITY_ERROR_INTERRUPT 25 |
||||
#define PCI_INTA_INTERRUPT 24 |
||||
#define PCI_PME_INTERRUPT 23 |
||||
#define PCI_SERR_INTERRUPT 22 |
||||
#define PCI_PERR_INTERRUPT 21 |
||||
#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 |
||||
#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 |
||||
#define PCI_RETRY_ABORT_INTERRUPT 17 |
||||
#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 |
||||
#define GPIO_INTERRUPT 13 |
||||
#define DMA_D_INTERRUPT 12 |
||||
#define DMA_C_INTERRUPT 11 |
||||
#define DMA_B_INTERRUPT 10 |
||||
#define DMA_A_INTERRUPT 9 |
||||
#define EEPROM_DONE_INTERRUPT 8 |
||||
#define VBUS_INTERRUPT 7 |
||||
#define CONTROL_STATUS_INTERRUPT 6 |
||||
#define ROOT_PORT_RESET_INTERRUPT 4 |
||||
#define SUSPEND_REQUEST_INTERRUPT 3 |
||||
#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 |
||||
#define RESUME_INTERRUPT 1 |
||||
#define SOF_INTERRUPT 0 |
||||
// offset 0x0030
|
||||
__le32 idxaddr; |
||||
__le32 idxdata; |
||||
__le32 fifoctl; |
||||
#define PCI_BASE2_RANGE 16 |
||||
#define IGNORE_FIFO_AVAILABILITY 3 |
||||
#define PCI_BASE2_SELECT 2 |
||||
#define FIFO_CONFIGURATION_SELECT 0 |
||||
u32 _unused2; |
||||
// offset 0x0040
|
||||
__le32 memaddr; |
||||
#define START 28 |
||||
#define DIRECTION 27 |
||||
#define FIFO_DIAGNOSTIC_SELECT 24 |
||||
#define MEMORY_ADDRESS 0 |
||||
__le32 memdata0; |
||||
__le32 memdata1; |
||||
u32 _unused3; |
||||
// offset 0x0050
|
||||
__le32 gpioctl; |
||||
#define GPIO3_LED_SELECT 12 |
||||
#define GPIO3_INTERRUPT_ENABLE 11 |
||||
#define GPIO2_INTERRUPT_ENABLE 10 |
||||
#define GPIO1_INTERRUPT_ENABLE 9 |
||||
#define GPIO0_INTERRUPT_ENABLE 8 |
||||
#define GPIO3_OUTPUT_ENABLE 7 |
||||
#define GPIO2_OUTPUT_ENABLE 6 |
||||
#define GPIO1_OUTPUT_ENABLE 5 |
||||
#define GPIO0_OUTPUT_ENABLE 4 |
||||
#define GPIO3_DATA 3 |
||||
#define GPIO2_DATA 2 |
||||
#define GPIO1_DATA 1 |
||||
#define GPIO0_DATA 0 |
||||
__le32 gpiostat; |
||||
#define GPIO3_INTERRUPT 3 |
||||
#define GPIO2_INTERRUPT 2 |
||||
#define GPIO1_INTERRUPT 1 |
||||
#define GPIO0_INTERRUPT 0 |
||||
} __attribute__ ((packed)); |
||||
|
||||
/* usb control, BAR0 + 0x0080 */ |
||||
struct net2280_usb_regs { |
||||
// offset 0x0080
|
||||
__le32 stdrsp; |
||||
#define STALL_UNSUPPORTED_REQUESTS 31 |
||||
#define SET_TEST_MODE 16 |
||||
#define GET_OTHER_SPEED_CONFIGURATION 15 |
||||
#define GET_DEVICE_QUALIFIER 14 |
||||
#define SET_ADDRESS 13 |
||||
#define ENDPOINT_SET_CLEAR_HALT 12 |
||||
#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 |
||||
#define GET_STRING_DESCRIPTOR_2 10 |
||||
#define GET_STRING_DESCRIPTOR_1 9 |
||||
#define GET_STRING_DESCRIPTOR_0 8 |
||||
#define GET_SET_INTERFACE 6 |
||||
#define GET_SET_CONFIGURATION 5 |
||||
#define GET_CONFIGURATION_DESCRIPTOR 4 |
||||
#define GET_DEVICE_DESCRIPTOR 3 |
||||
#define GET_ENDPOINT_STATUS 2 |
||||
#define GET_INTERFACE_STATUS 1 |
||||
#define GET_DEVICE_STATUS 0 |
||||
__le32 prodvendid; |
||||
#define PRODUCT_ID 16 |
||||
#define VENDOR_ID 0 |
||||
__le32 relnum; |
||||
__le32 usbctl; |
||||
#define SERIAL_NUMBER_INDEX 16 |
||||
#define PRODUCT_ID_STRING_ENABLE 13 |
||||
#define VENDOR_ID_STRING_ENABLE 12 |
||||
#define USB_ROOT_PORT_WAKEUP_ENABLE 11 |
||||
#define VBUS_PIN 10 |
||||
#define TIMED_DISCONNECT 9 |
||||
#define SUSPEND_IMMEDIATELY 7 |
||||
#define SELF_POWERED_USB_DEVICE 6 |
||||
#define REMOTE_WAKEUP_SUPPORT 5 |
||||
#define PME_POLARITY 4 |
||||
#define USB_DETECT_ENABLE 3 |
||||
#define PME_WAKEUP_ENABLE 2 |
||||
#define DEVICE_REMOTE_WAKEUP_ENABLE 1 |
||||
#define SELF_POWERED_STATUS 0 |
||||
// offset 0x0090
|
||||
__le32 usbstat; |
||||
#define HIGH_SPEED 7 |
||||
#define FULL_SPEED 6 |
||||
#define GENERATE_RESUME 5 |
||||
#define GENERATE_DEVICE_REMOTE_WAKEUP 4 |
||||
__le32 xcvrdiag; |
||||
#define FORCE_HIGH_SPEED_MODE 31 |
||||
#define FORCE_FULL_SPEED_MODE 30 |
||||
#define USB_TEST_MODE 24 |
||||
#define LINE_STATE 16 |
||||
#define TRANSCEIVER_OPERATION_MODE 2 |
||||
#define TRANSCEIVER_SELECT 1 |
||||
#define TERMINATION_SELECT 0 |
||||
__le32 setup0123; |
||||
__le32 setup4567; |
||||
// offset 0x0090
|
||||
u32 _unused0; |
||||
__le32 ouraddr; |
||||
#define FORCE_IMMEDIATE 7 |
||||
#define OUR_USB_ADDRESS 0 |
||||
__le32 ourconfig; |
||||
} __attribute__ ((packed)); |
||||
|
||||
/* pci control, BAR0 + 0x0100 */ |
||||
struct net2280_pci_regs { |
||||
// offset 0x0100
|
||||
__le32 pcimstctl; |
||||
#define PCI_ARBITER_PARK_SELECT 13 |
||||
#define PCI_MULTI LEVEL_ARBITER 12 |
||||
#define PCI_RETRY_ABORT_ENABLE 11 |
||||
#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 |
||||
#define DMA_READ_MULTIPLE_ENABLE 9 |
||||
#define DMA_READ_LINE_ENABLE 8 |
||||
#define PCI_MASTER_COMMAND_SELECT 6 |
||||
#define MEM_READ_OR_WRITE 0 |
||||
#define IO_READ_OR_WRITE 1 |
||||
#define CFG_READ_OR_WRITE 2 |
||||
#define PCI_MASTER_START 5 |
||||
#define PCI_MASTER_READ_WRITE 4 |
||||
#define PCI_MASTER_WRITE 0 |
||||
#define PCI_MASTER_READ 1 |
||||
#define PCI_MASTER_BYTE_WRITE_ENABLES 0 |
||||
__le32 pcimstaddr; |
||||
__le32 pcimstdata; |
||||
__le32 pcimststat; |
||||
#define PCI_ARBITER_CLEAR 2 |
||||
#define PCI_EXTERNAL_ARBITER 1 |
||||
#define PCI_HOST_MODE 0 |
||||
} __attribute__ ((packed)); |
||||
|
||||
/* dma control, BAR0 + 0x0180 ... array of four structs like this,
|
||||
* for channels 0..3. see also struct net2280_dma: descriptor |
||||
* that can be loaded into some of these registers. |
||||
*/ |
||||
struct net2280_dma_regs { /* [11.7] */ |
||||
// offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
|
||||
__le32 dmactl; |
||||
#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 |
||||
#define DMA_CLEAR_COUNT_ENABLE 21 |
||||
#define DESCRIPTOR_POLLING_RATE 19 |
||||
#define POLL_CONTINUOUS 0 |
||||
#define POLL_1_USEC 1 |
||||
#define POLL_100_USEC 2 |
||||
#define POLL_1_MSEC 3 |
||||
#define DMA_VALID_BIT_POLLING_ENABLE 18 |
||||
#define DMA_VALID_BIT_ENABLE 17 |
||||
#define DMA_SCATTER_GATHER_ENABLE 16 |
||||
#define DMA_OUT_AUTO_START_ENABLE 4 |
||||
#define DMA_PREEMPT_ENABLE 3 |
||||
#define DMA_FIFO_VALIDATE 2 |
||||
#define DMA_ENABLE 1 |
||||
#define DMA_ADDRESS_HOLD 0 |
||||
__le32 dmastat; |
||||
#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 |
||||
#define DMA_TRANSACTION_DONE_INTERRUPT 24 |
||||
#define DMA_ABORT 1 |
||||
#define DMA_START 0 |
||||
u32 _unused0[2]; |
||||
// offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
|
||||
__le32 dmacount; |
||||
#define VALID_BIT 31 |
||||
#define DMA_DIRECTION 30 |
||||
#define DMA_DONE_INTERRUPT_ENABLE 29 |
||||
#define END_OF_CHAIN 28 |
||||
#define DMA_BYTE_COUNT_MASK ((1<<24)-1) |
||||
#define DMA_BYTE_COUNT 0 |
||||
__le32 dmaaddr; |
||||
__le32 dmadesc; |
||||
u32 _unused1; |
||||
} __attribute__ ((packed)); |
||||
|
||||
/* dedicated endpoint registers, BAR0 + 0x0200 */ |
||||
|
||||
struct net2280_dep_regs { /* [11.8] */ |
||||
// offset 0x0200, 0x0210, 0x220, 0x230, 0x240
|
||||
__le32 dep_cfg; |
||||
// offset 0x0204, 0x0214, 0x224, 0x234, 0x244
|
||||
__le32 dep_rsp; |
||||
u32 _unused[2]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
|
||||
* like this, for ep0 then the configurable endpoints A..F |
||||
* ep0 reserved for control; E and F have only 64 bytes of fifo |
||||
*/ |
||||
struct net2280_ep_regs { /* [11.9] */ |
||||
// offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
|
||||
__le32 ep_cfg; |
||||
#define ENDPOINT_BYTE_COUNT 16 |
||||
#define ENDPOINT_ENABLE 10 |
||||
#define ENDPOINT_TYPE 8 |
||||
#define ENDPOINT_DIRECTION 7 |
||||
#define ENDPOINT_NUMBER 0 |
||||
__le32 ep_rsp; |
||||
#define SET_NAK_OUT_PACKETS 15 |
||||
#define SET_EP_HIDE_STATUS_PHASE 14 |
||||
#define SET_EP_FORCE_CRC_ERROR 13 |
||||
#define SET_INTERRUPT_MODE 12 |
||||
#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 |
||||
#define SET_NAK_OUT_PACKETS_MODE 10 |
||||
#define SET_ENDPOINT_TOGGLE 9 |
||||
#define SET_ENDPOINT_HALT 8 |
||||
#define CLEAR_NAK_OUT_PACKETS 7 |
||||
#define CLEAR_EP_HIDE_STATUS_PHASE 6 |
||||
#define CLEAR_EP_FORCE_CRC_ERROR 5 |
||||
#define CLEAR_INTERRUPT_MODE 4 |
||||
#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 |
||||
#define CLEAR_NAK_OUT_PACKETS_MODE 2 |
||||
#define CLEAR_ENDPOINT_TOGGLE 1 |
||||
#define CLEAR_ENDPOINT_HALT 0 |
||||
__le32 ep_irqenb; |
||||
#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 |
||||
#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 |
||||
#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 |
||||
#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 |
||||
#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 |
||||
#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 |
||||
__le32 ep_stat; |
||||
#define FIFO_VALID_COUNT 24 |
||||
#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 |
||||
#define TIMEOUT 21 |
||||
#define USB_STALL_SENT 20 |
||||
#define USB_IN_NAK_SENT 19 |
||||
#define USB_IN_ACK_RCVD 18 |
||||
#define USB_OUT_PING_NAK_SENT 17 |
||||
#define USB_OUT_ACK_SENT 16 |
||||
#define FIFO_OVERFLOW 13 |
||||
#define FIFO_UNDERFLOW 12 |
||||
#define FIFO_FULL 11 |
||||
#define FIFO_EMPTY 10 |
||||
#define FIFO_FLUSH 9 |
||||
#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 |
||||
#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 |
||||
#define NAK_OUT_PACKETS 4 |
||||
#define DATA_PACKET_RECEIVED_INTERRUPT 3 |
||||
#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 |
||||
#define DATA_OUT_PING_TOKEN_INTERRUPT 1 |
||||
#define DATA_IN_TOKEN_INTERRUPT 0 |
||||
// offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
|
||||
__le32 ep_avail; |
||||
__le32 ep_data; |
||||
u32 _unused0[2]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct net2280_reg_write { |
||||
__le16 port; |
||||
__le32 addr; |
||||
__le32 val; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct net2280_reg_read { |
||||
__le16 port; |
||||
__le32 addr; |
||||
} __attribute__ ((packed)); |
||||
#endif /* NET2280_H */ |
@ -0,0 +1,81 @@ |
||||
#ifndef PRISM54_H |
||||
#define PRISM54_H |
||||
|
||||
/*
|
||||
* Shared defines for all mac80211 Prism54 code |
||||
* |
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
||||
* |
||||
* Based on the islsm (softmac prism54) driver, which is: |
||||
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
enum control_frame_types { |
||||
P54_CONTROL_TYPE_FILTER_SET = 0, |
||||
P54_CONTROL_TYPE_CHANNEL_CHANGE, |
||||
P54_CONTROL_TYPE_FREQDONE, |
||||
P54_CONTROL_TYPE_DCFINIT, |
||||
P54_CONTROL_TYPE_FREEQUEUE = 7, |
||||
P54_CONTROL_TYPE_TXDONE, |
||||
P54_CONTROL_TYPE_PING, |
||||
P54_CONTROL_TYPE_STAT_READBACK, |
||||
P54_CONTROL_TYPE_BBP, |
||||
P54_CONTROL_TYPE_EEPROM_READBACK, |
||||
P54_CONTROL_TYPE_LED |
||||
}; |
||||
|
||||
struct p54_control_hdr { |
||||
__le16 magic1; |
||||
__le16 len; |
||||
__le32 req_id; |
||||
__le16 type; /* enum control_frame_types */ |
||||
u8 retry1; |
||||
u8 retry2; |
||||
u8 data[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) |
||||
#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 ) |
||||
|
||||
#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 |
||||
|
||||
struct p54_common { |
||||
u32 rx_start; |
||||
u32 rx_end; |
||||
struct sk_buff_head tx_queue; |
||||
void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, |
||||
size_t len, int free_on_tx); |
||||
int (*open)(struct ieee80211_hw *dev); |
||||
void (*stop)(struct ieee80211_hw *dev); |
||||
int mode; |
||||
u8 mac_addr[ETH_ALEN]; |
||||
u8 bssid[ETH_ALEN]; |
||||
struct pda_iq_autocal_entry *iq_autocal; |
||||
unsigned int iq_autocal_len; |
||||
struct pda_channel_output_limit *output_limit; |
||||
unsigned int output_limit_len; |
||||
struct pda_pa_curve_data *curve_data; |
||||
__le16 rxhw; |
||||
u8 version; |
||||
unsigned int tx_hdr_len; |
||||
void *cached_vdcf; |
||||
unsigned int fw_var; |
||||
/* FIXME: this channels/modes/rates stuff sucks */ |
||||
struct ieee80211_channel channels[14]; |
||||
struct ieee80211_rate rates[12]; |
||||
struct ieee80211_hw_mode modes[2]; |
||||
struct ieee80211_tx_queue_stats tx_stats; |
||||
}; |
||||
|
||||
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); |
||||
void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); |
||||
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); |
||||
void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); |
||||
struct ieee80211_hw *p54_init_common(size_t priv_data_len); |
||||
void p54_free_common(struct ieee80211_hw *dev); |
||||
|
||||
#endif /* PRISM54_H */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,329 @@ |
||||
#ifndef PRISM54COMMON_H |
||||
#define PRISM54COMMON_H |
||||
|
||||
/*
|
||||
* Common code specific definitions for mac80211 Prism54 drivers |
||||
* |
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
||||
* Copyright (c) 2007, Christian Lamparter <chunkeey@web.de> |
||||
* |
||||
* Based on the islsm (softmac prism54) driver, which is: |
||||
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
struct bootrec { |
||||
__le32 code; |
||||
__le32 len; |
||||
u32 data[0]; |
||||
} __attribute__((packed)); |
||||
|
||||
struct bootrec_exp_if { |
||||
__le16 role; |
||||
__le16 if_id; |
||||
__le16 variant; |
||||
__le16 btm_compat; |
||||
__le16 top_compat; |
||||
} __attribute__((packed)); |
||||
|
||||
#define BR_CODE_MIN 0x80000000 |
||||
#define BR_CODE_COMPONENT_ID 0x80000001 |
||||
#define BR_CODE_COMPONENT_VERSION 0x80000002 |
||||
#define BR_CODE_DEPENDENT_IF 0x80000003 |
||||
#define BR_CODE_EXPOSED_IF 0x80000004 |
||||
#define BR_CODE_DESCR 0x80000101 |
||||
#define BR_CODE_MAX 0x8FFFFFFF |
||||
#define BR_CODE_END_OF_BRA 0xFF0000FF |
||||
#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF |
||||
|
||||
#define FW_FMAC 0x464d4143 |
||||
#define FW_LM86 0x4c4d3836 |
||||
#define FW_LM87 0x4c4d3837 |
||||
#define FW_LM20 0x4c4d3230 |
||||
|
||||
/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ |
||||
|
||||
struct pda_entry { |
||||
__le16 len; /* includes both code and data */ |
||||
__le16 code; |
||||
u8 data[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct eeprom_pda_wrap { |
||||
u32 magic; |
||||
u16 pad; |
||||
u16 len; |
||||
u32 arm_opcode; |
||||
u8 data[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct pda_iq_autocal_entry { |
||||
__le16 freq; |
||||
__le16 iq_param[4]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct pda_channel_output_limit { |
||||
__le16 freq; |
||||
u8 val_bpsk; |
||||
u8 val_qpsk; |
||||
u8 val_16qam; |
||||
u8 val_64qam; |
||||
u8 rate_set_mask; |
||||
u8 rate_set_size; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct pda_pa_curve_data_sample_rev0 { |
||||
u8 rf_power; |
||||
u8 pa_detector; |
||||
u8 pcv; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct pda_pa_curve_data_sample_rev1 { |
||||
u8 rf_power; |
||||
u8 pa_detector; |
||||
u8 data_barker; |
||||
u8 data_bpsk; |
||||
u8 data_qpsk; |
||||
u8 data_16qam; |
||||
u8 data_64qam; |
||||
u8 padding; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct pda_pa_curve_data { |
||||
u8 cal_method_rev; |
||||
u8 channels; |
||||
u8 points_per_channel; |
||||
u8 padding; |
||||
u8 data[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
/*
|
||||
* this defines the PDR codes used to build PDAs as defined in document |
||||
* number 553155. The current implementation mirrors version 1.1 of the |
||||
* document and lists only PDRs supported by the ARM platform. |
||||
*/ |
||||
|
||||
/* common and choice range (0x0000 - 0x0fff) */ |
||||
#define PDR_END 0x0000 |
||||
#define PDR_MANUFACTURING_PART_NUMBER 0x0001 |
||||
#define PDR_PDA_VERSION 0x0002 |
||||
#define PDR_NIC_SERIAL_NUMBER 0x0003 |
||||
|
||||
#define PDR_MAC_ADDRESS 0x0101 |
||||
#define PDR_REGULATORY_DOMAIN_LIST 0x0103 |
||||
#define PDR_TEMPERATURE_TYPE 0x0107 |
||||
|
||||
#define PDR_PRISM_PCI_IDENTIFIER 0x0402 |
||||
|
||||
/* ARM range (0x1000 - 0x1fff) */ |
||||
#define PDR_COUNTRY_INFORMATION 0x1000 |
||||
#define PDR_INTERFACE_LIST 0x1001 |
||||
#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002 |
||||
#define PDR_OEM_NAME 0x1003 |
||||
#define PDR_PRODUCT_NAME 0x1004 |
||||
#define PDR_UTF8_OEM_NAME 0x1005 |
||||
#define PDR_UTF8_PRODUCT_NAME 0x1006 |
||||
#define PDR_COUNTRY_LIST 0x1007 |
||||
#define PDR_DEFAULT_COUNTRY 0x1008 |
||||
|
||||
#define PDR_ANTENNA_GAIN 0x1100 |
||||
|
||||
#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901 |
||||
#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902 |
||||
#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903 |
||||
#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904 |
||||
#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905 |
||||
#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906 |
||||
#define PDR_REGULATORY_POWER_LIMITS 0x1907 |
||||
#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908 |
||||
#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909 |
||||
#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a |
||||
|
||||
/* reserved range (0x2000 - 0x7fff) */ |
||||
|
||||
/* customer range (0x8000 - 0xffff) */ |
||||
#define PDR_BASEBAND_REGISTERS 0x8000 |
||||
#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 |
||||
|
||||
/* stored in skb->cb */ |
||||
struct memrecord { |
||||
u32 start_addr; |
||||
u32 end_addr; |
||||
struct ieee80211_tx_control *control; |
||||
}; |
||||
|
||||
struct p54_eeprom_lm86 { |
||||
__le16 offset; |
||||
__le16 len; |
||||
u8 data[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_rx_hdr { |
||||
__le16 magic; |
||||
__le16 len; |
||||
__le16 freq; |
||||
u8 antenna; |
||||
u8 rate; |
||||
u8 rssi; |
||||
u8 quality; |
||||
u16 unknown2; |
||||
__le64 timestamp; |
||||
u8 data[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_frame_sent_hdr { |
||||
u8 status; |
||||
u8 retries; |
||||
__le16 ack_rssi; |
||||
__le16 seq; |
||||
u16 rate; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_tx_control_allocdata { |
||||
u8 rateset[8]; |
||||
u16 padding; |
||||
u8 wep_key_present; |
||||
u8 wep_key_len; |
||||
u8 wep_key[16]; |
||||
__le32 frame_type; |
||||
u32 padding2; |
||||
__le16 magic4; |
||||
u8 antenna; |
||||
u8 output_power; |
||||
__le32 magic5; |
||||
u8 align[0]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_tx_control_filter { |
||||
__le16 filter_type; |
||||
u8 dst[ETH_ALEN]; |
||||
u8 src[ETH_ALEN]; |
||||
u8 antenna; |
||||
u8 debug; |
||||
__le32 magic3; |
||||
u8 rates[8]; // FIXME: what's this for?
|
||||
__le32 rx_addr; |
||||
__le16 max_rx; |
||||
__le16 rxhw; |
||||
__le16 magic8; |
||||
__le16 magic9; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_tx_control_channel { |
||||
__le16 magic1; |
||||
__le16 magic2; |
||||
u8 padding1[20]; |
||||
struct pda_iq_autocal_entry iq_autocal; |
||||
u8 pa_points_per_curve; |
||||
u8 val_barker; |
||||
u8 val_bpsk; |
||||
u8 val_qpsk; |
||||
u8 val_16qam; |
||||
u8 val_64qam; |
||||
struct pda_pa_curve_data_sample_rev1 curve_data[0]; |
||||
/* additional padding/data after curve_data */ |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_tx_control_led { |
||||
__le16 mode; |
||||
__le16 led_temporary; |
||||
__le16 led_permanent; |
||||
__le16 duration; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_tx_vdcf_queues { |
||||
__le16 aifs; |
||||
__le16 cwmin; |
||||
__le16 cwmax; |
||||
__le16 txop; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54_tx_control_vdcf { |
||||
u8 padding; |
||||
u8 slottime; |
||||
u8 magic1; |
||||
u8 magic2; |
||||
struct p54_tx_vdcf_queues queue[8]; |
||||
u8 pad2[4]; |
||||
__le16 frameburst; |
||||
} __attribute__ ((packed)); |
||||
|
||||
static const struct ieee80211_rate p54_rates[] = { |
||||
{ .rate = 10, |
||||
.val = 0, |
||||
.val2 = 0x10, |
||||
.flags = IEEE80211_RATE_CCK_2 }, |
||||
{ .rate = 20, |
||||
.val = 1, |
||||
.val2 = 0x11, |
||||
.flags = IEEE80211_RATE_CCK_2 }, |
||||
{ .rate = 55, |
||||
.val = 2, |
||||
.val2 = 0x12, |
||||
.flags = IEEE80211_RATE_CCK_2 }, |
||||
{ .rate = 110, |
||||
.val = 3, |
||||
.val2 = 0x13, |
||||
.flags = IEEE80211_RATE_CCK_2 }, |
||||
{ .rate = 60, |
||||
.val = 4, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 90, |
||||
.val = 5, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 120, |
||||
.val = 6, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 180, |
||||
.val = 7, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 240, |
||||
.val = 8, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 360, |
||||
.val = 9, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 480, |
||||
.val = 10, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
{ .rate = 540, |
||||
.val = 11, |
||||
.flags = IEEE80211_RATE_OFDM }, |
||||
}; |
||||
|
||||
// TODO: just generate this..
|
||||
static const struct ieee80211_channel p54_channels[] = { |
||||
{ .chan = 1, |
||||
.freq = 2412}, |
||||
{ .chan = 2, |
||||
.freq = 2417}, |
||||
{ .chan = 3, |
||||
.freq = 2422}, |
||||
{ .chan = 4, |
||||
.freq = 2427}, |
||||
{ .chan = 5, |
||||
.freq = 2432}, |
||||
{ .chan = 6, |
||||
.freq = 2437}, |
||||
{ .chan = 7, |
||||
.freq = 2442}, |
||||
{ .chan = 8, |
||||
.freq = 2447}, |
||||
{ .chan = 9, |
||||
.freq = 2452}, |
||||
{ .chan = 10, |
||||
.freq = 2457}, |
||||
{ .chan = 11, |
||||
.freq = 2462}, |
||||
{ .chan = 12, |
||||
.freq = 2467}, |
||||
{ .chan = 13, |
||||
.freq = 2472}, |
||||
{ .chan = 14, |
||||
.freq = 2484} |
||||
}; |
||||
|
||||
#endif /* PRISM54COMMON_H */ |
@ -0,0 +1,690 @@ |
||||
|
||||
/*
|
||||
* Linux device driver for PCI based Prism54 |
||||
* |
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
||||
* |
||||
* Based on the islsm (softmac prism54) driver, which is: |
||||
* Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
#include <linux/init.h> |
||||
#include <linux/pci.h> |
||||
#include <linux/firmware.h> |
||||
#include <linux/etherdevice.h> |
||||
#include <linux/delay.h> |
||||
#include <linux/completion.h> |
||||
#include <net/mac80211.h> |
||||
|
||||
#include "p54.h" |
||||
#include "p54pci.h" |
||||
|
||||
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); |
||||
MODULE_DESCRIPTION("Prism54 PCI wireless driver"); |
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_ALIAS("prism54pci"); |
||||
|
||||
static struct pci_device_id p54p_table[] __devinitdata = { |
||||
/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ |
||||
{ PCI_DEVICE(0x1260, 0x3890) }, |
||||
/* 3COM 3CRWE154G72 Wireless LAN adapter */ |
||||
{ PCI_DEVICE(0x10b7, 0x6001) }, |
||||
/* Intersil PRISM Indigo Wireless LAN adapter */ |
||||
{ PCI_DEVICE(0x1260, 0x3877) }, |
||||
/* Intersil PRISM Javelin/Xbow Wireless LAN adapter */ |
||||
{ PCI_DEVICE(0x1260, 0x3886) }, |
||||
{ }, |
||||
}; |
||||
|
||||
MODULE_DEVICE_TABLE(pci, p54p_table); |
||||
|
||||
static int p54p_upload_firmware(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54p_priv *priv = dev->priv; |
||||
const struct firmware *fw_entry = NULL; |
||||
__le32 reg; |
||||
int err; |
||||
u32 *data; |
||||
u32 remains, left, device_addr; |
||||
|
||||
P54P_WRITE(int_enable, 0); |
||||
P54P_READ(int_enable); |
||||
udelay(10); |
||||
|
||||
reg = P54P_READ(ctrl_stat); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); |
||||
P54P_WRITE(ctrl_stat, reg); |
||||
P54P_READ(ctrl_stat); |
||||
udelay(10); |
||||
|
||||
reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); |
||||
P54P_WRITE(ctrl_stat, reg); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
P54P_WRITE(ctrl_stat, reg); |
||||
wmb(); |
||||
|
||||
mdelay(50); |
||||
|
||||
err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); |
||||
if (err) { |
||||
printk(KERN_ERR "%s (prism54pci): cannot find firmware " |
||||
"(isl3886)\n", pci_name(priv->pdev)); |
||||
return err; |
||||
} |
||||
|
||||
p54_parse_firmware(dev, fw_entry); |
||||
|
||||
data = (u32 *) fw_entry->data; |
||||
remains = fw_entry->size; |
||||
device_addr = ISL38XX_DEV_FIRMWARE_ADDR; |
||||
while (remains) { |
||||
u32 i = 0; |
||||
left = min((u32)0x1000, remains); |
||||
P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr)); |
||||
P54P_READ(int_enable); |
||||
|
||||
device_addr += 0x1000; |
||||
while (i < left) { |
||||
P54P_WRITE(direct_mem_win[i], *data++); |
||||
i += sizeof(u32); |
||||
} |
||||
|
||||
remains -= left; |
||||
P54P_READ(int_enable); |
||||
} |
||||
|
||||
release_firmware(fw_entry); |
||||
|
||||
reg = P54P_READ(ctrl_stat); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); |
||||
P54P_WRITE(ctrl_stat, reg); |
||||
P54P_READ(ctrl_stat); |
||||
udelay(10); |
||||
|
||||
reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); |
||||
P54P_WRITE(ctrl_stat, reg); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
P54P_WRITE(ctrl_stat, reg); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id) |
||||
{ |
||||
struct p54p_priv *priv = (struct p54p_priv *) dev_id; |
||||
__le32 reg; |
||||
|
||||
reg = P54P_READ(int_ident); |
||||
P54P_WRITE(int_ack, reg); |
||||
|
||||
if (reg & P54P_READ(int_enable)) |
||||
complete(&priv->boot_comp); |
||||
|
||||
return IRQ_HANDLED; |
||||
} |
||||
|
||||
static int p54p_read_eeprom(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54p_priv *priv = dev->priv; |
||||
int err; |
||||
struct p54_control_hdr *hdr; |
||||
void *eeprom; |
||||
dma_addr_t rx_mapping, tx_mapping; |
||||
u16 alen; |
||||
|
||||
init_completion(&priv->boot_comp); |
||||
err = request_irq(priv->pdev->irq, &p54p_simple_interrupt, |
||||
IRQF_SHARED, "prism54pci", priv); |
||||
if (err) { |
||||
printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n", |
||||
pci_name(priv->pdev)); |
||||
return err; |
||||
} |
||||
|
||||
eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL); |
||||
if (!eeprom) { |
||||
printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n", |
||||
pci_name(priv->pdev)); |
||||
err = -ENOMEM; |
||||
goto out; |
||||
} |
||||
|
||||
memset(priv->ring_control, 0, sizeof(*priv->ring_control)); |
||||
P54P_WRITE(ring_control_base, priv->ring_control_dma); |
||||
P54P_READ(ring_control_base); |
||||
udelay(10); |
||||
|
||||
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); |
||||
P54P_READ(int_enable); |
||||
udelay(10); |
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
||||
|
||||
if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n", |
||||
pci_name(priv->pdev)); |
||||
err = -EINVAL; |
||||
goto out; |
||||
} |
||||
|
||||
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); |
||||
P54P_READ(int_enable); |
||||
|
||||
hdr = eeprom + 0x2010; |
||||
p54_fill_eeprom_readback(hdr); |
||||
hdr->req_id = cpu_to_le32(priv->common.rx_start); |
||||
|
||||
rx_mapping = pci_map_single(priv->pdev, eeprom, |
||||
0x2010, PCI_DMA_FROMDEVICE); |
||||
tx_mapping = pci_map_single(priv->pdev, (void *)hdr, |
||||
EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); |
||||
|
||||
priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); |
||||
priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); |
||||
priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); |
||||
priv->ring_control->tx_data[0].device_addr = hdr->req_id; |
||||
priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); |
||||
|
||||
priv->ring_control->host_idx[2] = cpu_to_le32(1); |
||||
priv->ring_control->host_idx[1] = cpu_to_le32(1); |
||||
|
||||
wmb(); |
||||
mdelay(100); |
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); |
||||
|
||||
wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); |
||||
wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ); |
||||
|
||||
pci_unmap_single(priv->pdev, tx_mapping, |
||||
EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); |
||||
pci_unmap_single(priv->pdev, rx_mapping, |
||||
0x2010, PCI_DMA_FROMDEVICE); |
||||
|
||||
alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len); |
||||
if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 || |
||||
alen < 0x10) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n", |
||||
pci_name(priv->pdev)); |
||||
err = -EINVAL; |
||||
goto out; |
||||
} |
||||
|
||||
p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10); |
||||
|
||||
out: |
||||
kfree(eeprom); |
||||
P54P_WRITE(int_enable, 0); |
||||
P54P_READ(int_enable); |
||||
udelay(10); |
||||
free_irq(priv->pdev->irq, priv); |
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
||||
return err; |
||||
} |
||||
|
||||
static void p54p_refill_rx_ring(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54p_priv *priv = dev->priv; |
||||
u32 limit, host_idx, idx; |
||||
|
||||
host_idx = le32_to_cpu(priv->ring_control->host_idx[0]); |
||||
limit = host_idx; |
||||
limit -= le32_to_cpu(priv->ring_control->device_idx[0]); |
||||
limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit; |
||||
|
||||
idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data); |
||||
while (limit-- > 1) { |
||||
struct p54p_desc *desc = &priv->ring_control->rx_data[idx]; |
||||
|
||||
if (!desc->host_addr) { |
||||
struct sk_buff *skb; |
||||
dma_addr_t mapping; |
||||
skb = dev_alloc_skb(MAX_RX_SIZE); |
||||
if (!skb) |
||||
break; |
||||
|
||||
mapping = pci_map_single(priv->pdev, |
||||
skb_tail_pointer(skb), |
||||
MAX_RX_SIZE, |
||||
PCI_DMA_FROMDEVICE); |
||||
desc->host_addr = cpu_to_le32(mapping); |
||||
desc->device_addr = 0; // FIXME: necessary?
|
||||
desc->len = cpu_to_le16(MAX_RX_SIZE); |
||||
desc->flags = 0; |
||||
priv->rx_buf[idx] = skb; |
||||
} |
||||
|
||||
idx++; |
||||
host_idx++; |
||||
idx %= ARRAY_SIZE(priv->ring_control->rx_data); |
||||
} |
||||
|
||||
wmb(); |
||||
priv->ring_control->host_idx[0] = cpu_to_le32(host_idx); |
||||
} |
||||
|
||||
static irqreturn_t p54p_interrupt(int irq, void *dev_id) |
||||
{ |
||||
struct ieee80211_hw *dev = dev_id; |
||||
struct p54p_priv *priv = dev->priv; |
||||
__le32 reg; |
||||
|
||||
spin_lock(&priv->lock); |
||||
reg = P54P_READ(int_ident); |
||||
if (unlikely(reg == 0xFFFFFFFF)) { |
||||
spin_unlock(&priv->lock); |
||||
return IRQ_HANDLED; |
||||
} |
||||
|
||||
P54P_WRITE(int_ack, reg); |
||||
|
||||
reg &= P54P_READ(int_enable); |
||||
|
||||
if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { |
||||
struct p54p_desc *desc; |
||||
u32 idx, i; |
||||
i = priv->tx_idx; |
||||
i %= ARRAY_SIZE(priv->ring_control->tx_data); |
||||
priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]); |
||||
idx %= ARRAY_SIZE(priv->ring_control->tx_data); |
||||
|
||||
while (i != idx) { |
||||
desc = &priv->ring_control->tx_data[i]; |
||||
if (priv->tx_buf[i]) { |
||||
kfree(priv->tx_buf[i]); |
||||
priv->tx_buf[i] = NULL; |
||||
} |
||||
|
||||
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), |
||||
le16_to_cpu(desc->len), PCI_DMA_TODEVICE); |
||||
|
||||
desc->host_addr = 0; |
||||
desc->device_addr = 0; |
||||
desc->len = 0; |
||||
desc->flags = 0; |
||||
|
||||
i++; |
||||
i %= ARRAY_SIZE(priv->ring_control->tx_data); |
||||
} |
||||
|
||||
i = priv->rx_idx; |
||||
i %= ARRAY_SIZE(priv->ring_control->rx_data); |
||||
priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]); |
||||
idx %= ARRAY_SIZE(priv->ring_control->rx_data); |
||||
while (i != idx) { |
||||
u16 len; |
||||
struct sk_buff *skb; |
||||
desc = &priv->ring_control->rx_data[i]; |
||||
len = le16_to_cpu(desc->len); |
||||
skb = priv->rx_buf[i]; |
||||
|
||||
skb_put(skb, len); |
||||
|
||||
if (p54_rx(dev, skb)) { |
||||
pci_unmap_single(priv->pdev, |
||||
le32_to_cpu(desc->host_addr), |
||||
MAX_RX_SIZE, PCI_DMA_FROMDEVICE); |
||||
|
||||
priv->rx_buf[i] = NULL; |
||||
desc->host_addr = 0; |
||||
} else { |
||||
skb_trim(skb, 0); |
||||
desc->len = cpu_to_le16(MAX_RX_SIZE); |
||||
} |
||||
|
||||
i++; |
||||
i %= ARRAY_SIZE(priv->ring_control->rx_data); |
||||
} |
||||
|
||||
p54p_refill_rx_ring(dev); |
||||
|
||||
wmb(); |
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); |
||||
} else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) |
||||
complete(&priv->boot_comp); |
||||
|
||||
spin_unlock(&priv->lock); |
||||
|
||||
return reg ? IRQ_HANDLED : IRQ_NONE; |
||||
} |
||||
|
||||
static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, |
||||
size_t len, int free_on_tx) |
||||
{ |
||||
struct p54p_priv *priv = dev->priv; |
||||
unsigned long flags; |
||||
struct p54p_desc *desc; |
||||
dma_addr_t mapping; |
||||
u32 device_idx, idx, i; |
||||
|
||||
spin_lock_irqsave(&priv->lock, flags); |
||||
|
||||
device_idx = le32_to_cpu(priv->ring_control->device_idx[1]); |
||||
idx = le32_to_cpu(priv->ring_control->host_idx[1]); |
||||
i = idx % ARRAY_SIZE(priv->ring_control->tx_data); |
||||
|
||||
mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); |
||||
desc = &priv->ring_control->tx_data[i]; |
||||
desc->host_addr = cpu_to_le32(mapping); |
||||
desc->device_addr = data->req_id; |
||||
desc->len = cpu_to_le16(len); |
||||
desc->flags = 0; |
||||
|
||||
wmb(); |
||||
priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1); |
||||
|
||||
if (free_on_tx) |
||||
priv->tx_buf[i] = data; |
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags); |
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); |
||||
P54P_READ(dev_int); |
||||
|
||||
/* FIXME: unlikely to happen because the device usually runs out of
|
||||
memory before we fill the ring up, but we can make it impossible */ |
||||
if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2) |
||||
printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); |
||||
} |
||||
|
||||
static int p54p_open(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54p_priv *priv = dev->priv; |
||||
int err; |
||||
|
||||
init_completion(&priv->boot_comp); |
||||
err = request_irq(priv->pdev->irq, &p54p_interrupt, |
||||
IRQF_SHARED, "prism54pci", dev); |
||||
if (err) { |
||||
printk(KERN_ERR "%s: failed to register IRQ handler\n", |
||||
wiphy_name(dev->wiphy)); |
||||
return err; |
||||
} |
||||
|
||||
memset(priv->ring_control, 0, sizeof(*priv->ring_control)); |
||||
priv->rx_idx = priv->tx_idx = 0; |
||||
p54p_refill_rx_ring(dev); |
||||
|
||||
p54p_upload_firmware(dev); |
||||
|
||||
P54P_WRITE(ring_control_base, priv->ring_control_dma); |
||||
P54P_READ(ring_control_base); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT)); |
||||
P54P_READ(int_enable); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
||||
P54P_READ(dev_int); |
||||
|
||||
if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) { |
||||
printk(KERN_ERR "%s: Cannot boot firmware!\n", |
||||
wiphy_name(dev->wiphy)); |
||||
free_irq(priv->pdev->irq, dev); |
||||
return -ETIMEDOUT; |
||||
} |
||||
|
||||
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)); |
||||
P54P_READ(int_enable); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); |
||||
P54P_READ(dev_int); |
||||
wmb(); |
||||
udelay(10); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void p54p_stop(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54p_priv *priv = dev->priv; |
||||
unsigned int i; |
||||
struct p54p_desc *desc; |
||||
|
||||
P54P_WRITE(int_enable, 0); |
||||
P54P_READ(int_enable); |
||||
udelay(10); |
||||
|
||||
free_irq(priv->pdev->irq, dev); |
||||
|
||||
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { |
||||
desc = &priv->ring_control->rx_data[i]; |
||||
if (desc->host_addr) |
||||
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), |
||||
MAX_RX_SIZE, PCI_DMA_FROMDEVICE); |
||||
kfree_skb(priv->rx_buf[i]); |
||||
priv->rx_buf[i] = NULL; |
||||
} |
||||
|
||||
for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { |
||||
desc = &priv->ring_control->tx_data[i]; |
||||
if (desc->host_addr) |
||||
pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), |
||||
le16_to_cpu(desc->len), PCI_DMA_TODEVICE); |
||||
|
||||
kfree(priv->tx_buf[i]); |
||||
priv->tx_buf[i] = NULL; |
||||
} |
||||
|
||||
memset(priv->ring_control, 0, sizeof(*priv->ring_control)); |
||||
} |
||||
|
||||
static int __devinit p54p_probe(struct pci_dev *pdev, |
||||
const struct pci_device_id *id) |
||||
{ |
||||
struct p54p_priv *priv; |
||||
struct ieee80211_hw *dev; |
||||
unsigned long mem_addr, mem_len; |
||||
int err; |
||||
|
||||
err = pci_enable_device(pdev); |
||||
if (err) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n", |
||||
pci_name(pdev)); |
||||
return err; |
||||
} |
||||
|
||||
mem_addr = pci_resource_start(pdev, 0); |
||||
mem_len = pci_resource_len(pdev, 0); |
||||
if (mem_len < sizeof(struct p54p_csr)) { |
||||
printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n", |
||||
pci_name(pdev)); |
||||
pci_disable_device(pdev); |
||||
return err; |
||||
} |
||||
|
||||
err = pci_request_regions(pdev, "prism54pci"); |
||||
if (err) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n", |
||||
pci_name(pdev)); |
||||
return err; |
||||
} |
||||
|
||||
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || |
||||
pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { |
||||
printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n", |
||||
pci_name(pdev)); |
||||
goto err_free_reg; |
||||
} |
||||
|
||||
pci_set_master(pdev); |
||||
pci_try_set_mwi(pdev); |
||||
|
||||
pci_write_config_byte(pdev, 0x40, 0); |
||||
pci_write_config_byte(pdev, 0x41, 0); |
||||
|
||||
dev = p54_init_common(sizeof(*priv)); |
||||
if (!dev) { |
||||
printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n", |
||||
pci_name(pdev)); |
||||
err = -ENOMEM; |
||||
goto err_free_reg; |
||||
} |
||||
|
||||
priv = dev->priv; |
||||
priv->pdev = pdev; |
||||
|
||||
SET_IEEE80211_DEV(dev, &pdev->dev); |
||||
pci_set_drvdata(pdev, dev); |
||||
|
||||
priv->map = ioremap(mem_addr, mem_len); |
||||
if (!priv->map) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n", |
||||
pci_name(pdev)); |
||||
err = -EINVAL; // TODO: use a better error code?
|
||||
goto err_free_dev; |
||||
} |
||||
|
||||
priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), |
||||
&priv->ring_control_dma); |
||||
if (!priv->ring_control) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n", |
||||
pci_name(pdev)); |
||||
err = -ENOMEM; |
||||
goto err_iounmap; |
||||
} |
||||
memset(priv->ring_control, 0, sizeof(*priv->ring_control)); |
||||
|
||||
err = p54p_upload_firmware(dev); |
||||
if (err) |
||||
goto err_free_desc; |
||||
|
||||
err = p54p_read_eeprom(dev); |
||||
if (err) |
||||
goto err_free_desc; |
||||
|
||||
priv->common.open = p54p_open; |
||||
priv->common.stop = p54p_stop; |
||||
priv->common.tx = p54p_tx; |
||||
|
||||
spin_lock_init(&priv->lock); |
||||
|
||||
err = ieee80211_register_hw(dev); |
||||
if (err) { |
||||
printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n", |
||||
pci_name(pdev)); |
||||
goto err_free_common; |
||||
} |
||||
|
||||
printk(KERN_INFO "%s: hwaddr " MAC_FMT ", isl38%02x\n", |
||||
wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), |
||||
priv->common.version); |
||||
|
||||
return 0; |
||||
|
||||
err_free_common: |
||||
p54_free_common(dev); |
||||
|
||||
err_free_desc: |
||||
pci_free_consistent(pdev, sizeof(*priv->ring_control), |
||||
priv->ring_control, priv->ring_control_dma); |
||||
|
||||
err_iounmap: |
||||
iounmap(priv->map); |
||||
|
||||
err_free_dev: |
||||
pci_set_drvdata(pdev, NULL); |
||||
ieee80211_free_hw(dev); |
||||
|
||||
err_free_reg: |
||||
pci_release_regions(pdev); |
||||
pci_disable_device(pdev); |
||||
return err; |
||||
} |
||||
|
||||
static void __devexit p54p_remove(struct pci_dev *pdev) |
||||
{ |
||||
struct ieee80211_hw *dev = pci_get_drvdata(pdev); |
||||
struct p54p_priv *priv; |
||||
|
||||
if (!dev) |
||||
return; |
||||
|
||||
ieee80211_unregister_hw(dev); |
||||
priv = dev->priv; |
||||
pci_free_consistent(pdev, sizeof(*priv->ring_control), |
||||
priv->ring_control, priv->ring_control_dma); |
||||
p54_free_common(dev); |
||||
iounmap(priv->map); |
||||
pci_release_regions(pdev); |
||||
pci_disable_device(pdev); |
||||
ieee80211_free_hw(dev); |
||||
} |
||||
|
||||
#ifdef CONFIG_PM |
||||
static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) |
||||
{ |
||||
struct ieee80211_hw *dev = pci_get_drvdata(pdev); |
||||
struct p54p_priv *priv = dev->priv; |
||||
|
||||
if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { |
||||
ieee80211_stop_queues(dev); |
||||
p54p_stop(dev); |
||||
} |
||||
|
||||
pci_save_state(pdev); |
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state)); |
||||
return 0; |
||||
} |
||||
|
||||
static int p54p_resume(struct pci_dev *pdev) |
||||
{ |
||||
struct ieee80211_hw *dev = pci_get_drvdata(pdev); |
||||
struct p54p_priv *priv = dev->priv; |
||||
|
||||
pci_set_power_state(pdev, PCI_D0); |
||||
pci_restore_state(pdev); |
||||
|
||||
if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) { |
||||
p54p_open(dev); |
||||
ieee80211_start_queues(dev); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
#endif /* CONFIG_PM */ |
||||
|
||||
static struct pci_driver p54p_driver = { |
||||
.name = "prism54pci", |
||||
.id_table = p54p_table, |
||||
.probe = p54p_probe, |
||||
.remove = __devexit_p(p54p_remove), |
||||
#ifdef CONFIG_PM |
||||
.suspend = p54p_suspend, |
||||
.resume = p54p_resume, |
||||
#endif /* CONFIG_PM */ |
||||
}; |
||||
|
||||
static int __init p54p_init(void) |
||||
{ |
||||
return pci_register_driver(&p54p_driver); |
||||
} |
||||
|
||||
static void __exit p54p_exit(void) |
||||
{ |
||||
pci_unregister_driver(&p54p_driver); |
||||
} |
||||
|
||||
module_init(p54p_init); |
||||
module_exit(p54p_exit); |
@ -0,0 +1,106 @@ |
||||
#ifndef PRISM54PCI_H |
||||
#define PRISM54PCI_H |
||||
|
||||
/*
|
||||
* Defines for PCI based mac80211 Prism54 driver |
||||
* |
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
||||
* |
||||
* Based on the islsm (softmac prism54) driver, which is: |
||||
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
/* Device Interrupt register bits */ |
||||
#define ISL38XX_DEV_INT_RESET 0x0001 |
||||
#define ISL38XX_DEV_INT_UPDATE 0x0002 |
||||
#define ISL38XX_DEV_INT_WAKEUP 0x0008 |
||||
#define ISL38XX_DEV_INT_SLEEP 0x0010 |
||||
#define ISL38XX_DEV_INT_ABORT 0x0020 |
||||
/* these two only used in USB */ |
||||
#define ISL38XX_DEV_INT_DATA 0x0040 |
||||
#define ISL38XX_DEV_INT_MGMT 0x0080 |
||||
|
||||
#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000 |
||||
#define ISL38XX_DEV_INT_PCIUART_DR 0x8000 |
||||
|
||||
/* Interrupt Identification/Acknowledge/Enable register bits */ |
||||
#define ISL38XX_INT_IDENT_UPDATE 0x0002 |
||||
#define ISL38XX_INT_IDENT_INIT 0x0004 |
||||
#define ISL38XX_INT_IDENT_WAKEUP 0x0008 |
||||
#define ISL38XX_INT_IDENT_SLEEP 0x0010 |
||||
#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000 |
||||
#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000 |
||||
|
||||
/* Control/Status register bits */ |
||||
#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 |
||||
#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 |
||||
#define ISL38XX_CTRL_STAT_RESET 0x10000000 |
||||
#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 |
||||
#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 |
||||
#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 |
||||
|
||||
struct p54p_csr { |
||||
__le32 dev_int; |
||||
u8 unused_1[12]; |
||||
__le32 int_ident; |
||||
__le32 int_ack; |
||||
__le32 int_enable; |
||||
u8 unused_2[4]; |
||||
union { |
||||
__le32 ring_control_base; |
||||
__le32 gen_purp_com[2]; |
||||
}; |
||||
u8 unused_3[8]; |
||||
__le32 direct_mem_base; |
||||
u8 unused_4[44]; |
||||
__le32 dma_addr; |
||||
__le32 dma_len; |
||||
__le32 dma_ctrl; |
||||
u8 unused_5[12]; |
||||
__le32 ctrl_stat; |
||||
u8 unused_6[1924]; |
||||
u8 cardbus_cis[0x800]; |
||||
u8 direct_mem_win[0x1000]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
/* usb backend only needs the register defines above */ |
||||
#ifndef PRISM54USB_H |
||||
struct p54p_desc { |
||||
__le32 host_addr; |
||||
__le32 device_addr; |
||||
__le16 len; |
||||
__le16 flags; |
||||
} __attribute__ ((packed)); |
||||
|
||||
struct p54p_ring_control { |
||||
__le32 host_idx[4]; |
||||
__le32 device_idx[4]; |
||||
struct p54p_desc rx_data[8]; |
||||
struct p54p_desc tx_data[32]; |
||||
struct p54p_desc rx_mgmt[4]; |
||||
struct p54p_desc tx_mgmt[4]; |
||||
} __attribute__ ((packed)); |
||||
|
||||
#define P54P_READ(r) __raw_readl(&priv->map->r) |
||||
#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r) |
||||
|
||||
struct p54p_priv { |
||||
struct p54_common common; |
||||
struct pci_dev *pdev; |
||||
struct p54p_csr __iomem *map; |
||||
|
||||
spinlock_t lock; |
||||
struct p54p_ring_control *ring_control; |
||||
dma_addr_t ring_control_dma; |
||||
u32 rx_idx, tx_idx; |
||||
struct sk_buff *rx_buf[8]; |
||||
void *tx_buf[32]; |
||||
struct completion boot_comp; |
||||
}; |
||||
|
||||
#endif /* PRISM54USB_H */ |
||||
#endif /* PRISM54PCI_H */ |
@ -0,0 +1,905 @@ |
||||
|
||||
/*
|
||||
* Linux device driver for USB based Prism54 |
||||
* |
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
||||
* |
||||
* Based on the islsm (softmac prism54) driver, which is: |
||||
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
#include <linux/init.h> |
||||
#include <linux/usb.h> |
||||
#include <linux/pci.h> |
||||
#include <linux/firmware.h> |
||||
#include <linux/etherdevice.h> |
||||
#include <linux/delay.h> |
||||
#include <linux/crc32.h> |
||||
#include <net/mac80211.h> |
||||
|
||||
#include "p54.h" |
||||
#include "p54usb.h" |
||||
|
||||
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); |
||||
MODULE_DESCRIPTION("Prism54 USB wireless driver"); |
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_ALIAS("prism54usb"); |
||||
|
||||
static struct usb_device_id p54u_table[] __devinitdata = { |
||||
/* Version 1 devices (pci chip + net2280) */ |
||||
{USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ |
||||
{USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */ |
||||
{USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */ |
||||
{USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */ |
||||
{USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */ |
||||
{USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ |
||||
{USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ |
||||
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ |
||||
{USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ |
||||
{USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ |
||||
{USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ |
||||
{USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ |
||||
{USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */ |
||||
{USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */ |
||||
{USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ |
||||
|
||||
/* Version 2 devices (3887) */ |
||||
{USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */ |
||||
{USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */ |
||||
{USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */ |
||||
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */ |
||||
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */ |
||||
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */ |
||||
{USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */ |
||||
{USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */ |
||||
{USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/ |
||||
{USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/ |
||||
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */ |
||||
{USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */ |
||||
{USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */ |
||||
{USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ |
||||
{USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */ |
||||
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ |
||||
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ |
||||
{USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ |
||||
{USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ |
||||
{} |
||||
}; |
||||
|
||||
MODULE_DEVICE_TABLE(usb, p54u_table); |
||||
|
||||
static void p54u_rx_cb(struct urb *urb) |
||||
{ |
||||
struct sk_buff *skb = (struct sk_buff *) urb->context; |
||||
struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb; |
||||
struct ieee80211_hw *dev = info->dev; |
||||
struct p54u_priv *priv = dev->priv; |
||||
|
||||
if (unlikely(urb->status)) { |
||||
info->urb = NULL; |
||||
usb_free_urb(urb); |
||||
return; |
||||
} |
||||
|
||||
skb_unlink(skb, &priv->rx_queue); |
||||
skb_put(skb, urb->actual_length); |
||||
if (!priv->hw_type) |
||||
skb_pull(skb, sizeof(struct net2280_tx_hdr)); |
||||
|
||||
if (p54_rx(dev, skb)) { |
||||
skb = dev_alloc_skb(MAX_RX_SIZE); |
||||
if (unlikely(!skb)) { |
||||
usb_free_urb(urb); |
||||
/* TODO check rx queue length and refill *somewhere* */ |
||||
return; |
||||
} |
||||
|
||||
info = (struct p54u_rx_info *) skb->cb; |
||||
info->urb = urb; |
||||
info->dev = dev; |
||||
urb->transfer_buffer = skb_tail_pointer(skb); |
||||
urb->context = skb; |
||||
skb_queue_tail(&priv->rx_queue, skb); |
||||
} else { |
||||
skb_trim(skb, 0); |
||||
skb_queue_tail(&priv->rx_queue, skb); |
||||
} |
||||
|
||||
usb_submit_urb(urb, GFP_ATOMIC); |
||||
} |
||||
|
||||
static void p54u_tx_cb(struct urb *urb) |
||||
{ |
||||
usb_free_urb(urb); |
||||
} |
||||
|
||||
static void p54u_tx_free_cb(struct urb *urb) |
||||
{ |
||||
kfree(urb->transfer_buffer); |
||||
usb_free_urb(urb); |
||||
} |
||||
|
||||
static int p54u_init_urbs(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
struct urb *entry; |
||||
struct sk_buff *skb; |
||||
struct p54u_rx_info *info; |
||||
|
||||
while (skb_queue_len(&priv->rx_queue) < 32) { |
||||
skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL); |
||||
if (!skb) |
||||
break; |
||||
entry = usb_alloc_urb(0, GFP_KERNEL); |
||||
if (!entry) { |
||||
kfree_skb(skb); |
||||
break; |
||||
} |
||||
usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb); |
||||
info = (struct p54u_rx_info *) skb->cb; |
||||
info->urb = entry; |
||||
info->dev = dev; |
||||
skb_queue_tail(&priv->rx_queue, skb); |
||||
usb_submit_urb(entry, GFP_KERNEL); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void p54u_free_urbs(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
struct p54u_rx_info *info; |
||||
struct sk_buff *skb; |
||||
|
||||
while ((skb = skb_dequeue(&priv->rx_queue))) { |
||||
info = (struct p54u_rx_info *) skb->cb; |
||||
if (!info->urb) |
||||
continue; |
||||
|
||||
usb_kill_urb(info->urb); |
||||
kfree_skb(skb); |
||||
} |
||||
} |
||||
|
||||
static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, |
||||
size_t len, int free_on_tx) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
struct urb *addr_urb, *data_urb; |
||||
|
||||
addr_urb = usb_alloc_urb(0, GFP_ATOMIC); |
||||
if (!addr_urb) |
||||
return; |
||||
|
||||
data_urb = usb_alloc_urb(0, GFP_ATOMIC); |
||||
if (!data_urb) { |
||||
usb_free_urb(addr_urb); |
||||
return; |
||||
} |
||||
|
||||
usb_fill_bulk_urb(addr_urb, priv->udev, |
||||
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, |
||||
sizeof(data->req_id), p54u_tx_cb, dev); |
||||
usb_fill_bulk_urb(data_urb, priv->udev, |
||||
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, |
||||
free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); |
||||
|
||||
usb_submit_urb(addr_urb, GFP_ATOMIC); |
||||
usb_submit_urb(data_urb, GFP_ATOMIC); |
||||
} |
||||
|
||||
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, |
||||
size_t len, int free_on_tx) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
struct urb *int_urb, *data_urb; |
||||
struct net2280_tx_hdr *hdr; |
||||
struct net2280_reg_write *reg; |
||||
|
||||
reg = kmalloc(sizeof(*reg), GFP_ATOMIC); |
||||
if (!reg) |
||||
return; |
||||
|
||||
int_urb = usb_alloc_urb(0, GFP_ATOMIC); |
||||
if (!int_urb) { |
||||
kfree(reg); |
||||
return; |
||||
} |
||||
|
||||
data_urb = usb_alloc_urb(0, GFP_ATOMIC); |
||||
if (!data_urb) { |
||||
kfree(reg); |
||||
usb_free_urb(int_urb); |
||||
return; |
||||
} |
||||
|
||||
reg->port = cpu_to_le16(NET2280_DEV_U32); |
||||
reg->addr = cpu_to_le32(P54U_DEV_BASE); |
||||
reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); |
||||
|
||||
len += sizeof(*data); |
||||
hdr = (void *)data - sizeof(*hdr); |
||||
memset(hdr, 0, sizeof(*hdr)); |
||||
hdr->device_addr = data->req_id; |
||||
hdr->len = cpu_to_le16(len); |
||||
|
||||
usb_fill_bulk_urb(int_urb, priv->udev, |
||||
usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), |
||||
p54u_tx_free_cb, dev); |
||||
usb_submit_urb(int_urb, GFP_ATOMIC); |
||||
|
||||
usb_fill_bulk_urb(data_urb, priv->udev, |
||||
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), |
||||
free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); |
||||
usb_submit_urb(data_urb, GFP_ATOMIC); |
||||
} |
||||
|
||||
static int p54u_write(struct p54u_priv *priv, |
||||
struct net2280_reg_write *buf, |
||||
enum net2280_op_type type, |
||||
__le32 addr, __le32 val) |
||||
{ |
||||
unsigned int ep; |
||||
int alen; |
||||
|
||||
if (type & 0x0800) |
||||
ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV); |
||||
else |
||||
ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG); |
||||
|
||||
buf->port = cpu_to_le16(type); |
||||
buf->addr = addr; |
||||
buf->val = val; |
||||
|
||||
return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000); |
||||
} |
||||
|
||||
static int p54u_read(struct p54u_priv *priv, void *buf, |
||||
enum net2280_op_type type, |
||||
__le32 addr, __le32 *val) |
||||
{ |
||||
struct net2280_reg_read *read = buf; |
||||
__le32 *reg = buf; |
||||
unsigned int ep; |
||||
int alen, err; |
||||
|
||||
if (type & 0x0800) |
||||
ep = P54U_PIPE_DEV; |
||||
else |
||||
ep = P54U_PIPE_BRG; |
||||
|
||||
read->port = cpu_to_le16(type); |
||||
read->addr = addr; |
||||
|
||||
err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep), |
||||
read, sizeof(*read), &alen, 1000); |
||||
if (err) |
||||
return err; |
||||
|
||||
err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep), |
||||
reg, sizeof(*reg), &alen, 1000); |
||||
if (err) |
||||
return err; |
||||
|
||||
*val = *reg; |
||||
return 0; |
||||
} |
||||
|
||||
static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep, |
||||
void *data, size_t len) |
||||
{ |
||||
int alen; |
||||
return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep), |
||||
data, len, &alen, 2000); |
||||
} |
||||
|
||||
static int p54u_read_eeprom(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
void *buf; |
||||
struct p54_control_hdr *hdr; |
||||
int err, alen; |
||||
size_t offset = priv->hw_type ? 0x10 : 0x20; |
||||
|
||||
buf = kmalloc(0x2020, GFP_KERNEL); |
||||
if (!buf) { |
||||
printk(KERN_ERR "prism54usb: cannot allocate memory for" |
||||
"eeprom readback!\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
if (priv->hw_type) { |
||||
*((u32 *) buf) = priv->common.rx_start; |
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: addr send failed\n"); |
||||
goto fail; |
||||
} |
||||
} else { |
||||
struct net2280_reg_write *reg = buf; |
||||
reg->port = cpu_to_le16(NET2280_DEV_U32); |
||||
reg->addr = cpu_to_le32(P54U_DEV_BASE); |
||||
reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); |
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg)); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: dev_int send failed\n"); |
||||
goto fail; |
||||
} |
||||
} |
||||
|
||||
hdr = buf + priv->common.tx_hdr_len; |
||||
p54_fill_eeprom_readback(hdr); |
||||
hdr->req_id = cpu_to_le32(priv->common.rx_start); |
||||
if (priv->common.tx_hdr_len) { |
||||
struct net2280_tx_hdr *tx_hdr = buf; |
||||
tx_hdr->device_addr = hdr->req_id; |
||||
tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN); |
||||
} |
||||
|
||||
/* we can just pretend to send 0x2000 bytes of nothing in the headers */ |
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, |
||||
EEPROM_READBACK_LEN + priv->common.tx_hdr_len); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: eeprom req send failed\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
err = usb_bulk_msg(priv->udev, |
||||
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), |
||||
buf, 0x2020, &alen, 1000); |
||||
if (!err && alen > offset) { |
||||
p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset); |
||||
} else { |
||||
printk(KERN_ERR "prism54usb: eeprom read failed!\n"); |
||||
err = -EINVAL; |
||||
goto fail; |
||||
} |
||||
|
||||
fail: |
||||
kfree(buf); |
||||
return err; |
||||
} |
||||
|
||||
static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) |
||||
{ |
||||
static char start_string[] = "~~~~<\r"; |
||||
struct p54u_priv *priv = dev->priv; |
||||
const struct firmware *fw_entry = NULL; |
||||
int err, alen; |
||||
u8 carry = 0; |
||||
u8 *buf, *tmp, *data; |
||||
unsigned int left, remains, block_size; |
||||
struct x2_header *hdr; |
||||
unsigned long timeout; |
||||
|
||||
tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); |
||||
if (!buf) { |
||||
printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); |
||||
err = -ENOMEM; |
||||
goto err_bufalloc; |
||||
} |
||||
|
||||
memcpy(buf, start_string, 4); |
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); |
||||
if (err) { |
||||
printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); |
||||
goto err_reset; |
||||
} |
||||
|
||||
err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); |
||||
if (err) { |
||||
printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); |
||||
goto err_req_fw_failed; |
||||
} |
||||
|
||||
p54_parse_firmware(dev, fw_entry); |
||||
|
||||
left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); |
||||
strcpy(buf, start_string); |
||||
left -= strlen(start_string); |
||||
tmp += strlen(start_string); |
||||
|
||||
data = fw_entry->data; |
||||
remains = fw_entry->size; |
||||
|
||||
hdr = (struct x2_header *)(buf + strlen(start_string)); |
||||
memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE); |
||||
hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR); |
||||
hdr->fw_length = cpu_to_le32(fw_entry->size); |
||||
hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr, |
||||
sizeof(u32)*2)); |
||||
left -= sizeof(*hdr); |
||||
tmp += sizeof(*hdr); |
||||
|
||||
while (remains) { |
||||
while (left--) { |
||||
if (carry) { |
||||
*tmp++ = carry; |
||||
carry = 0; |
||||
remains--; |
||||
continue; |
||||
} |
||||
switch (*data) { |
||||
case '~': |
||||
*tmp++ = '}'; |
||||
carry = '^'; |
||||
break; |
||||
case '}': |
||||
*tmp++ = '}'; |
||||
carry = ']'; |
||||
break; |
||||
default: |
||||
*tmp++ = *data; |
||||
remains--; |
||||
break; |
||||
} |
||||
data++; |
||||
} |
||||
|
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: firmware upload failed!\n"); |
||||
goto err_upload_failed; |
||||
} |
||||
|
||||
tmp = buf; |
||||
left = block_size = min((unsigned int)P54U_FW_BLOCK, remains); |
||||
} |
||||
|
||||
*((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); |
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: firmware upload failed!\n"); |
||||
goto err_upload_failed; |
||||
} |
||||
|
||||
timeout = jiffies + msecs_to_jiffies(1000); |
||||
while (!(err = usb_bulk_msg(priv->udev, |
||||
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { |
||||
if (alen > 2 && !memcmp(buf, "OK", 2)) |
||||
break; |
||||
|
||||
if (alen > 5 && !memcmp(buf, "ERROR", 5)) { |
||||
printk(KERN_INFO "prism54usb: firmware upload failed!\n"); |
||||
err = -EINVAL; |
||||
break; |
||||
} |
||||
|
||||
if (time_after(jiffies, timeout)) { |
||||
printk(KERN_ERR "prism54usb: firmware boot timed out!\n"); |
||||
err = -ETIMEDOUT; |
||||
break; |
||||
} |
||||
} |
||||
if (err) |
||||
goto err_upload_failed; |
||||
|
||||
buf[0] = 'g'; |
||||
buf[1] = '\r'; |
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: firmware boot failed!\n"); |
||||
goto err_upload_failed; |
||||
} |
||||
|
||||
timeout = jiffies + msecs_to_jiffies(1000); |
||||
while (!(err = usb_bulk_msg(priv->udev, |
||||
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { |
||||
if (alen > 0 && buf[0] == 'g') |
||||
break; |
||||
|
||||
if (time_after(jiffies, timeout)) { |
||||
err = -ETIMEDOUT; |
||||
break; |
||||
} |
||||
} |
||||
if (err) |
||||
goto err_upload_failed; |
||||
|
||||
err_upload_failed: |
||||
release_firmware(fw_entry); |
||||
err_req_fw_failed: |
||||
err_reset: |
||||
kfree(buf); |
||||
err_bufalloc: |
||||
return err; |
||||
} |
||||
|
||||
static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
const struct firmware *fw_entry = NULL; |
||||
const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE; |
||||
int err, alen; |
||||
void *buf; |
||||
__le32 reg; |
||||
unsigned int remains, offset; |
||||
u8 *data; |
||||
|
||||
buf = kmalloc(512, GFP_KERNEL); |
||||
if (!buf) { |
||||
printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); |
||||
if (err) { |
||||
printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); |
||||
kfree(buf); |
||||
return err; |
||||
} |
||||
|
||||
p54_parse_firmware(dev, fw_entry); |
||||
|
||||
#define P54U_WRITE(type, addr, data) \ |
||||
do {\
|
||||
err = p54u_write(priv, buf, type,\
|
||||
cpu_to_le32((u32)(unsigned long)addr), data);\
|
||||
if (err) \
|
||||
goto fail;\
|
||||
} while (0) |
||||
|
||||
#define P54U_READ(type, addr) \ |
||||
do {\
|
||||
err = p54u_read(priv, buf, type,\
|
||||
cpu_to_le32((u32)(unsigned long)addr), ®);\
|
||||
if (err)\
|
||||
goto fail;\
|
||||
} while (0) |
||||
|
||||
/* power down net2280 bridge */ |
||||
P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL); |
||||
reg |= cpu_to_le32(P54U_BRG_POWER_DOWN); |
||||
reg &= cpu_to_le32(~P54U_BRG_POWER_UP); |
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); |
||||
|
||||
mdelay(100); |
||||
|
||||
/* power up bridge */ |
||||
reg |= cpu_to_le32(P54U_BRG_POWER_UP); |
||||
reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN); |
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg); |
||||
|
||||
mdelay(100); |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT, |
||||
cpu_to_le32(NET2280_CLK_30Mhz | |
||||
NET2280_PCI_ENABLE | |
||||
NET2280_PCI_SOFT_RESET)); |
||||
|
||||
mdelay(20); |
||||
|
||||
P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND, |
||||
cpu_to_le32(PCI_COMMAND_MEMORY | |
||||
PCI_COMMAND_MASTER)); |
||||
|
||||
P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0, |
||||
cpu_to_le32(NET2280_BASE)); |
||||
|
||||
P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS); |
||||
reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT); |
||||
P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg); |
||||
|
||||
// TODO: we really need this?
|
||||
P54U_READ(NET2280_BRG_U32, NET2280_RELNUM); |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP, |
||||
cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); |
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP, |
||||
cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE)); |
||||
|
||||
P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2, |
||||
cpu_to_le32(NET2280_BASE2)); |
||||
|
||||
/* finally done setting up the bridge */ |
||||
|
||||
P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND, |
||||
cpu_to_le32(PCI_COMMAND_MEMORY | |
||||
PCI_COMMAND_MASTER)); |
||||
|
||||
P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0); |
||||
P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0, |
||||
cpu_to_le32(P54U_DEV_BASE)); |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); |
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, |
||||
cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); |
||||
|
||||
/* do romboot */ |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0); |
||||
|
||||
P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
||||
|
||||
mdelay(20); |
||||
|
||||
reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
||||
|
||||
mdelay(20); |
||||
|
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
||||
|
||||
mdelay(100); |
||||
|
||||
P54U_READ(NET2280_DEV_U32, &devreg->int_ident); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
||||
|
||||
/* finally, we can upload firmware now! */ |
||||
remains = fw_entry->size; |
||||
data = fw_entry->data; |
||||
offset = ISL38XX_DEV_FIRMWARE_ADDR; |
||||
|
||||
while (remains) { |
||||
unsigned int block_len = min(remains, (unsigned int)512); |
||||
memcpy(buf, data, block_len); |
||||
|
||||
err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: firmware block upload " |
||||
"failed\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base, |
||||
cpu_to_le32(0xc0000f00)); |
||||
|
||||
P54U_WRITE(NET2280_DEV_U32, |
||||
0x0020 | (unsigned long)&devreg->direct_mem_win, 0); |
||||
P54U_WRITE(NET2280_DEV_U32, |
||||
0x0020 | (unsigned long)&devreg->direct_mem_win, |
||||
cpu_to_le32(1)); |
||||
|
||||
P54U_WRITE(NET2280_DEV_U32, |
||||
0x0024 | (unsigned long)&devreg->direct_mem_win, |
||||
cpu_to_le32(block_len)); |
||||
P54U_WRITE(NET2280_DEV_U32, |
||||
0x0028 | (unsigned long)&devreg->direct_mem_win, |
||||
cpu_to_le32(offset)); |
||||
|
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr, |
||||
cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR)); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len, |
||||
cpu_to_le32(block_len >> 2)); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl, |
||||
cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER)); |
||||
|
||||
mdelay(10); |
||||
|
||||
P54U_READ(NET2280_DEV_U32, |
||||
0x002C | (unsigned long)&devreg->direct_mem_win); |
||||
if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || |
||||
!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { |
||||
printk(KERN_ERR "prism54usb: firmware DMA transfer " |
||||
"failed\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT, |
||||
cpu_to_le32(NET2280_FIFO_FLUSH)); |
||||
|
||||
remains -= block_len; |
||||
data += block_len; |
||||
offset += block_len; |
||||
} |
||||
|
||||
/* do ramboot */ |
||||
P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); |
||||
reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
||||
|
||||
mdelay(20); |
||||
|
||||
reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
||||
|
||||
reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg); |
||||
|
||||
mdelay(100); |
||||
|
||||
P54U_READ(NET2280_DEV_U32, &devreg->int_ident); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
||||
|
||||
/* start up the firmware */ |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, |
||||
cpu_to_le32(ISL38XX_INT_IDENT_INIT)); |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, |
||||
cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, |
||||
cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE | |
||||
NET2280_USB_INTERRUPT_ENABLE)); |
||||
|
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int, |
||||
cpu_to_le32(ISL38XX_DEV_INT_RESET)); |
||||
|
||||
err = usb_interrupt_msg(priv->udev, |
||||
usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT), |
||||
buf, sizeof(__le32), &alen, 1000); |
||||
if (err || alen != sizeof(__le32)) |
||||
goto fail; |
||||
|
||||
P54U_READ(NET2280_DEV_U32, &devreg->int_ident); |
||||
P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg); |
||||
|
||||
if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))) |
||||
err = -EINVAL; |
||||
|
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0); |
||||
P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1, |
||||
cpu_to_le32(NET2280_PCI_INTA_INTERRUPT)); |
||||
|
||||
#undef P54U_WRITE |
||||
#undef P54U_READ |
||||
|
||||
fail: |
||||
release_firmware(fw_entry); |
||||
kfree(buf); |
||||
return err; |
||||
} |
||||
|
||||
static int p54u_open(struct ieee80211_hw *dev) |
||||
{ |
||||
struct p54u_priv *priv = dev->priv; |
||||
int err; |
||||
|
||||
err = p54u_init_urbs(dev); |
||||
if (err) { |
||||
return err; |
||||
} |
||||
|
||||
priv->common.open = p54u_init_urbs; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static void p54u_stop(struct ieee80211_hw *dev) |
||||
{ |
||||
/* TODO: figure out how to reliably stop the 3887 and net2280 so
|
||||
the hardware is still usable next time we want to start it. |
||||
until then, we just stop listening to the hardware.. */ |
||||
p54u_free_urbs(dev); |
||||
return; |
||||
} |
||||
|
||||
static int __devinit p54u_probe(struct usb_interface *intf, |
||||
const struct usb_device_id *id) |
||||
{ |
||||
struct usb_device *udev = interface_to_usbdev(intf); |
||||
struct ieee80211_hw *dev; |
||||
struct p54u_priv *priv; |
||||
int err; |
||||
unsigned int i, recognized_pipes; |
||||
|
||||
dev = p54_init_common(sizeof(*priv)); |
||||
if (!dev) { |
||||
printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n"); |
||||
return -ENOMEM; |
||||
} |
||||
|
||||
priv = dev->priv; |
||||
|
||||
SET_IEEE80211_DEV(dev, &intf->dev); |
||||
usb_set_intfdata(intf, dev); |
||||
priv->udev = udev; |
||||
|
||||
usb_get_dev(udev); |
||||
|
||||
/* really lazy and simple way of figuring out if we're a 3887 */ |
||||
/* TODO: should just stick the identification in the device table */ |
||||
i = intf->altsetting->desc.bNumEndpoints; |
||||
recognized_pipes = 0; |
||||
while (i--) { |
||||
switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) { |
||||
case P54U_PIPE_DATA: |
||||
case P54U_PIPE_MGMT: |
||||
case P54U_PIPE_BRG: |
||||
case P54U_PIPE_DEV: |
||||
case P54U_PIPE_DATA | USB_DIR_IN: |
||||
case P54U_PIPE_MGMT | USB_DIR_IN: |
||||
case P54U_PIPE_BRG | USB_DIR_IN: |
||||
case P54U_PIPE_DEV | USB_DIR_IN: |
||||
case P54U_PIPE_INT | USB_DIR_IN: |
||||
recognized_pipes++; |
||||
} |
||||
} |
||||
priv->common.open = p54u_open; |
||||
|
||||
if (recognized_pipes < P54U_PIPE_NUMBER) { |
||||
priv->hw_type = P54U_3887; |
||||
priv->common.tx = p54u_tx_3887; |
||||
} else { |
||||
dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr); |
||||
priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr); |
||||
priv->common.tx = p54u_tx_net2280; |
||||
} |
||||
priv->common.stop = p54u_stop; |
||||
|
||||
if (priv->hw_type) |
||||
err = p54u_upload_firmware_3887(dev); |
||||
else |
||||
err = p54u_upload_firmware_net2280(dev); |
||||
if (err) |
||||
goto err_free_dev; |
||||
|
||||
err = p54u_read_eeprom(dev); |
||||
if (err) |
||||
goto err_free_dev; |
||||
|
||||
if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { |
||||
u8 perm_addr[ETH_ALEN]; |
||||
|
||||
printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n"); |
||||
random_ether_addr(perm_addr); |
||||
SET_IEEE80211_PERM_ADDR(dev, perm_addr); |
||||
} |
||||
|
||||
skb_queue_head_init(&priv->rx_queue); |
||||
|
||||
err = ieee80211_register_hw(dev); |
||||
if (err) { |
||||
printk(KERN_ERR "prism54usb: Cannot register netdevice\n"); |
||||
goto err_free_dev; |
||||
} |
||||
|
||||
printk(KERN_INFO "%s: hwaddr " MAC_FMT ", isl38%02x\n", |
||||
wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr), |
||||
priv->common.version); |
||||
|
||||
return 0; |
||||
|
||||
err_free_dev: |
||||
ieee80211_free_hw(dev); |
||||
usb_set_intfdata(intf, NULL); |
||||
usb_put_dev(udev); |
||||
return err; |
||||
} |
||||
|
||||
static void __devexit p54u_disconnect(struct usb_interface *intf) |
||||
{ |
||||
struct ieee80211_hw *dev = usb_get_intfdata(intf); |
||||
struct p54u_priv *priv; |
||||
|
||||
if (!dev) |
||||
return; |
||||
|
||||
ieee80211_unregister_hw(dev); |
||||
|
||||
priv = dev->priv; |
||||
usb_put_dev(interface_to_usbdev(intf)); |
||||
p54_free_common(dev); |
||||
ieee80211_free_hw(dev); |
||||
} |
||||
|
||||
static struct usb_driver p54u_driver = { |
||||
.name = "prism54usb", |
||||
.id_table = p54u_table, |
||||
.probe = p54u_probe, |
||||
.disconnect = p54u_disconnect, |
||||
}; |
||||
|
||||
static int __init p54u_init(void) |
||||
{ |
||||
return usb_register(&p54u_driver); |
||||
} |
||||
|
||||
static void __exit p54u_exit(void) |
||||
{ |
||||
usb_deregister(&p54u_driver); |
||||
} |
||||
|
||||
module_init(p54u_init); |
||||
module_exit(p54u_exit); |
@ -0,0 +1,133 @@ |
||||
#ifndef PRISM54USB_H |
||||
#define PRISM54USB_H |
||||
|
||||
/*
|
||||
* Defines for USB based mac80211 Prism54 driver |
||||
* |
||||
* Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> |
||||
* |
||||
* Based on the islsm (softmac prism54) driver, which is: |
||||
* Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
|
||||
/* for isl3886 register definitions used on ver 1 devices */ |
||||
#include "p54pci.h" |
||||
#include "net2280.h" |
||||
|
||||
/* pci */ |
||||
#define NET2280_BASE 0x10000000 |
||||
#define NET2280_BASE2 0x20000000 |
||||
|
||||
/* gpio */ |
||||
#define P54U_BRG_POWER_UP (1 << GPIO0_DATA) |
||||
#define P54U_BRG_POWER_DOWN (1 << GPIO1_DATA) |
||||
|
||||
/* devinit */ |
||||
#define NET2280_CLK_4Mhz (15 << LOCAL_CLOCK_FREQUENCY) |
||||
#define NET2280_CLK_30Mhz (2 << LOCAL_CLOCK_FREQUENCY) |
||||
#define NET2280_CLK_60Mhz (1 << LOCAL_CLOCK_FREQUENCY) |
||||
#define NET2280_CLK_STOP (0 << LOCAL_CLOCK_FREQUENCY) |
||||
#define NET2280_PCI_ENABLE (1 << PCI_ENABLE) |
||||
#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET) |
||||
|
||||
/* endpoints */ |
||||
#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE (1 << CLEAR_NAK_OUT_PACKETS_MODE) |
||||
#define NET2280_FIFO_FLUSH (1 << FIFO_FLUSH) |
||||
|
||||
/* irq */ |
||||
#define NET2280_USB_INTERRUPT_ENABLE (1 << USB_INTERRUPT_ENABLE) |
||||
#define NET2280_PCI_INTA_INTERRUPT (1 << PCI_INTA_INTERRUPT) |
||||
#define NET2280_PCI_INTA_INTERRUPT_ENABLE (1 << PCI_INTA_INTERRUPT_ENABLE) |
||||
|
||||
/* registers */ |
||||
#define NET2280_DEVINIT 0x00 |
||||
#define NET2280_USBIRQENB1 0x24 |
||||
#define NET2280_IRQSTAT1 0x2c |
||||
#define NET2280_FIFOCTL 0x38 |
||||
#define NET2280_GPIOCTL 0x50 |
||||
#define NET2280_RELNUM 0x88 |
||||
#define NET2280_EPA_RSP 0x324 |
||||
#define NET2280_EPA_STAT 0x32c |
||||
#define NET2280_EPB_STAT 0x34c |
||||
#define NET2280_EPC_RSP 0x364 |
||||
#define NET2280_EPC_STAT 0x36c |
||||
#define NET2280_EPD_STAT 0x38c |
||||
|
||||
#define NET2280_EPA_CFG 0x320 |
||||
#define NET2280_EPB_CFG 0x340 |
||||
#define NET2280_EPC_CFG 0x360 |
||||
#define NET2280_EPD_CFG 0x380 |
||||
#define NET2280_EPE_CFG 0x3A0 |
||||
#define NET2280_EPF_CFG 0x3C0 |
||||
#define P54U_DEV_BASE 0x40000000 |
||||
|
||||
struct net2280_tx_hdr { |
||||
__le32 device_addr; |
||||
__le16 len; |
||||
__le16 follower; /* ? */ |
||||
u8 padding[8]; |
||||
} __attribute__((packed)); |
||||
|
||||
/* Some flags for the isl hardware registers controlling DMA inside the
|
||||
* chip */ |
||||
#define ISL38XX_DMA_STATUS_DONE 0x00000001 |
||||
#define ISL38XX_DMA_STATUS_READY 0x00000002 |
||||
#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000 |
||||
#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004 |
||||
|
||||
enum net2280_op_type { |
||||
NET2280_BRG_U32 = 0x001F, |
||||
NET2280_BRG_CFG_U32 = 0x000F, |
||||
NET2280_BRG_CFG_U16 = 0x0003, |
||||
NET2280_DEV_U32 = 0x080F, |
||||
NET2280_DEV_CFG_U32 = 0x088F, |
||||
NET2280_DEV_CFG_U16 = 0x0883 |
||||
}; |
||||
|
||||
#define P54U_FW_BLOCK 2048 |
||||
|
||||
#define X2_SIGNATURE "x2 " |
||||
#define X2_SIGNATURE_SIZE 4 |
||||
|
||||
struct x2_header { |
||||
u8 signature[X2_SIGNATURE_SIZE]; |
||||
__le32 fw_load_addr; |
||||
__le32 fw_length; |
||||
__le32 crc; |
||||
} __attribute__((packed)); |
||||
|
||||
/* pipes 3 and 4 are not used by the driver */ |
||||
#define P54U_PIPE_NUMBER 9 |
||||
|
||||
enum p54u_pipe_addr { |
||||
P54U_PIPE_DATA = 0x01, |
||||
P54U_PIPE_MGMT = 0x02, |
||||
P54U_PIPE_3 = 0x03, |
||||
P54U_PIPE_4 = 0x04, |
||||
P54U_PIPE_BRG = 0x0d, |
||||
P54U_PIPE_DEV = 0x0e, |
||||
P54U_PIPE_INT = 0x0f |
||||
}; |
||||
|
||||
struct p54u_rx_info { |
||||
struct urb *urb; |
||||
struct ieee80211_hw *dev; |
||||
}; |
||||
|
||||
struct p54u_priv { |
||||
struct p54_common common; |
||||
struct usb_device *udev; |
||||
enum { |
||||
P54U_NET2280 = 0, |
||||
P54U_3887 |
||||
} hw_type; |
||||
|
||||
spinlock_t lock; |
||||
struct sk_buff_head rx_queue; |
||||
}; |
||||
|
||||
#endif /* PRISM54USB_H */ |
Loading…
Reference in new issue