linux/drivers/staging/wlags49_h2/wl_cs.c
<<
>>
Prefs
   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/bitops.h>
  78
  79#include <linux/netdevice.h>
  80#include <linux/etherdevice.h>
  81#include <linux/skbuff.h>
  82#include <linux/if_arp.h>
  83#include <linux/ioport.h>
  84#include <linux/module.h>
  85
  86#include <pcmcia/cistpl.h>
  87#include <pcmcia/cisreg.h>
  88#include <pcmcia/ciscode.h>
  89#include <pcmcia/ds.h>
  90#include <debug.h>
  91
  92#include <hcf.h>
  93#include <dhf.h>
  94#include <hcfdef.h>
  95
  96#include <wl_if.h>
  97#include <wl_internal.h>
  98#include <wl_util.h>
  99#include <wl_main.h>
 100#include <wl_netdev.h>
 101#include <wl_cs.h>
 102
 103
 104/*******************************************************************************
 105 *  global definitions
 106 ******************************************************************************/
 107#if DBG
 108extern dbg_info_t *DbgInfo;
 109#endif  /* DBG */
 110
 111
 112/*******************************************************************************
 113 *      wl_adapter_attach()
 114 *******************************************************************************
 115 *
 116 *  DESCRIPTION:
 117 *
 118 *      Creates an instance of the driver, allocating local data structures for
 119 *  one device. The device is registered with Card Services.
 120 *
 121 *  PARAMETERS:
 122 *
 123 *      none
 124 *
 125 *  RETURNS:
 126 *
 127 *      pointer to an allocated dev_link_t structure
 128 *      NULL on failure
 129 *
 130 ******************************************************************************/
 131static int wl_adapter_attach(struct pcmcia_device *link)
 132{
 133        struct net_device   *dev;
 134        struct wl_private   *lp;
 135        int ret;
 136        /*--------------------------------------------------------------------*/
 137
 138        DBG_FUNC("wl_adapter_attach");
 139        DBG_ENTER(DbgInfo);
 140
 141        dev = wl_device_alloc();
 142        if (dev == NULL) {
 143                DBG_ERROR(DbgInfo, "wl_device_alloc returned NULL\n");
 144                return -ENOMEM;
 145        }
 146
 147        link->resource[0]->end  = HCF_NUM_IO_PORTS;
 148        link->resource[0]->flags= IO_DATA_PATH_WIDTH_16;
 149        link->config_flags     |= CONF_ENABLE_IRQ;
 150        link->config_index      = 5;
 151        link->config_regs       = PRESENT_OPTION;
 152
 153        link->priv = dev;
 154        lp = wl_priv(dev);
 155        lp->link = link;
 156
 157        ret = wl_adapter_insert(link);
 158        if (ret != 0)
 159                wl_device_dealloc(dev);
 160
 161        DBG_LEAVE(DbgInfo);
 162        return ret;
 163} /* wl_adapter_attach */
 164/*============================================================================*/
 165
 166
 167
 168static void wl_adapter_detach(struct pcmcia_device *link)
 169{
 170        struct net_device   *dev = link->priv;
 171        /*--------------------------------------------------------------------*/
 172
 173        DBG_FUNC("wl_adapter_detach");
 174        DBG_ENTER(DbgInfo);
 175        DBG_PARAM(DbgInfo, "link", "0x%p", link);
 176
 177        wl_adapter_release(link);
 178
 179        if (dev) {
 180                unregister_netdev(dev);
 181                wl_device_dealloc(dev);
 182        }
 183
 184        DBG_LEAVE(DbgInfo);
 185} /* wl_adapter_detach */
 186/*============================================================================*/
 187
 188
 189void wl_adapter_release(struct pcmcia_device *link)
 190{
 191        DBG_FUNC("wl_adapter_release");
 192        DBG_ENTER(DbgInfo);
 193        DBG_PARAM(DbgInfo, "link", "0x%p", link);
 194
 195        /* Stop hardware */
 196        wl_remove(link->priv);
 197
 198        pcmcia_disable_device(link);
 199
 200        DBG_LEAVE(DbgInfo);
 201} /* wl_adapter_release */
 202/*============================================================================*/
 203
 204static int wl_adapter_suspend(struct pcmcia_device *link)
 205{
 206        struct net_device *dev = link->priv;
 207
 208        /* if (link->open) { */
 209        netif_device_detach(dev);
 210        wl_suspend(dev);
 211        /* CHECK! pcmcia_release_configuration(link->handle); */
 212        /* } */
 213
 214        return 0;
 215} /* wl_adapter_suspend */
 216
 217static int wl_adapter_resume(struct pcmcia_device *link)
 218{
 219        struct net_device *dev = link->priv;
 220
 221        wl_resume(dev);
 222
 223        netif_device_attach(dev);
 224
 225        return 0;
 226} /* wl_adapter_resume */
 227
 228int wl_adapter_insert(struct pcmcia_device *link)
 229{
 230        struct net_device *dev;
 231        int ret;
 232        /*--------------------------------------------------------------------*/
 233
 234        DBG_FUNC("wl_adapter_insert");
 235        DBG_ENTER(DbgInfo);
 236        DBG_PARAM(DbgInfo, "link", "0x%p", link);
 237
 238        dev     = link->priv;
 239
 240        /* Do we need to allocate an interrupt? */
 241        link->config_flags |= CONF_ENABLE_IRQ;
 242        link->io_lines = 6;
 243
 244        ret = pcmcia_request_io(link);
 245        if (ret != 0)
 246                goto failed;
 247
 248        ret = pcmcia_request_irq(link, (void *) wl_isr);
 249        if (ret != 0)
 250                goto failed;
 251
 252        ret = pcmcia_enable_device(link);
 253        if (ret != 0)
 254                goto failed;
 255
 256        dev->irq        = link->irq;
 257        dev->base_addr  = link->resource[0]->start;
 258
 259        SET_NETDEV_DEV(dev, &link->dev);
 260        ret = register_netdev(dev);
 261        if (ret != 0) {
 262                printk("%s: register_netdev() failed\n", MODULE_NAME);
 263                goto failed;
 264        }
 265
 266        printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, mac_address"
 267                " %pM\n", dev->name, dev->base_addr, dev->irq, dev->dev_addr);
 268
 269        DBG_LEAVE(DbgInfo);
 270        return 0;
 271
 272failed:
 273        wl_adapter_release(link);
 274
 275        DBG_LEAVE(DbgInfo);
 276        return ret;
 277} /* wl_adapter_insert */
 278/*============================================================================*/
 279
 280
 281/*******************************************************************************
 282 *      wl_adapter_open()
 283 *******************************************************************************
 284 *
 285 *  DESCRIPTION:
 286 *
 287 *      Open the device.
 288 *
 289 *  PARAMETERS:
 290 *
 291 *      dev - a pointer to a net_device structure representing the network
 292 *            device to open.
 293 *
 294 *  RETURNS:
 295 *
 296 *      0 on success
 297 *      errno value otherwise
 298 *
 299 ******************************************************************************/
 300int wl_adapter_open(struct net_device *dev)
 301{
 302        struct wl_private *lp = wl_priv(dev);
 303        struct pcmcia_device *link = lp->link;
 304        int result = 0;
 305        int hcf_status = HCF_SUCCESS;
 306        /*--------------------------------------------------------------------*/
 307
 308        DBG_FUNC("wl_adapter_open");
 309        DBG_ENTER(DbgInfo);
 310        DBG_PRINT("%s\n", VERSION_INFO);
 311        DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
 312
 313        if (!pcmcia_dev_present(link)) {
 314                DBG_LEAVE(DbgInfo);
 315                return -ENODEV;
 316        }
 317
 318        link->open++;
 319
 320        hcf_status = wl_open(dev);
 321
 322        if (hcf_status != HCF_SUCCESS) {
 323                link->open--;
 324                result = -ENODEV;
 325        }
 326
 327        DBG_LEAVE(DbgInfo);
 328        return result;
 329} /* wl_adapter_open */
 330/*============================================================================*/
 331
 332
 333/*******************************************************************************
 334 *      wl_adapter_close()
 335 *******************************************************************************
 336 *
 337 *  DESCRIPTION:
 338 *
 339 *      Close the device.
 340 *
 341 *  PARAMETERS:
 342 *
 343 *      dev - a pointer to a net_device structure representing the network
 344 *            device to close.
 345 *
 346 *  RETURNS:
 347 *
 348 *      0 on success
 349 *      errno value otherwise
 350 *
 351 ******************************************************************************/
 352int wl_adapter_close(struct net_device *dev)
 353{
 354        struct wl_private *lp = wl_priv(dev);
 355        struct pcmcia_device *link = lp->link;
 356        /*--------------------------------------------------------------------*/
 357
 358        DBG_FUNC("wl_adapter_close");
 359        DBG_ENTER(DbgInfo);
 360        DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
 361
 362        if (link == NULL) {
 363                DBG_LEAVE(DbgInfo);
 364                return -ENODEV;
 365        }
 366
 367        DBG_TRACE(DbgInfo, "%s: Shutting down adapter.\n", dev->name);
 368        wl_close(dev);
 369
 370        link->open--;
 371
 372        DBG_LEAVE(DbgInfo);
 373        return 0;
 374} /* wl_adapter_close */
 375/*============================================================================*/
 376
 377static const struct pcmcia_device_id wl_adapter_ids[] = {
 378#if !((HCF_TYPE) & HCF_TYPE_HII5)
 379        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003),
 380        PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110",
 381                                0x33103a9b, 0xe175b0dd),
 382#else
 383        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0004),
 384        PCMCIA_DEVICE_PROD_ID12("Linksys", "WCF54G_Wireless-G_CompactFlash_Card",
 385                                0x0733cc81, 0x98a599e1),
 386#endif  /* (HCF_TYPE) & HCF_TYPE_HII5 */
 387        PCMCIA_DEVICE_NULL,
 388};
 389MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids);
 390
 391static struct pcmcia_driver wlags49_driver = {
 392        .owner      = THIS_MODULE,
 393        .name       = DRIVER_NAME,
 394        .probe      = wl_adapter_attach,
 395        .remove     = wl_adapter_detach,
 396        .id_table   = wl_adapter_ids,
 397        .suspend    = wl_adapter_suspend,
 398        .resume     = wl_adapter_resume,
 399};
 400
 401
 402
 403/*******************************************************************************
 404 *      wl_adapter_init_module()
 405 *******************************************************************************
 406 *
 407 *  DESCRIPTION:
 408 *
 409 *      Called by init_module() to perform PCMCIA driver initialization.
 410 *
 411 *  PARAMETERS:
 412 *
 413 *      N/A
 414 *
 415 *  RETURNS:
 416 *
 417 *      0 on success
 418 *      -1 on error
 419 *
 420 ******************************************************************************/
 421int wl_adapter_init_module(void)
 422{
 423        int ret;
 424        /*--------------------------------------------------------------------*/
 425
 426        DBG_FUNC("wl_adapter_init_module");
 427        DBG_ENTER(DbgInfo);
 428        DBG_TRACE(DbgInfo, "wl_adapter_init_module() -- PCMCIA\n");
 429
 430        ret = pcmcia_register_driver(&wlags49_driver);
 431
 432        DBG_LEAVE(DbgInfo);
 433        return ret;
 434} /* wl_adapter_init_module */
 435/*============================================================================*/
 436
 437
 438/*******************************************************************************
 439 *      wl_adapter_cleanup_module()
 440 *******************************************************************************
 441 *
 442 *  DESCRIPTION:
 443 *
 444 *      Called by cleanup_module() to perform driver uninitialization.
 445 *
 446 *  PARAMETERS:
 447 *
 448 *      N/A
 449 *
 450 *  RETURNS:
 451 *
 452 *      N/A
 453 *
 454 ******************************************************************************/
 455void wl_adapter_cleanup_module(void)
 456{
 457        DBG_FUNC("wl_adapter_cleanup_module");
 458        DBG_ENTER(DbgInfo);
 459        DBG_TRACE(DbgInfo, "wl_adapter_cleanup_module() -- PCMCIA\n");
 460
 461
 462        pcmcia_unregister_driver(&wlags49_driver);
 463
 464        DBG_LEAVE(DbgInfo);
 465        return;
 466} /* wl_adapter_cleanup_module */
 467/*============================================================================*/
 468
 469
 470/*******************************************************************************
 471 *      wl_adapter_is_open()
 472 *******************************************************************************
 473 *
 474 *  DESCRIPTION:
 475 *
 476 *      Check with Card Services to determine if this device is open.
 477 *
 478 *  PARAMETERS:
 479 *
 480 *      dev - a pointer to the net_device structure whose open status will be
 481 *            checked
 482 *
 483 *  RETURNS:
 484 *
 485 *      nonzero if device is open
 486 *      0 otherwise
 487 *
 488 ******************************************************************************/
 489int wl_adapter_is_open(struct net_device *dev)
 490{
 491        struct wl_private *lp = wl_priv(dev);
 492        struct pcmcia_device *link = lp->link;
 493
 494        if (!pcmcia_dev_present(link))
 495                return 0;
 496
 497        return link->open;
 498} /* wl_adapter_is_open */
 499/*============================================================================*/
 500