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 36static const struct pcmcia_device_id ipw_ids[] = { 37 PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), 38 PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200), 39 PCMCIA_DEVICE_NULL 40}; 41MODULE_DEVICE_TABLE(pcmcia, ipw_ids); 42 43static void ipwireless_detach(struct pcmcia_device *link); 44 45/* 46 * Module params 47 */ 48/* Debug mode: more verbose, print sent/recv bytes */ 49int ipwireless_debug; 50int ipwireless_loopback; 51int ipwireless_out_queue = 10; 52 53module_param_named(debug, ipwireless_debug, int, 0); 54module_param_named(loopback, ipwireless_loopback, int, 0); 55module_param_named(out_queue, ipwireless_out_queue, int, 0); 56MODULE_PARM_DESC(debug, "switch on debug messages [0]"); 57MODULE_PARM_DESC(loopback, 58 "debug: enable ras_raw channel [0]"); 59MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]"); 60 61/* Executes in process context. */ 62static void signalled_reboot_work(struct work_struct *work_reboot) 63{ 64 struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, 65 work_reboot); 66 struct pcmcia_device *link = ipw->link; 67 pcmcia_reset_card(link->socket); 68} 69 70static void signalled_reboot_callback(void *callback_data) 71{ 72 struct ipw_dev *ipw = (struct ipw_dev *) callback_data; 73 74 /* Delegate to process context. */ 75 schedule_work(&ipw->work_reboot); 76} 77 78static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) 79{ 80 struct ipw_dev *ipw = priv_data; 81 int ret; 82 83 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 84 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; 85 86 /* 0x40 causes it to generate level mode interrupts. */ 87 /* 0x04 enables IREQ pin. */ 88 p_dev->config_index |= 0x44; 89 p_dev->io_lines = 16; 90 ret = pcmcia_request_io(p_dev); 91 if (ret) 92 return ret; 93 94 if (!request_region(p_dev->resource[0]->start, 95 resource_size(p_dev->resource[0]), 96 IPWIRELESS_PCCARD_NAME)) { 97 ret = -EBUSY; 98 goto exit; 99 } 100 101 p_dev->resource[2]->flags |= 102 WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; 103 104 ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0); 105 if (ret != 0) 106 goto exit1; 107 108 ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr); 109 if (ret != 0) 110 goto exit1; 111 112 ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100; 113 114 ipw->common_memory = ioremap(p_dev->resource[2]->start, 115 resource_size(p_dev->resource[2])); 116 if (!request_mem_region(p_dev->resource[2]->start, 117 resource_size(p_dev->resource[2]), 118 IPWIRELESS_PCCARD_NAME)) { 119 ret = -EBUSY; 120 goto exit2; 121 } 122 123 p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | 124 WIN_ENABLE; 125 p_dev->resource[3]->end = 0; /* this used to be 0x1000 */ 126 ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0); 127 if (ret != 0) 128 goto exit3; 129 130 ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0); 131 if (ret != 0) 132 goto exit3; 133 134 ipw->attr_memory = ioremap(p_dev->resource[3]->start, 135 resource_size(p_dev->resource[3])); 136 if (!request_mem_region(p_dev->resource[3]->start, 137 resource_size(p_dev->resource[3]), 138 IPWIRELESS_PCCARD_NAME)) { 139 ret = -EBUSY; 140 goto exit4; 141 } 142 143 return 0; 144 145exit4: 146 iounmap(ipw->attr_memory); 147exit3: 148 release_mem_region(p_dev->resource[2]->start, 149 resource_size(p_dev->resource[2])); 150exit2: 151 iounmap(ipw->common_memory); 152exit1: 153 release_region(p_dev->resource[0]->start, 154 resource_size(p_dev->resource[0])); 155exit: 156 pcmcia_disable_device(p_dev); 157 return ret; 158} 159 160static int config_ipwireless(struct ipw_dev *ipw) 161{ 162 struct pcmcia_device *link = ipw->link; 163 int ret = 0; 164 165 ipw->is_v2_card = 0; 166 link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM | 167 CONF_ENABLE_IRQ; 168 169 ret = pcmcia_loop_config(link, ipwireless_probe, ipw); 170 if (ret != 0) 171 return ret; 172 173 INIT_WORK(&ipw->work_reboot, signalled_reboot_work); 174 175 ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start, 176 ipw->attr_memory, ipw->common_memory, 177 ipw->is_v2_card, signalled_reboot_callback, 178 ipw); 179 180 ret = pcmcia_request_irq(link, ipwireless_interrupt); 181 if (ret != 0) 182 goto exit; 183 184 printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", 185 ipw->is_v2_card ? "V2/V3" : "V1"); 186 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 187 ": I/O ports %pR, irq %d\n", link->resource[0], 188 (unsigned int) link->irq); 189 if (ipw->attr_memory && ipw->common_memory) 190 printk(KERN_INFO IPWIRELESS_PCCARD_NAME 191 ": attr memory %pR, common memory %pR\n", 192 link->resource[3], 193 link->resource[2]); 194 195 ipw->network = ipwireless_network_create(ipw->hardware); 196 if (!ipw->network) 197 goto exit; 198 199 ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network); 200 if (!ipw->tty) 201 goto exit; 202 203 ipwireless_init_hardware_v2_v3(ipw->hardware); 204 205 /* 206 * Do the RequestConfiguration last, because it enables interrupts. 207 * Then we don't get any interrupts before we're ready for them. 208 */ 209 ret = pcmcia_enable_device(link); 210 if (ret != 0) 211 goto exit; 212 213 return 0; 214 215exit: 216 if (ipw->common_memory) { 217 release_mem_region(link->resource[2]->start, 218 resource_size(link->resource[2])); 219 iounmap(ipw->common_memory); 220 } 221 if (ipw->attr_memory) { 222 release_mem_region(link->resource[3]->start, 223 resource_size(link->resource[3])); 224 iounmap(ipw->attr_memory); 225 } 226 pcmcia_disable_device(link); 227 return -1; 228} 229 230static void release_ipwireless(struct ipw_dev *ipw) 231{ 232 release_region(ipw->link->resource[0]->start, 233 resource_size(ipw->link->resource[0])); 234 if (ipw->common_memory) { 235 release_mem_region(ipw->link->resource[2]->start, 236 resource_size(ipw->link->resource[2])); 237 iounmap(ipw->common_memory); 238 } 239 if (ipw->attr_memory) { 240 release_mem_region(ipw->link->resource[3]->start, 241 resource_size(ipw->link->resource[3])); 242 iounmap(ipw->attr_memory); 243 } 244 pcmcia_disable_device(ipw->link); 245} 246 247/* 248 * ipwireless_attach() creates an "instance" of the driver, allocating 249 * local data structures for one device (one interface). The device 250 * is registered with Card Services. 251 * 252 * The pcmcia_device structure is initialized, but we don't actually 253 * configure the card at this point -- we wait until we receive a 254 * card insertion event. 255 */ 256static int ipwireless_attach(struct pcmcia_device *link) 257{ 258 struct ipw_dev *ipw; 259 int ret; 260 261 ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL); 262 if (!ipw) 263 return -ENOMEM; 264 265 ipw->link = link; 266 link->priv = ipw; 267 268 ipw->hardware = ipwireless_hardware_create(); 269 if (!ipw->hardware) { 270 kfree(ipw); 271 return -ENOMEM; 272 } 273 /* RegisterClient will call config_ipwireless */ 274 275 ret = config_ipwireless(ipw); 276 277 if (ret != 0) { 278 ipwireless_detach(link); 279 return ret; 280 } 281 282 return 0; 283} 284 285/* 286 * This deletes a driver "instance". The device is de-registered with 287 * Card Services. If it has been released, all local data structures 288 * are freed. Otherwise, the structures will be freed when the device 289 * is released. 290 */ 291static void ipwireless_detach(struct pcmcia_device *link) 292{ 293 struct ipw_dev *ipw = link->priv; 294 295 release_ipwireless(ipw); 296 297 if (ipw->tty != NULL) 298 ipwireless_tty_free(ipw->tty); 299 if (ipw->network != NULL) 300 ipwireless_network_free(ipw->network); 301 if (ipw->hardware != NULL) 302 ipwireless_hardware_free(ipw->hardware); 303 kfree(ipw); 304} 305 306static struct pcmcia_driver me = { 307 .owner = THIS_MODULE, 308 .probe = ipwireless_attach, 309 .remove = ipwireless_detach, 310 .name = IPWIRELESS_PCCARD_NAME, 311 .id_table = ipw_ids 312}; 313 314/* 315 * Module insertion : initialisation of the module. 316 * Register the card with cardmgr... 317 */ 318static int __init init_ipwireless(void) 319{ 320 int ret; 321 322 ret = ipwireless_tty_init(); 323 if (ret != 0) 324 return ret; 325 326 ret = pcmcia_register_driver(&me); 327 if (ret != 0) 328 ipwireless_tty_release(); 329 330 return ret; 331} 332 333/* 334 * Module removal 335 */ 336static void __exit exit_ipwireless(void) 337{ 338 pcmcia_unregister_driver(&me); 339 ipwireless_tty_release(); 340} 341 342module_init(init_ipwireless); 343module_exit(exit_ipwireless); 344 345MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR); 346MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION); 347MODULE_LICENSE("GPL"); 348