1/******************************************************************************* 2 * Agere Systems Inc. 3 * Wireless device driver for Linux (wlags49). 4 * 5 * Copyright (c) 1998-2003 Agere Systems Inc. 6 * All rights reserved. 7 * http://www.agere.com 8 * 9 * Initially developed by TriplePoint, Inc. 10 * http://www.triplepoint.com 11 * 12 *------------------------------------------------------------------------------ 13 * 14 * This file contains processing and initialization specific to Card Services 15 * devices (PCMCIA, CF). 16 * 17 *------------------------------------------------------------------------------ 18 * 19 * SOFTWARE LICENSE 20 * 21 * This software is provided subject to the following terms and conditions, 22 * which you should read carefully before using the software. Using this 23 * software indicates your acceptance of these terms and conditions. If you do 24 * not agree with these terms and conditions, do not use the software. 25 * 26 * Copyright (c) 2003 Agere Systems Inc. 27 * All rights reserved. 28 * 29 * Redistribution and use in source or binary forms, with or without 30 * modifications, are permitted provided that the following conditions are met: 31 * 32 * . Redistributions of source code must retain the above copyright notice, this 33 * list of conditions and the following Disclaimer as comments in the code as 34 * well as in the documentation and/or other materials provided with the 35 * distribution. 36 * 37 * . Redistributions in binary form must reproduce the above copyright notice, 38 * this list of conditions and the following Disclaimer in the documentation 39 * and/or other materials provided with the distribution. 40 * 41 * . Neither the name of Agere Systems Inc. nor the names of the contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * Disclaimer 46 * 47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 48 * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF 49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY 50 * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN 51 * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY 52 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 53 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 54 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 55 * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 58 * DAMAGE. 59 * 60 ******************************************************************************/ 61 62/******************************************************************************* 63 * include files 64 ******************************************************************************/ 65#include <wl_version.h> 66 67#include <linux/kernel.h> 68#include <linux/sched.h> 69#include <linux/ptrace.h> 70#include <linux/ctype.h> 71#include <linux/string.h> 72#include <linux/timer.h> 73#include <linux/interrupt.h> 74#include <linux/in.h> 75#include <linux/delay.h> 76#include <asm/io.h> 77#include <asm/system.h> 78#include <asm/bitops.h> 79 80#include <linux/netdevice.h> 81#include <linux/etherdevice.h> 82#include <linux/skbuff.h> 83#include <linux/if_arp.h> 84#include <linux/ioport.h> 85 86#include <pcmcia/cs.h> 87#include <pcmcia/cistpl.h> 88#include <pcmcia/cisreg.h> 89#include <pcmcia/ciscode.h> 90#include <pcmcia/ds.h> 91#include <debug.h> 92 93#include <hcf.h> 94#include <dhf.h> 95#include <hcfdef.h> 96 97#include <wl_if.h> 98#include <wl_internal.h> 99#include <wl_util.h> 100#include <wl_main.h> 101#include <wl_netdev.h> 102#include <wl_cs.h> 103#include <wl_sysfs.h> 104 105 106/******************************************************************************* 107 * global definitions 108 ******************************************************************************/ 109#if DBG 110extern dbg_info_t *DbgInfo; 111#endif /* DBG */ 112 113 114/******************************************************************************* 115 * wl_adapter_attach() 116 ******************************************************************************* 117 * 118 * DESCRIPTION: 119 * 120 * Creates an instance of the driver, allocating local data structures for 121 * one device. The device is registered with Card Services. 122 * 123 * PARAMETERS: 124 * 125 * none 126 * 127 * RETURNS: 128 * 129 * pointer to an allocated dev_link_t structure 130 * NULL on failure 131 * 132 ******************************************************************************/ 133static int wl_adapter_attach(struct pcmcia_device *link) 134{ 135 struct net_device *dev; 136 struct wl_private *lp; 137 /*--------------------------------------------------------------------*/ 138 139 DBG_FUNC("wl_adapter_attach"); 140 DBG_ENTER(DbgInfo); 141 142 dev = wl_device_alloc(); 143 if (dev == NULL) { 144 DBG_ERROR(DbgInfo, "wl_device_alloc returned NULL\n"); 145 return -ENOMEM; 146 } 147 148 link->resource[0]->end = HCF_NUM_IO_PORTS; 149 link->resource[0]->flags= IO_DATA_PATH_WIDTH_16; 150 link->conf.Attributes = CONF_ENABLE_IRQ; 151 link->conf.IntType = INT_MEMORY_AND_IO; 152 link->conf.ConfigIndex = 5; 153 link->conf.Present = PRESENT_OPTION; 154 155 link->priv = dev; 156 lp = wl_priv(dev); 157 lp->link = link; 158 159 wl_adapter_insert(link); 160 161 DBG_LEAVE(DbgInfo); 162 return 0; 163} /* wl_adapter_attach */ 164/*============================================================================*/ 165 166 167 168/******************************************************************************* 169 * wl_adapter_detach() 170 ******************************************************************************* 171 * 172 * DESCRIPTION: 173 * 174 * This deletes a driver "instance". The device is de-registered with Card 175 * Services. If it has been released, then the net device is unregistered, and 176 * all local data structures are freed. Otherwise, the structures will be 177 * freed when the device is released. 178 * 179 * PARAMETERS: 180 * 181 * link - pointer to the dev_link_t structure representing the device to 182 * detach 183 * 184 * RETURNS: 185 * 186 * N/A 187 * 188 ******************************************************************************/ 189static void wl_adapter_detach(struct pcmcia_device *link) 190{ 191 struct net_device *dev = link->priv; 192 /*--------------------------------------------------------------------*/ 193 194 DBG_FUNC("wl_adapter_detach"); 195 DBG_ENTER(DbgInfo); 196 DBG_PARAM(DbgInfo, "link", "0x%p", link); 197 198 wl_adapter_release(link); 199 200 if (dev) { 201 unregister_wlags_sysfs(dev); 202 unregister_netdev(dev); 203 } 204 205 wl_device_dealloc(dev); 206 207 DBG_LEAVE(DbgInfo); 208} /* wl_adapter_detach */ 209/*============================================================================*/ 210 211 212/******************************************************************************* 213 * wl_adapter_release() 214 ******************************************************************************* 215 * 216 * DESCRIPTION: 217 * 218 * After a card is removed, this routine will release the PCMCIA 219 * configuration. If the device is still open, this will be postponed until it 220 * is closed. 221 * 222 * PARAMETERS: 223 * 224 * arg - a u_long representing a pointer to a dev_link_t structure for the 225 * device to be released. 226 * 227 * RETURNS: 228 * 229 * N/A 230 * 231 ******************************************************************************/ 232void wl_adapter_release(struct pcmcia_device *link) 233{ 234 DBG_FUNC("wl_adapter_release"); 235 DBG_ENTER(DbgInfo); 236 DBG_PARAM(DbgInfo, "link", "0x%p", link); 237 238 /* Stop hardware */ 239 wl_remove(link->priv); 240 241 pcmcia_disable_device(link); 242 243 DBG_LEAVE(DbgInfo); 244} /* wl_adapter_release */ 245/*============================================================================*/ 246 247static int wl_adapter_suspend(struct pcmcia_device *link) 248{ 249 struct net_device *dev = link->priv; 250 251 /* if (link->open) { */ 252 netif_device_detach(dev); 253 wl_suspend(dev); 254 /* CHECK! pcmcia_release_configuration(link->handle); */ 255 /* } */ 256 257 return 0; 258} /* wl_adapter_suspend */ 259 260static int wl_adapter_resume(struct pcmcia_device *link) 261{ 262 struct net_device *dev = link->priv; 263 264 wl_resume(dev); 265 266 netif_device_attach(dev); 267 268 return 0; 269} /* wl_adapter_resume */ 270 271/******************************************************************************* 272 * wl_adapter_insert() 273 ******************************************************************************* 274 * 275 * DESCRIPTION: 276 * 277 * wl_adapter_insert() is scheduled to run after a CARD_INSERTION event is 278 * received, to configure the PCMCIA socket, and to make the ethernet device 279 * available to the system. 280 * 281 * PARAMETERS: 282 * 283 * link - pointer to the dev_link_t structure representing the device to 284 * insert 285 * 286 * RETURNS: 287 * 288 * N/A 289 * 290 ******************************************************************************/ 291void wl_adapter_insert(struct pcmcia_device *link) 292{ 293 struct net_device *dev; 294 int i; 295 int ret; 296 /*--------------------------------------------------------------------*/ 297 298 DBG_FUNC("wl_adapter_insert"); 299 DBG_ENTER(DbgInfo); 300 DBG_PARAM(DbgInfo, "link", "0x%p", link); 301 302 dev = link->priv; 303 304 /* Do we need to allocate an interrupt? */ 305 link->conf.Attributes |= CONF_ENABLE_IRQ; 306 link->io_lines = 6; 307 308 ret = pcmcia_request_io(link); 309 if (ret != 0) 310 goto failed; 311 312 ret = pcmcia_request_irq(link, (void *) wl_isr); 313 if (ret != 0) 314 goto failed; 315 316 ret = pcmcia_request_configuration(link, &link->conf); 317 if (ret != 0) 318 goto failed; 319 320 dev->irq = link->irq; 321 dev->base_addr = link->resource[0]->start; 322 323 SET_NETDEV_DEV(dev, &link->dev); 324 if (register_netdev(dev) != 0) { 325 printk("%s: register_netdev() failed\n", MODULE_NAME); 326 goto failed; 327 } 328 329 register_wlags_sysfs(dev); 330 331 printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, ""mac_address ", 332 dev->name, dev->base_addr, dev->irq); 333 for (i = 0; i < ETH_ALEN; i++) 334 printk("%02X%c", dev->dev_addr[i], ((i < (ETH_ALEN-1)) ? ':' : '\n')); 335 336 DBG_LEAVE(DbgInfo); 337 return; 338 339failed: 340 wl_adapter_release(link); 341 342 DBG_LEAVE(DbgInfo); 343 return; 344} /* wl_adapter_insert */ 345/*============================================================================*/ 346 347 348/******************************************************************************* 349 * wl_adapter_open() 350 ******************************************************************************* 351 * 352 * DESCRIPTION: 353 * 354 * Open the device. 355 * 356 * PARAMETERS: 357 * 358 * dev - a pointer to a net_device structure representing the network 359 * device to open. 360 * 361 * RETURNS: 362 * 363 * 0 on success 364 * errno value otherwise 365 * 366 ******************************************************************************/ 367int wl_adapter_open(struct net_device *dev) 368{ 369 struct wl_private *lp = wl_priv(dev); 370 struct pcmcia_device *link = lp->link; 371 int result = 0; 372 int hcf_status = HCF_SUCCESS; 373 /*--------------------------------------------------------------------*/ 374 375 DBG_FUNC("wl_adapter_open"); 376 DBG_ENTER(DbgInfo); 377 DBG_PRINT("%s\n", VERSION_INFO); 378 DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); 379 380 if (!pcmcia_dev_present(link)) { 381 DBG_LEAVE(DbgInfo); 382 return -ENODEV; 383 } 384 385 link->open++; 386 387 hcf_status = wl_open(dev); 388 389 if (hcf_status != HCF_SUCCESS) { 390 link->open--; 391 result = -ENODEV; 392 } 393 394 DBG_LEAVE(DbgInfo); 395 return result; 396} /* wl_adapter_open */ 397/*============================================================================*/ 398 399 400/******************************************************************************* 401 * wl_adapter_close() 402 ******************************************************************************* 403 * 404 * DESCRIPTION: 405 * 406 * Close the device. 407 * 408 * PARAMETERS: 409 * 410 * dev - a pointer to a net_device structure representing the network 411 * device to close. 412 * 413 * RETURNS: 414 * 415 * 0 on success 416 * errno value otherwise 417 * 418 ******************************************************************************/ 419int wl_adapter_close(struct net_device *dev) 420{ 421 struct wl_private *lp = wl_priv(dev); 422 struct pcmcia_device *link = lp->link; 423 /*--------------------------------------------------------------------*/ 424 425 DBG_FUNC("wl_adapter_close"); 426 DBG_ENTER(DbgInfo); 427 DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev); 428 429 if (link == NULL) { 430 DBG_LEAVE(DbgInfo); 431 return -ENODEV; 432 } 433 434 DBG_TRACE(DbgInfo, "%s: Shutting down adapter.\n", dev->name); 435 wl_close(dev); 436 437 link->open--; 438 439 DBG_LEAVE(DbgInfo); 440 return 0; 441} /* wl_adapter_close */ 442/*============================================================================*/ 443 444static struct pcmcia_device_id wl_adapter_ids[] = { 445#if !((HCF_TYPE) & HCF_TYPE_HII5) 446 PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003), 447 PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110", 448 0x33103a9b, 0xe175b0dd), 449#else 450 PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0004), 451 PCMCIA_DEVICE_PROD_ID12("Linksys", "WCF54G_Wireless-G_CompactFlash_Card", 452 0x0733cc81, 0x98a599e1), 453#endif /* (HCF_TYPE) & HCF_TYPE_HII5 */ 454 PCMCIA_DEVICE_NULL, 455}; 456MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids); 457 458static struct pcmcia_driver wlags49_driver = { 459 .owner = THIS_MODULE, 460 .drv = { 461 .name = DRIVER_NAME, 462 }, 463 .probe = wl_adapter_attach, 464 .remove = wl_adapter_detach, 465 .id_table = wl_adapter_ids, 466 .suspend = wl_adapter_suspend, 467 .resume = wl_adapter_resume, 468}; 469 470 471 472/******************************************************************************* 473 * wl_adapter_init_module() 474 ******************************************************************************* 475 * 476 * DESCRIPTION: 477 * 478 * Called by init_module() to perform PCMCIA driver initialization. 479 * 480 * PARAMETERS: 481 * 482 * N/A 483 * 484 * RETURNS: 485 * 486 * 0 on success 487 * -1 on error 488 * 489 ******************************************************************************/ 490int wl_adapter_init_module(void) 491{ 492 int ret; 493 /*--------------------------------------------------------------------*/ 494 495 DBG_FUNC("wl_adapter_init_module"); 496 DBG_ENTER(DbgInfo); 497 DBG_TRACE(DbgInfo, "wl_adapter_init_module() -- PCMCIA\n"); 498 499 ret = pcmcia_register_driver(&wlags49_driver); 500 501 DBG_LEAVE(DbgInfo); 502 return ret; 503} /* wl_adapter_init_module */ 504/*============================================================================*/ 505 506 507/******************************************************************************* 508 * wl_adapter_cleanup_module() 509 ******************************************************************************* 510 * 511 * DESCRIPTION: 512 * 513 * Called by cleanup_module() to perform driver uninitialization. 514 * 515 * PARAMETERS: 516 * 517 * N/A 518 * 519 * RETURNS: 520 * 521 * N/A 522 * 523 ******************************************************************************/ 524void wl_adapter_cleanup_module(void) 525{ 526 DBG_FUNC("wl_adapter_cleanup_module"); 527 DBG_ENTER(DbgInfo); 528 DBG_TRACE(DbgInfo, "wl_adapter_cleanup_module() -- PCMCIA\n"); 529 530 531 pcmcia_unregister_driver(&wlags49_driver); 532 533 DBG_LEAVE(DbgInfo); 534 return; 535} /* wl_adapter_cleanup_module */ 536/*============================================================================*/ 537 538 539/******************************************************************************* 540 * wl_adapter_is_open() 541 ******************************************************************************* 542 * 543 * DESCRIPTION: 544 * 545 * Check with Card Services to determine if this device is open. 546 * 547 * PARAMETERS: 548 * 549 * dev - a pointer to the net_device structure whose open status will be 550 * checked 551 * 552 * RETURNS: 553 * 554 * nonzero if device is open 555 * 0 otherwise 556 * 557 ******************************************************************************/ 558int wl_adapter_is_open(struct net_device *dev) 559{ 560 struct wl_private *lp = wl_priv(dev); 561 struct pcmcia_device *link = lp->link; 562 563 if (!pcmcia_dev_present(link)) 564 return 0; 565 566 return link->open; 567} /* wl_adapter_is_open */ 568/*============================================================================*/ 569 570 571#if DBG 572 573/******************************************************************************* 574 * DbgEvent() 575 ******************************************************************************* 576 * 577 * DESCRIPTION: 578 * 579 * Converts the card serivces events to text for debugging. 580 * 581 * PARAMETERS: 582 * 583 * mask - a integer representing the error(s) being reported by Card 584 * Services. 585 * 586 * RETURNS: 587 * 588 * a pointer to a string describing the error(s) 589 * 590 ******************************************************************************/ 591const char *DbgEvent(int mask) 592{ 593 static char DbgBuffer[256]; 594 char *pBuf; 595 /*--------------------------------------------------------------------*/ 596 597 pBuf = DbgBuffer; 598 *pBuf = '\0'; 599 600 601 if (mask & CS_EVENT_WRITE_PROTECT) 602 strcat(pBuf, "WRITE_PROTECT "); 603 604 if (mask & CS_EVENT_CARD_LOCK) 605 strcat(pBuf, "CARD_LOCK "); 606 607 if (mask & CS_EVENT_CARD_INSERTION) 608 strcat(pBuf, "CARD_INSERTION "); 609 610 if (mask & CS_EVENT_CARD_REMOVAL) 611 strcat(pBuf, "CARD_REMOVAL "); 612 613 if (mask & CS_EVENT_BATTERY_DEAD) 614 strcat(pBuf, "BATTERY_DEAD "); 615 616 if (mask & CS_EVENT_BATTERY_LOW) 617 strcat(pBuf, "BATTERY_LOW "); 618 619 if (mask & CS_EVENT_READY_CHANGE) 620 strcat(pBuf, "READY_CHANGE "); 621 622 if (mask & CS_EVENT_CARD_DETECT) 623 strcat(pBuf, "CARD_DETECT "); 624 625 if (mask & CS_EVENT_RESET_REQUEST) 626 strcat(pBuf, "RESET_REQUEST "); 627 628 if (mask & CS_EVENT_RESET_PHYSICAL) 629 strcat(pBuf, "RESET_PHYSICAL "); 630 631 if (mask & CS_EVENT_CARD_RESET) 632 strcat(pBuf, "CARD_RESET "); 633 634 if (mask & CS_EVENT_REGISTRATION_COMPLETE) 635 strcat(pBuf, "REGISTRATION_COMPLETE "); 636 637 /* if (mask & CS_EVENT_RESET_COMPLETE) 638 strcat(pBuf, "RESET_COMPLETE "); */ 639 640 if (mask & CS_EVENT_PM_SUSPEND) 641 strcat(pBuf, "PM_SUSPEND "); 642 643 if (mask & CS_EVENT_PM_RESUME) 644 strcat(pBuf, "PM_RESUME "); 645 646 if (mask & CS_EVENT_INSERTION_REQUEST) 647 strcat(pBuf, "INSERTION_REQUEST "); 648 649 if (mask & CS_EVENT_EJECTION_REQUEST) 650 strcat(pBuf, "EJECTION_REQUEST "); 651 652 if (mask & CS_EVENT_MTD_REQUEST) 653 strcat(pBuf, "MTD_REQUEST "); 654 655 if (mask & CS_EVENT_ERASE_COMPLETE) 656 strcat(pBuf, "ERASE_COMPLETE "); 657 658 if (mask & CS_EVENT_REQUEST_ATTENTION) 659 strcat(pBuf, "REQUEST_ATTENTION "); 660 661 if (mask & CS_EVENT_CB_DETECT) 662 strcat(pBuf, "CB_DETECT "); 663 664 if (mask & CS_EVENT_3VCARD) 665 strcat(pBuf, "3VCARD "); 666 667 if (mask & CS_EVENT_XVCARD) 668 strcat(pBuf, "XVCARD "); 669 670 671 if (*pBuf) { 672 pBuf[strlen(pBuf) - 1] = '\0'; 673 } else { 674 if (mask != 0x0) 675 sprintf(pBuf, "<<0x%08x>>", mask); 676 } 677 678 return pBuf; 679} /* DbgEvent */ 680/*============================================================================*/ 681 682#endif /* DBG */ 683