Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | #define WLAN_HOSTIF WLAN_PCI
#include "hfa384x.c"
#include "prism2mgmt.c"
#include "prism2mib.c"
#include "prism2sta.c"
#define PCI_SIZE 0x1000 /* Memory size - 4K bytes */
/* ISL3874A 11Mb/s WLAN controller */
#define PCIVENDOR_INTERSIL 0x1260UL
#define PCIDEVICE_ISL3874 0x3873UL /* [MSM] yeah I know...the ID says
3873. Trust me, it's a 3874. */
/* Samsung SWL-2210P 11Mb/s WLAN controller (uses ISL3874A) */
#define PCIVENDOR_SAMSUNG 0x167dUL
#define PCIDEVICE_SWL_2210P 0xa000UL
#define PCIVENDOR_NETGEAR 0x1385UL /* for MA311 */
/* PCI Class & Sub-Class code, Network-'Other controller' */
#define PCI_CLASS_NETWORK_OTHERS 0x280
/*----------------------------------------------------------------
* prism2sta_probe_pci
*
* Probe routine called when a PCI device w/ matching ID is found.
* The ISL3874 implementation uses the following map:
* BAR0: Prism2.x registers memory mapped, size=4k
* Here's the sequence:
* - Allocate the PCI resources.
* - Read the PCMCIA attribute memory to make sure we have a WLAN card
* - Reset the MAC
* - Initialize the netdev and wlan data
* - Initialize the MAC
*
* Arguments:
* pdev ptr to pci device structure containing info about
* pci configuration.
* id ptr to the device id entry that matched this device.
*
* Returns:
* zero - success
* negative - failed
*
* Side effects:
*
*
* Call context:
* process thread
*
----------------------------------------------------------------*/
static int __devinit
prism2sta_probe_pci(
struct pci_dev *pdev,
const struct pci_device_id *id)
{
int result;
phys_t phymem = 0;
void __iomem *mem = NULL;
wlandevice_t *wlandev = NULL;
hfa384x_t *hw = NULL;
DBFENTER;
/* Enable the pci device */
if (pci_enable_device(pdev)) {
WLAN_LOG_ERROR("%s: pci_enable_device() failed.\n", dev_info);
result = -EIO;
goto fail;
}
/* Figure out our resources */
phymem = pci_resource_start(pdev, 0);
if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
result = -EIO;
goto fail;
}
mem = ioremap(phymem, PCI_SIZE);
if ( mem == 0 ) {
WLAN_LOG_ERROR("%s: ioremap() failed.\n", dev_info);
result = -EIO;
goto fail;
}
/* Log the device */
WLAN_LOG_INFO("A Prism2.5 PCI device found, "
"phymem:0x%llx, irq:%d, mem:0x%p\n",
(unsigned long long)phymem, pdev->irq, mem);
if ((wlandev = create_wlan()) == NULL) {
WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
result = -EIO;
goto fail;
}
hw = wlandev->priv;
if ( wlan_setup(wlandev) != 0 ) {
WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
result = -EIO;
goto fail;
}
/* Setup netdevice's ability to report resources
* Note: the netdevice was allocated by wlan_setup()
*/
wlandev->netdev->irq = pdev->irq;
wlandev->netdev->mem_start = (unsigned long) mem;
wlandev->netdev->mem_end = wlandev->netdev->mem_start +
pci_resource_len(pdev, 0);
/* Initialize the hw data */
hfa384x_create(hw, wlandev->netdev->irq, 0, mem);
hw->wlandev = wlandev;
/* Register the wlandev, this gets us a name and registers the
* linux netdevice.
*/
SET_MODULE_OWNER(wlandev->netdev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev));
#endif
if ( register_wlandev(wlandev) != 0 ) {
WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info);
result = -EIO;
goto fail;
}
#if 0
/* TODO: Move this and an irq test into an hfa384x_testif() routine.
*/
outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr));
if ( reg != PRISM2STA_MAGIC ) {
WLAN_LOG_ERROR("MAC register access test failed!\n");
result = -EIO;
goto fail;
}
#endif
/* Do a chip-level reset on the MAC */
if (prism2_doreset) {
result = hfa384x_corereset(hw,
prism2_reset_holdtime,
prism2_reset_settletime, 0);
if (result != 0) {
WLAN_LOG_ERROR(
"%s: hfa384x_corereset() failed.\n",
dev_info);
unregister_wlandev(wlandev);
hfa384x_destroy(hw);
result = -EIO;
goto fail;
}
}
pci_set_drvdata(pdev, wlandev);
/* Shouldn't actually hook up the IRQ until we
* _know_ things are alright. A test routine would help.
*/
request_irq(wlandev->netdev->irq, hfa384x_interrupt,
SA_SHIRQ, wlandev->name, wlandev);
wlandev->msdstate = WLAN_MSD_HWPRESENT;
result = 0;
goto done;
fail:
pci_set_drvdata(pdev, NULL);
if (wlandev) kfree(wlandev);
if (hw) kfree(hw);
if (mem) iounmap(mem);
pci_release_regions(pdev);
pci_disable_device(pdev);
done:
DBFEXIT;
return result;
}
static void __devexit prism2sta_remove_pci(struct pci_dev *pdev)
{
wlandevice_t *wlandev;
hfa384x_t *hw;
wlandev = (wlandevice_t *) pci_get_drvdata(pdev);
hw = wlandev->priv;
p80211netdev_hwremoved(wlandev);
/* reset hardware */
prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
if (pdev->irq)
free_irq(pdev->irq, wlandev);
unregister_wlandev(wlandev);
/* free local stuff */
if (hw) {
hfa384x_destroy(hw);
kfree(hw);
}
iounmap((void __iomem *)wlandev->netdev->mem_start);
wlan_unsetup(wlandev);
pci_release_regions(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(wlandev);
}
static struct pci_device_id pci_id_tbl[] = {
{
PCIVENDOR_INTERSIL, PCIDEVICE_ISL3874,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
/* Driver data, we just put the name here */
(unsigned long)"Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller"
},
{
PCIVENDOR_INTERSIL, 0x3872,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
/* Driver data, we just put the name here */
(unsigned long)"Intersil Prism2.5 ISL3872 11Mb/s WLAN Controller"
},
{
PCIVENDOR_SAMSUNG, PCIDEVICE_SWL_2210P,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
/* Driver data, we just put the name here */
(unsigned long)"Samsung MagicLAN SWL-2210P 11Mb/s WLAN Controller"
},
{ /* for NetGear MA311 */
PCIVENDOR_NETGEAR, 0x3872,
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
/* Driver data, we just put the name here */
(unsigned long)"Netgear MA311 WLAN Controller"
},
{
0, 0, 0, 0, 0, 0, 0
}
};
MODULE_DEVICE_TABLE(pci, pci_id_tbl);
/* Function declared here because of ptr reference below */
static int __devinit prism2sta_probe_pci(struct pci_dev *pdev,
const struct pci_device_id *id);
static void __devexit prism2sta_remove_pci(struct pci_dev *pdev);
static struct pci_driver prism2_pci_drv_id = {
.name = "prism2_pci",
.id_table = pci_id_tbl,
.probe = prism2sta_probe_pci,
.remove = prism2sta_remove_pci,
#ifdef CONFIG_PM
.suspend = prism2sta_suspend_pci,
.resume = prism2sta_resume_pci,
#endif
};
#ifdef MODULE
static int __init prism2pci_init(void)
{
WLAN_LOG_NOTICE("%s Loaded\n", version);
return pci_module_init(&prism2_pci_drv_id);
};
static void __exit prism2pci_cleanup(void)
{
pci_unregister_driver(&prism2_pci_drv_id);
};
module_init(prism2pci_init);
module_exit(prism2pci_cleanup);
#endif
int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis)
{
int result = 0;
unsigned long timeout;
UINT16 reg;
DBFENTER;
/* Assert reset and wait awhile
* (note: these delays are _really_ long, but they appear to be
* necessary.)
*/
hfa384x_setreg(hw, 0xc5, HFA384x_PCICOR);
timeout = jiffies + HZ/4;
while(time_before(jiffies, timeout)) udelay(5);
if (genesis) {
hfa384x_setreg(hw, genesis, HFA384x_PCIHCR);
timeout = jiffies + HZ/4;
while(time_before(jiffies, timeout)) udelay(5);
}
/* Clear the reset and wait some more
*/
hfa384x_setreg(hw, 0x45, HFA384x_PCICOR);
timeout = jiffies + HZ/2;
while(time_before(jiffies, timeout)) udelay(5);
/* Wait for f/w to complete initialization (CMD:BUSY == 0)
*/
timeout = jiffies + 2*HZ;
reg = hfa384x_getreg(hw, HFA384x_CMD);
while ( HFA384x_CMD_ISBUSY(reg) && time_before( jiffies, timeout) ) {
reg = hfa384x_getreg(hw, HFA384x_CMD);
udelay(10);
}
if (HFA384x_CMD_ISBUSY(reg)) {
WLAN_LOG_WARNING("corereset: Timed out waiting for cmd register.\n");
result=1;
}
DBFEXIT;
return result;
}
|