557 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			557 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
diff -Nru 1/acx_struct.h 2/acx_struct.h
 | 
						|
--- 1/acx_struct.h	2007-10-03 23:42:39.000000000 +0800
 | 
						|
+++ 2/acx_struct.h	2007-10-06 01:15:32.000000000 +0800
 | 
						|
@@ -1425,7 +1425,13 @@
 | 
						|
 
 | 
						|
 	const u16	*io;		/* points to ACX100 or ACX111 PCI I/O register address set */
 | 
						|
 
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 	struct pci_dev	*pdev;
 | 
						|
+#endif
 | 
						|
+#ifdef CONFIG_VLYNQ
 | 
						|
+	struct vlynq_device	*vdev;
 | 
						|
+#endif
 | 
						|
+	struct device *bus_dev;
 | 
						|
 
 | 
						|
 	unsigned long	membase;
 | 
						|
 	unsigned long	membase2;
 | 
						|
diff -Nru 1/pci.c 2/pci.c
 | 
						|
--- 1/pci.c	2007-10-03 23:42:39.000000000 +0800
 | 
						|
+++ 2/pci.c	2007-10-06 01:15:32.000000000 +0800
 | 
						|
@@ -33,11 +33,15 @@
 | 
						|
 #include <linux/ethtool.h>
 | 
						|
 #include <linux/dma-mapping.h>
 | 
						|
 #include <linux/workqueue.h>
 | 
						|
+#ifdef CONFIG_VLYNQ
 | 
						|
+#include <linux/vlynq.h>
 | 
						|
+#endif
 | 
						|
 
 | 
						|
 #include "acx.h"
 | 
						|
 
 | 
						|
 /***********************************************************************
 | 
						|
 */
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 #define PCI_TYPE		(PCI_USES_MEM | PCI_ADDR0 | PCI_NO_ACPI_WAKE)
 | 
						|
 #define PCI_ACX100_REGION1		0x01
 | 
						|
 #define PCI_ACX100_REGION1_SIZE		0x1000	/* Memory size - 4K bytes */
 | 
						|
@@ -74,7 +78,7 @@
 | 
						|
 #define PCI_UNKNOWN	5
 | 
						|
 #define PCI_POWER_ERROR	-1
 | 
						|
 #endif
 | 
						|
-
 | 
						|
+#endif /* CONFIG_PCI */
 | 
						|
 /***********************************************************************
 | 
						|
 */
 | 
						|
 
 | 
						|
@@ -87,12 +91,6 @@
 | 
						|
 static void acxpci_s_up(struct ieee80211_hw *hw);
 | 
						|
 static void acxpci_s_down(struct ieee80211_hw *hw);
 | 
						|
 
 | 
						|
-void acxpci_put_devname(acx_device_t *adev, struct ethtool_drvinfo *info)
 | 
						|
-{
 | 
						|
-
 | 
						|
-        strncpy(info->bus_info,pci_name(adev->pdev), ETHTOOL_BUSINFO_LEN);
 | 
						|
-}
 | 
						|
-
 | 
						|
 /***********************************************************************
 | 
						|
 ** Register access
 | 
						|
 **
 | 
						|
@@ -605,12 +603,12 @@
 | 
						|
 	snprintf(filename, sizeof(filename), "tiacx1%02dc%02X",
 | 
						|
 		 IS_ACX111(adev) * 11, adev->radio_type);
 | 
						|
 
 | 
						|
-	fw_image = acx_s_read_fw(&adev->pdev->dev, filename, &file_size);
 | 
						|
+	fw_image = acx_s_read_fw(adev->bus_dev, filename, &file_size);
 | 
						|
 	if (!fw_image) {
 | 
						|
 		adev->need_radio_fw = 1;
 | 
						|
 		filename[sizeof("tiacx1NN") - 1] = '\0';
 | 
						|
 		fw_image =
 | 
						|
-		    acx_s_read_fw(&adev->pdev->dev, filename, &file_size);
 | 
						|
+		    acx_s_read_fw(adev->bus_dev, filename, &file_size);
 | 
						|
 		if (!fw_image) {
 | 
						|
 			FN_EXIT1(NOT_OK);
 | 
						|
 			return NOT_OK;
 | 
						|
@@ -670,7 +668,7 @@
 | 
						|
 
 | 
						|
 	snprintf(filename, sizeof(filename), "tiacx1%02dr%02X",
 | 
						|
 		 IS_ACX111(adev) * 11, adev->radio_type);
 | 
						|
-	radio_image = acx_s_read_fw(&adev->pdev->dev, filename, &size);
 | 
						|
+	radio_image = acx_s_read_fw(adev->bus_dev, filename, &size);
 | 
						|
 	if (!radio_image) {
 | 
						|
 		printk("acx: can't load radio module '%s'\n", filename);
 | 
						|
 		goto fail;
 | 
						|
@@ -886,7 +884,9 @@
 | 
						|
 
 | 
						|
 	acx_lock(adev, flags);
 | 
						|
 
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 	acxpci_l_reset_mac(adev);
 | 
						|
+#endif
 | 
						|
 
 | 
						|
 	ecpu_ctrl = read_reg16(adev, IO_ACX_ECPU_CTRL) & 1;
 | 
						|
 	if (!ecpu_ctrl) {
 | 
						|
@@ -1426,6 +1426,7 @@
 | 
						|
 };
 | 
						|
 
 | 
						|
 
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 static int __devinit
 | 
						|
 acxpci_e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | 
						|
 {
 | 
						|
@@ -1477,6 +1478,7 @@
 | 
						|
 	/* acx_sem_lock(adev); */
 | 
						|
 	adev->ieee = ieee;
 | 
						|
 	adev->pdev = pdev;
 | 
						|
+	adev->bus_dev = &pdev->dev;
 | 
						|
 	adev->dev_type = DEVTYPE_PCI;
 | 
						|
 
 | 
						|
 /** Finished with private interface **/
 | 
						|
@@ -1916,7 +1918,7 @@
 | 
						|
 	return OK;
 | 
						|
 }
 | 
						|
 #endif /* CONFIG_PM */
 | 
						|
-
 | 
						|
+#endif /* CONFIG_PCI */
 | 
						|
 
 | 
						|
 /***********************************************************************
 | 
						|
 ** acxpci_s_up
 | 
						|
@@ -1998,7 +2000,7 @@
 | 
						|
 	/* then wait until interrupts have finished executing on other CPUs */
 | 
						|
 	acx_lock(adev, flags);
 | 
						|
 	disable_acx_irq(adev);
 | 
						|
-        synchronize_irq(adev->pdev->irq);
 | 
						|
+        synchronize_irq(adev->irq);
 | 
						|
 	acx_unlock(adev, flags);
 | 
						|
 
 | 
						|
 	/* we really don't want to have an asynchronous tasklet disturb us
 | 
						|
@@ -3449,8 +3451,7 @@
 | 
						|
 {
 | 
						|
 	void *ptr;
 | 
						|
 
 | 
						|
-	ptr = dma_alloc_coherent(adev->pdev ? &adev->pdev->dev : NULL,
 | 
						|
-				 size, phy, GFP_KERNEL);
 | 
						|
+	ptr = dma_alloc_coherent(adev->bus_dev, size, phy, GFP_KERNEL);
 | 
						|
 
 | 
						|
 	if (ptr) {
 | 
						|
 		log(L_DEBUG, "%s sz=%d adr=0x%p phy=0x%08llx\n",
 | 
						|
@@ -4016,10 +4017,371 @@
 | 
						|
 	return OK;
 | 
						|
 }
 | 
						|
 
 | 
						|
+#ifdef CONFIG_VLYNQ
 | 
						|
+struct vlynq_reg_config {
 | 
						|
+	u32 offset;
 | 
						|
+	u32 value;
 | 
						|
+};
 | 
						|
+
 | 
						|
+struct vlynq_known {
 | 
						|
+	u32 chip_id;
 | 
						|
+	char name[32];
 | 
						|
+	struct vlynq_mapping rx_mapping[4];
 | 
						|
+	int irq;
 | 
						|
+	int irq_type;
 | 
						|
+	int num_regs;
 | 
						|
+	struct vlynq_reg_config regs[10];
 | 
						|
+};
 | 
						|
+
 | 
						|
+#define CHIP_TNETW1130 0x00000009
 | 
						|
+#define CHIP_TNETW1350 0x00000029
 | 
						|
+
 | 
						|
+static struct vlynq_known known_devices[] = {
 | 
						|
+	{
 | 
						|
+		.chip_id = CHIP_TNETW1130, .name = "TI TNETW1130",
 | 
						|
+		.rx_mapping = {
 | 
						|
+			{ .size = 0x22000, .offset = 0xf0000000 },
 | 
						|
+			{ .size = 0x40000, .offset = 0xc0000000 },
 | 
						|
+			{ .size = 0x0, .offset = 0x0 },
 | 
						|
+			{ .size = 0x0, .offset = 0x0 },
 | 
						|
+		},
 | 
						|
+		.irq = 0,
 | 
						|
+		.irq_type = IRQ_TYPE_EDGE_RISING,
 | 
						|
+		.num_regs = 5,
 | 
						|
+		.regs = {
 | 
						|
+			{
 | 
						|
+				.offset = 0x790,
 | 
						|
+				.value = (0xd0000000 - PHYS_OFFSET)
 | 
						|
+			},
 | 
						|
+			{
 | 
						|
+				.offset = 0x794,
 | 
						|
+				.value = (0xd0000000 - PHYS_OFFSET)
 | 
						|
+			},
 | 
						|
+			{ .offset = 0x740, .value = 0 },
 | 
						|
+			{ .offset = 0x744, .value = 0x00010000 },
 | 
						|
+			{ .offset = 0x764, .value = 0x00010000 },
 | 
						|
+		},
 | 
						|
+	},
 | 
						|
+	{
 | 
						|
+		.chip_id = CHIP_TNETW1350, .name = "TI TNETW1350",
 | 
						|
+		.rx_mapping = {
 | 
						|
+			{ .size = 0x100000, .offset = 0x00300000 },
 | 
						|
+			{ .size = 0x80000, .offset = 0x00000000 },
 | 
						|
+			{ .size = 0x0, .offset = 0x0 },
 | 
						|
+			{ .size = 0x0, .offset = 0x0 },
 | 
						|
+		},
 | 
						|
+		.irq = 0,
 | 
						|
+		.irq_type = IRQ_TYPE_EDGE_RISING,
 | 
						|
+		.num_regs = 5,
 | 
						|
+		.regs = {
 | 
						|
+			{
 | 
						|
+				.offset = 0x790,
 | 
						|
+				.value = (0x60000000 - PHYS_OFFSET)
 | 
						|
+			},
 | 
						|
+			{
 | 
						|
+				.offset = 0x794,
 | 
						|
+				.value = (0x60000000 - PHYS_OFFSET)
 | 
						|
+			},
 | 
						|
+			{ .offset = 0x740, .value = 0 },
 | 
						|
+			{ .offset = 0x744, .value = 0x00010000 },
 | 
						|
+			{ .offset = 0x764, .value = 0x00010000 },
 | 
						|
+		},
 | 
						|
+	},
 | 
						|
+};
 | 
						|
+
 | 
						|
+static struct vlynq_device_id acx_vlynq_id[] = {
 | 
						|
+	{ CHIP_TNETW1130, vlynq_div_auto, 0 },
 | 
						|
+	{ CHIP_TNETW1350, vlynq_div_auto, 1 },
 | 
						|
+	{ 0, 0, 0 },
 | 
						|
+};
 | 
						|
+
 | 
						|
+static __devinit int vlynq_probe(struct vlynq_device *vdev,
 | 
						|
+				 struct vlynq_device_id *id)
 | 
						|
+{
 | 
						|
+	int result = -EIO, i;
 | 
						|
+	u32 addr;
 | 
						|
+	struct ieee80211_hw *ieee;
 | 
						|
+	acx_device_t *adev = NULL;
 | 
						|
+	acx111_ie_configoption_t co;
 | 
						|
+	struct vlynq_mapping mapping[4] = { { 0, }, };
 | 
						|
+	struct vlynq_known *match = NULL;
 | 
						|
+
 | 
						|
+	FN_ENTER;
 | 
						|
+	result = vlynq_enable_device(vdev);
 | 
						|
+	if (result)
 | 
						|
+		return result;
 | 
						|
+
 | 
						|
+	match = &known_devices[id->driver_data];
 | 
						|
+
 | 
						|
+	if (!match) {
 | 
						|
+		result = -ENODEV;
 | 
						|
+		goto fail;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	mapping[0].offset = ARCH_PFN_OFFSET << PAGE_SHIFT;
 | 
						|
+	mapping[0].size = 0x02000000;
 | 
						|
+	vlynq_set_local_mapping(vdev, vdev->mem_start, mapping);
 | 
						|
+	vlynq_set_remote_mapping(vdev, 0, match->rx_mapping);
 | 
						|
+
 | 
						|
+	set_irq_type(vlynq_virq_to_irq(vdev, match->irq), match->irq_type);
 | 
						|
+
 | 
						|
+	addr = (u32)ioremap(vdev->mem_start, 0x1000);
 | 
						|
+	if (!addr) {
 | 
						|
+		printk(KERN_ERR "%s: failed to remap io memory\n",
 | 
						|
+		       vdev->dev.bus_id);
 | 
						|
+		result = -ENXIO;
 | 
						|
+		goto fail;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	for (i = 0; i < match->num_regs; i++)
 | 
						|
+		iowrite32(match->regs[i].value,
 | 
						|
+			  (u32 *)(addr + match->regs[i].offset));
 | 
						|
+
 | 
						|
+	iounmap((void *)addr);
 | 
						|
+
 | 
						|
+	ieee = ieee80211_alloc_hw(sizeof(struct acx_device), &acxpci_hw_ops);
 | 
						|
+	if (!ieee) {
 | 
						|
+		printk("acx: could not allocate ieee80211 structure %s\n",
 | 
						|
+		       vdev->dev.bus_id);
 | 
						|
+		goto fail_alloc_netdev;
 | 
						|
+	}
 | 
						|
+	ieee->flags &=	 (~IEEE80211_HW_RX_INCLUDES_FCS &
 | 
						|
+			  ~IEEE80211_HW_MONITOR_DURING_OPER) |
 | 
						|
+			 IEEE80211_HW_WEP_INCLUDE_IV;
 | 
						|
+	ieee->queues = 1;
 | 
						|
+
 | 
						|
+	adev = ieee2adev(ieee);
 | 
						|
+
 | 
						|
+	memset(adev, 0, sizeof(*adev));
 | 
						|
+	/** Set up our private interface **/
 | 
						|
+	spin_lock_init(&adev->lock);	/* initial state: unlocked */
 | 
						|
+	/* We do not start with downed sem: we want PARANOID_LOCKING to work */
 | 
						|
+	mutex_init(&adev->mutex);
 | 
						|
+	/* since nobody can see new netdev yet, we can as well
 | 
						|
+	 ** just _presume_ that we're under sem (instead of actually taking it): */
 | 
						|
+	/* acx_sem_lock(adev); */
 | 
						|
+	adev->ieee = ieee;
 | 
						|
+	adev->vdev = vdev;
 | 
						|
+	adev->bus_dev = &vdev->dev;
 | 
						|
+	adev->dev_type = DEVTYPE_PCI;
 | 
						|
+
 | 
						|
+/** Finished with private interface **/
 | 
						|
+
 | 
						|
+	vlynq_set_drvdata(vdev, ieee);
 | 
						|
+	if (!request_mem_region(vdev->mem_start, vdev->mem_end - vdev->mem_start, "acx")) {
 | 
						|
+		printk("acx: cannot reserve VLYNQ memory region\n");
 | 
						|
+		goto fail_request_mem_region;
 | 
						|
+	}
 | 
						|
+	adev->iobase = ioremap(vdev->mem_start, vdev->mem_end - vdev->mem_start);
 | 
						|
+	if (!adev->iobase) {
 | 
						|
+		printk("acx: ioremap() FAILED\n");
 | 
						|
+		goto fail_ioremap;
 | 
						|
+	}
 | 
						|
+	adev->iobase2 = adev->iobase + match->rx_mapping[0].size;
 | 
						|
+	adev->chip_type = CHIPTYPE_ACX111;
 | 
						|
+	adev->chip_name = match->name;
 | 
						|
+	adev->io = IO_ACX111;
 | 
						|
+	adev->irq = vlynq_virq_to_irq(vdev, match->irq);
 | 
						|
+
 | 
						|
+	printk("acx: found %s-based wireless network card at %s, irq:%d, "
 | 
						|
+	       "phymem:0x%x, mem:0x%p\n",
 | 
						|
+	       match->name, vdev->dev.bus_id, adev->irq,
 | 
						|
+	       vdev->mem_start, adev->iobase);
 | 
						|
+	log(L_ANY, "initial debug setting is 0x%04X\n", acx_debug);
 | 
						|
+
 | 
						|
+	if (0 == adev->irq) {
 | 
						|
+		printk("acx: can't use IRQ 0\n");
 | 
						|
+		goto fail_irq;
 | 
						|
+	}
 | 
						|
+	SET_IEEE80211_DEV(ieee, &vdev->dev);
 | 
						|
+
 | 
						|
+
 | 
						|
+	/* to find crashes due to weird driver access
 | 
						|
+	 * to unconfigured interface (ifup) */
 | 
						|
+	adev->mgmt_timer.function = (void (*)(unsigned long))0x0000dead;
 | 
						|
+
 | 
						|
+
 | 
						|
+	/* ok, pci setup is finished, now start initializing the card */
 | 
						|
+
 | 
						|
+	/* NB: read_reg() reads may return bogus data before reset_dev(),
 | 
						|
+	 * since the firmware which directly controls large parts of the I/O
 | 
						|
+	 * registers isn't initialized yet.
 | 
						|
+	 * acx100 seems to be more affected than acx111 */
 | 
						|
+	if (OK != acxpci_s_reset_dev(adev))
 | 
						|
+		goto fail_reset;
 | 
						|
+
 | 
						|
+	if (OK != acx_s_init_mac(adev))
 | 
						|
+		goto fail_init_mac;
 | 
						|
+
 | 
						|
+	acx_s_interrogate(adev, &co, ACX111_IE_CONFIG_OPTIONS);
 | 
						|
+/* TODO: merge them into one function, they are called just once and are the same for pci & usb */
 | 
						|
+	if (OK != acxpci_read_eeprom_byte(adev, 0x05, &adev->eeprom_version))
 | 
						|
+		goto fail_read_eeprom_version;
 | 
						|
+
 | 
						|
+	acx_s_parse_configoption(adev, &co);
 | 
						|
+	acx_s_set_defaults(adev);
 | 
						|
+	acx_s_get_firmware_version(adev);	/* needs to be after acx_s_init_mac() */
 | 
						|
+	acx_display_hardware_details(adev);
 | 
						|
+
 | 
						|
+	/* Register the card, AFTER everything else has been set up,
 | 
						|
+	 * since otherwise an ioctl could step on our feet due to
 | 
						|
+	 * firmware operations happening in parallel or uninitialized data */
 | 
						|
+
 | 
						|
+
 | 
						|
+	acx_proc_register_entries(ieee);
 | 
						|
+
 | 
						|
+	/* Now we have our device, so make sure the kernel doesn't try
 | 
						|
+	 * to send packets even though we're not associated to a network yet */
 | 
						|
+
 | 
						|
+	/* after register_netdev() userspace may start working with dev
 | 
						|
+	 * (in particular, on other CPUs), we only need to up the sem */
 | 
						|
+	/* acx_sem_unlock(adev); */
 | 
						|
+
 | 
						|
+	printk("acx " ACX_RELEASE ": net device %s, driver compiled "
 | 
						|
+	       "against wireless extensions %d and Linux %s\n",
 | 
						|
+	       wiphy_name(adev->ieee->wiphy), WIRELESS_EXT, UTS_RELEASE);
 | 
						|
+
 | 
						|
+	MAC_COPY(adev->ieee->wiphy->perm_addr, adev->dev_addr);
 | 
						|
+
 | 
						|
+	log(L_IRQ | L_INIT, "using IRQ %d\n", adev->irq);
 | 
						|
+
 | 
						|
+/** done with board specific setup **/
 | 
						|
+
 | 
						|
+	acx_init_task_scheduler(adev);
 | 
						|
+	result = ieee80211_register_hw(adev->ieee);
 | 
						|
+	if (OK != result) {
 | 
						|
+		printk("acx: ieee80211_register_hw() FAILED: %d\n", result);
 | 
						|
+		goto fail_register_netdev;
 | 
						|
+	}
 | 
						|
+#if CMD_DISCOVERY
 | 
						|
+	great_inquisitor(adev);
 | 
						|
+#endif
 | 
						|
+
 | 
						|
+	result = OK;
 | 
						|
+	goto done;
 | 
						|
+
 | 
						|
+	/* error paths: undo everything in reverse order... */
 | 
						|
+
 | 
						|
+
 | 
						|
+	acxpci_s_delete_dma_regions(adev);
 | 
						|
+
 | 
						|
+      fail_init_mac:
 | 
						|
+      fail_read_eeprom_version:
 | 
						|
+      fail_reset:
 | 
						|
+
 | 
						|
+      fail_alloc_netdev:
 | 
						|
+      fail_irq:
 | 
						|
+
 | 
						|
+	iounmap(adev->iobase);
 | 
						|
+      fail_ioremap:
 | 
						|
+
 | 
						|
+	release_mem_region(vdev->mem_start, vdev->mem_end - vdev->mem_start);
 | 
						|
+      fail_request_mem_region:
 | 
						|
+      fail_register_netdev:
 | 
						|
+	ieee80211_free_hw(ieee);
 | 
						|
+      fail:
 | 
						|
+	vlynq_disable_device(vdev);
 | 
						|
+      done:
 | 
						|
+	FN_EXIT1(result);
 | 
						|
+	return result;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static void vlynq_remove(struct vlynq_device *vdev)
 | 
						|
+{
 | 
						|
+	struct ieee80211_hw *hw = vlynq_get_drvdata(vdev);
 | 
						|
+	acx_device_t *adev = ieee2adev(hw);
 | 
						|
+	unsigned long flags;
 | 
						|
+	FN_ENTER;
 | 
						|
+
 | 
						|
+	if (!hw) {
 | 
						|
+		log(L_DEBUG, "%s: card is unused. Skipping any release code\n",
 | 
						|
+		    __func__);
 | 
						|
+		goto end;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+
 | 
						|
+	acx_lock(adev, flags);
 | 
						|
+	acx_unlock(adev, flags);
 | 
						|
+	adev->initialized = 0;
 | 
						|
+
 | 
						|
+	/* If device wasn't hot unplugged... */
 | 
						|
+	if (adev_present(adev)) {
 | 
						|
+
 | 
						|
+		acx_sem_lock(adev);
 | 
						|
+
 | 
						|
+		/* disable both Tx and Rx to shut radio down properly */
 | 
						|
+		if (adev->initialized) {
 | 
						|
+			acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_TX, NULL, 0);
 | 
						|
+			acx_s_issue_cmd(adev, ACX1xx_CMD_DISABLE_RX, NULL, 0);
 | 
						|
+		}
 | 
						|
+		acx_lock(adev, flags);
 | 
						|
+		/* disable power LED to save power :-) */
 | 
						|
+		log(L_INIT, "switching off power LED to save power\n");
 | 
						|
+		acxpci_l_power_led(adev, 0);
 | 
						|
+		/* stop our eCPU */
 | 
						|
+		acx_unlock(adev, flags);
 | 
						|
+
 | 
						|
+		acx_sem_unlock(adev);
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	/* unregister the device to not let the kernel
 | 
						|
+	 * (e.g. ioctls) access a half-deconfigured device
 | 
						|
+	 * NB: this will cause acxpci_e_close() to be called,
 | 
						|
+	 * thus we shouldn't call it under sem!
 | 
						|
+	 * Well, netdev did, but ieee80211 stack does not, so we
 | 
						|
+	 * have to do so manually...
 | 
						|
+	 */
 | 
						|
+	acxpci_e_close(hw);
 | 
						|
+	log(L_INIT, "removing device %s\n", wiphy_name(adev->ieee->wiphy));
 | 
						|
+	ieee80211_unregister_hw(adev->ieee);
 | 
						|
+
 | 
						|
+	/* unregister_netdev ensures that no references to us left.
 | 
						|
+	 * For paranoid reasons we continue to follow the rules */
 | 
						|
+	acx_sem_lock(adev);
 | 
						|
+
 | 
						|
+	if (adev->dev_state_mask & ACX_STATE_IFACE_UP) {
 | 
						|
+		acxpci_s_down(hw);
 | 
						|
+		CLEAR_BIT(adev->dev_state_mask, ACX_STATE_IFACE_UP);
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	acx_proc_unregister_entries(adev->ieee);
 | 
						|
+
 | 
						|
+	/* finally, clean up PCI bus state */
 | 
						|
+	acxpci_s_delete_dma_regions(adev);
 | 
						|
+	if (adev->iobase)
 | 
						|
+		iounmap(adev->iobase);
 | 
						|
+	if (adev->iobase2)
 | 
						|
+		iounmap(adev->iobase2);
 | 
						|
+	release_mem_region(vdev->mem_start, vdev->mem_end - vdev->mem_start);
 | 
						|
+
 | 
						|
+	/* remove dev registration */
 | 
						|
+
 | 
						|
+	free_irq(adev->irq, adev);
 | 
						|
+	acx_sem_unlock(adev);
 | 
						|
+	vlynq_disable_device(vdev);
 | 
						|
+
 | 
						|
+	/* Free netdev (quite late,
 | 
						|
+	 * since otherwise we might get caught off-guard
 | 
						|
+	 * by a netdev timeout handler execution
 | 
						|
+	 * expecting to see a working dev...) */
 | 
						|
+	ieee80211_free_hw(adev->ieee);
 | 
						|
+
 | 
						|
+      end:
 | 
						|
+	FN_EXIT0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static struct vlynq_driver vlynq_acx = {
 | 
						|
+	.name = "acx_vlynq",
 | 
						|
+	.id_table = acx_vlynq_id,
 | 
						|
+	.probe = vlynq_probe,
 | 
						|
+	.remove = __devexit_p(vlynq_remove),
 | 
						|
+};
 | 
						|
+#endif
 | 
						|
 
 | 
						|
 /***********************************************************************
 | 
						|
 ** Data for init_module/cleanup_module
 | 
						|
 */
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 static const struct pci_device_id acxpci_id_tbl[] __devinitdata = {
 | 
						|
 	{
 | 
						|
 	 .vendor = PCI_VENDOR_ID_TI,
 | 
						|
@@ -4071,7 +4433,7 @@
 | 
						|
 	.resume = acxpci_e_resume
 | 
						|
 #endif /* CONFIG_PM */
 | 
						|
 };
 | 
						|
-
 | 
						|
+#endif /* CONFIG_PCI */
 | 
						|
 
 | 
						|
 /***********************************************************************
 | 
						|
 ** acxpci_e_init_module
 | 
						|
@@ -4080,7 +4442,7 @@
 | 
						|
 */
 | 
						|
 int __init acxpci_e_init_module(void)
 | 
						|
 {
 | 
						|
-	int res;
 | 
						|
+	int res = 0;
 | 
						|
 
 | 
						|
 	FN_ENTER;
 | 
						|
 
 | 
						|
@@ -4100,10 +4462,15 @@
 | 
						|
 #endif
 | 
						|
 	log(L_INIT,
 | 
						|
 	    "acx: " ENDIANNESS_STRING
 | 
						|
-	    "acx: PCI module " ACX_RELEASE " initialized, "
 | 
						|
+	    "acx: PCI/VLYNQ module " ACX_RELEASE " initialized, "
 | 
						|
 	    "waiting for cards to probe...\n");
 | 
						|
 
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 	res = pci_register_driver(&acxpci_drv_id);
 | 
						|
+#endif
 | 
						|
+#ifdef CONFIG_VLYNQ
 | 
						|
+	res = vlynq_register_driver(&vlynq_acx);
 | 
						|
+#endif
 | 
						|
 	FN_EXIT1(res);
 | 
						|
 	return res;
 | 
						|
 }
 | 
						|
@@ -4119,7 +4486,12 @@
 | 
						|
 {
 | 
						|
 	FN_ENTER;
 | 
						|
 
 | 
						|
+#ifdef CONFIG_VLYNQ
 | 
						|
+	vlynq_unregister_driver(&vlynq_acx);
 | 
						|
+#endif
 | 
						|
+#ifdef CONFIG_PCI
 | 
						|
 	pci_unregister_driver(&acxpci_drv_id);
 | 
						|
+#endif
 | 
						|
 
 | 
						|
 	FN_EXIT0;
 | 
						|
 }
 |