1/* 2 * IPWireless 3G PCMCIA Network Driver 3 * 4 * Original code 5 * by Stephen Blackheath <stephen@blacksapphire.com>, 6 * Ben Martel <benm@symmetric.co.nz> 7 * 8 * Copyrighted as follows: 9 * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) 10 * 11 * Various driver changes and rewrites, port to new kernels 12 * Copyright (C) 2006-2007 Jiri Kosina 13 * 14 * Misc code cleanups and updates 15 * Copyright (C) 2007 David Sterba 16 */ 17 18#include "hardware.h" 19#include "network.h" 20#include "main.h" 21#include "tty.h" 22 23#include <linux/delay.h> 24#include <linux/init.h> 25#include <linux/io.h> 26#include <linux/kernel.h> 27#include <linux/module.h> 28#include <linux/sched.h> 29#include <linux/slab.h> 30 31#include <pcmcia/cisreg.h> 32#include <pcmcia/device_id.h> 33#include <pcmcia/ss.h> 34#include <pcmcia/ds.h> 35#include <pcmcia/cs.h> 36 37static struct pcmcia_device_id ipw_ids[] = { 38 PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), 39 PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200), 40 PCMCIA_DEVICE_NULL 41}; 42MODULE_DEVICE_TABLE(pcmcia, ipw_ids); 43 44static void ipwireless_detach(struct pcmcia_device *link); 45 46/* 47 * Module params 48 */ 49/* Debug mode: more verbose, print sent/recv bytes */ 50int ipwireless_debug; 51int ipwireless_loopback; 52int ipwireless_out_queue = 10; 53 54module_param_named(debug, ipwireless_debug, int, 0); 55module_param_named(loopback, ipwireless_loopback, int, 0); 56module_param_named(out_queue, ipwireless_out_queue, int, 0); 57MODULE_PARM_DESC(debug, "switch on debug messages [0]"); 58MODULE_PARM_DESC(loopback, 59 "debug: enable ras_raw channel [0]"); 60MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]"); 61 62/* Executes in process context. */ 63static void signalled_reboot_work(struct work_struct *work_reboot) 64{ 65 struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, 66 work_reboot); 67 struct pcmcia_device *link = ipw->link; 68 pcmcia_reset_card(link->socket); 69} 70 71static void signalled_reboot_callback(void *callback_data) 72{ 73 struct ipw_dev *ipw = (struct ipw_dev *) callback_data; 74 75 /* Delegate to process context. */ 76 schedule_work(&ipw->work_reboot); 77} 78 79static int ipwireless_probe(struct pcmcia_device *p_dev, 80 cistpl_cftable_entry_t *cfg, 81 cistpl_cftable_entry_t *dflt, 82 unsigned int vcc, 83 void *priv_data) 84{ 85 struct ipw_dev *ipw = priv_data; 86 struct resource *io_resource; 87 int ret; 88 89 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; 90 p_dev->resource[0]->start = cfg->io.win[0].base; 91 p_dev->resource[0]->end = cfg->io.win[0].len; 92 93 /* 0x40 causes it to generate level mode interrupts. */ 94 /* 0x04 enables IREQ pin. */ 95 p_dev->conf.ConfigIndex = cfg->index | 0x44; 96 p_dev->io_lines = 16; 97 ret = pcmcia_request_io(p_dev); 98 if (ret) 99 return ret; 100 101 io_resource = request_region(p_dev->resource[0]->start, 102 resource_size(p_dev->resource[0]), 103 IPWIRELESS_PCCARD_NAME); 104 105 if (cfg->mem.nwin == 0) 106 return 0; 107 108 ipw->request_common_memory.Attributes = 109 WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; 110 ipw->request_common_memory.Base = cfg->mem.win[0].host_addr; 111 ipw->request_common_memory.Size = cfg->mem.win[0].len; 112 if (ipw->request_common_memory.Size < 0x1000) 113 ipw->request_common_memory.Size = 0x1000; 114 ipw->request_common_memory.AccessSpeed = 0; 115 116 ret = pcmcia_request_window(p_dev, &ipw->request_common_memory, 117 &ipw->handle_common_memory); 118 119 if (ret != 0) 120 goto exit1; 121 122 ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory, 123 cfg->mem.win[0].card_addr); 124 125 if (ret != 0) 126 goto exit2; 127 128 ipw->is_v2_card = cfg->mem.win[0].len == 0x100; 129 130 ipw->common_memory = ioremap(ipw->request_common_memory.Base, 131 ipw->request_common_memory.Size); 132 request_mem_region(ipw->request_common_memory.Base, 133 ipw->request_common_memory.Size, 134 IPWIRELESS_PCCARD_NAME); 135 136 ipw->request_attr_memory.Attributes = 137 WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; 138 ipw->request_attr_memory.Base = 0; 139 ipw->request_attr_memory.Size = 0; /* this used to be 0x1000 */ 140 ipw->request_attr_memory.AccessSpeed = 0; 141 142 ret = pcmcia_request_window(p_dev, &ipw->request_attr_memory, 143 &ipw->handle_attr_memory); 144 145 if (ret != 0) 146 goto exit2; 147 148 ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, 0); 149 if (ret != 0) 150 goto exit3; 151 152 ipw->attr_memory = ioremap(ipw->request_attr_memory.Base, 153 ipw->request_attr_memory.Size); 154 request_mem_region(ipw->request_attr_memory.Base, 155 ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME); 156 157 return 0; 158 159exit3: 160exit2: 161 if (ipw->common_memory) { 162 release_mem_region(ipw->request_common_memory.Base, 163 ipw->request_common_memory.Size); 164 iounmap(ipw->common_memory); 165 } 166exit1: 167 release_resource(io_resource); 168 pcmcia_disable_device(p_dev); 169 return -1; 170} 171 172static int config_ipwireless(struct ipw_dev *ipw) 173{ 174 struct pcmcia_device *link = ipw->link; 175 int ret = 0; 176 177 ipw->is_v2_card = 0; 178 179 ret = pcmcia_loop_config(link, ipwireless_probe, ipw); 180 if (ret != 0) 181 return ret; 182 183 link->conf.Attributes = CONF_ENABLE_IRQ; 184 link->conf.IntType = INT_MEMORY_AND_IO; 185 186 INIT_WORK(&ipw->work_reboot, signalled_reboot_work); 187 188 ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start, 189 ipw->attr_memory, ipw->common_memory, 190 ipw->is_v2_card, signalled_reboot_callback, 191 ipw); 192 193 ret = pcmcia_request_irq(link, ipwireless_interrupt); 194 if (ret != 0) 195 goto exit; 196 197 printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", 198 ipw->is_v2_card ? "V2/V3" : "V1"); 199 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 200 ": I/O ports %pR, irq %d\n", link->resource[0], 201 (unsigned int) link->irq); 202 if (ipw->attr_memory && ipw->common_memory) 203 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 204 ": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n", 205 ipw->request_attr_memory.Base, 206 ipw->request_attr_memory.Base 207 + ipw->request_attr_memory.Size - 1, 208 ipw->request_common_memory.Base, 209 ipw->request_common_memory.Base 210 + ipw->request_common_memory.Size - 1); 211 212 ipw->network = ipwireless_network_create(ipw->hardware); 213 if (!ipw->network) 214 goto exit; 215 216 ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network); 217 if (!ipw->tty) 218 goto exit; 219 220 ipwireless_init_hardware_v2_v3(ipw->hardware); 221 222 /* 223 * Do the RequestConfiguration last, because it enables interrupts. 224 * Then we don't get any interrupts before we're ready for them. 225 */ 226 ret = pcmcia_request_configuration(link, &link->conf); 227 228 if (ret != 0) 229 goto exit; 230 231 return 0; 232 233exit: 234 if (ipw->attr_memory) { 235 release_mem_region(ipw->request_attr_memory.Base, 236 ipw->request_attr_memory.Size); 237 iounmap(ipw->attr_memory); 238 239 } 240 if (ipw->common_memory) { 241 release_mem_region(ipw->request_common_memory.Base, 242 ipw->request_common_memory.Size); 243 iounmap(ipw->common_memory); 244 } 245 pcmcia_disable_device(link); 246 return -1; 247} 248 249static void release_ipwireless(struct ipw_dev *ipw) 250{ 251 if (ipw->common_memory) { 252 release_mem_region(ipw->request_common_memory.Base, 253 ipw->request_common_memory.Size); 254 iounmap(ipw->common_memory); 255 } 256 if (ipw->attr_memory) { 257 release_mem_region(ipw->request_attr_memory.Base, 258 ipw->request_attr_memory.Size); 259 iounmap(ipw->attr_memory); 260 } 261 pcmcia_disable_device(ipw->link); 262} 263 264/* 265 * ipwireless_attach() creates an "instance" of the driver, allocating 266 * local data structures for one device (one interface). The device 267 * is registered with Card Services. 268 * 269 * The pcmcia_device structure is initialized, but we don't actually 270 * configure the card at this point -- we wait until we receive a 271 * card insertion event. 272 */ 273static int ipwireless_attach(struct pcmcia_device *link) 274{ 275 struct ipw_dev *ipw; 276 int ret; 277 278 ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL); 279 if (!ipw) 280 return -ENOMEM; 281 282 ipw->link = link; 283 link->priv = ipw; 284 285 ipw->hardware = ipwireless_hardware_create(); 286 if (!ipw->hardware) { 287 kfree(ipw); 288 return -ENOMEM; 289 } 290 /* RegisterClient will call config_ipwireless */ 291 292 ret = config_ipwireless(ipw); 293 294 if (ret != 0) { 295 ipwireless_detach(link); 296 return ret; 297 } 298 299 return 0; 300} 301 302/* 303 * This deletes a driver "instance". The device is de-registered with 304 * Card Services. If it has been released, all local data structures 305 * are freed. Otherwise, the structures will be freed when the device 306 * is released. 307 */ 308static void ipwireless_detach(struct pcmcia_device *link) 309{ 310 struct ipw_dev *ipw = link->priv; 311 312 release_ipwireless(ipw); 313 314 if (ipw->tty != NULL) 315 ipwireless_tty_free(ipw->tty); 316 if (ipw->network != NULL) 317 ipwireless_network_free(ipw->network); 318 if (ipw->hardware != NULL) 319 ipwireless_hardware_free(ipw->hardware); 320 kfree(ipw); 321} 322 323static struct pcmcia_driver me = { 324 .owner = THIS_MODULE, 325 .probe = ipwireless_attach, 326 .remove = ipwireless_detach, 327 .drv = { .name = IPWIRELESS_PCCARD_NAME }, 328 .id_table = ipw_ids 329}; 330 331/* 332 * Module insertion : initialisation of the module. 333 * Register the card with cardmgr... 334 */ 335static int __init init_ipwireless(void) 336{ 337 int ret; 338 339 printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " 340 IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n"); 341 342 ret = ipwireless_tty_init(); 343 if (ret != 0) 344 return ret; 345 346 ret = pcmcia_register_driver(&me); 347 if (ret != 0) 348 ipwireless_tty_release(); 349 350 return ret; 351} 352 353/* 354 * Module removal 355 */ 356static void __exit exit_ipwireless(void) 357{ 358 printk(KERN_INFO IPWIRELESS_PCCARD_NAME " " 359 IPWIRELESS_PCMCIA_VERSION " removed\n"); 360 361 pcmcia_unregister_driver(&me); 362 ipwireless_tty_release(); 363} 364 365module_init(init_ipwireless); 366module_exit(exit_ipwireless); 367 368MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR); 369MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION); 370MODULE_LICENSE("GPL"); 371