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