357 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * IPWireless 3G PCMCIA Network Driver4 *5 * Original code6 * by Stephen Blackheath <stephen@blacksapphire.com>,7 * Ben Martel <benm@symmetric.co.nz>8 *9 * Copyrighted as follows:10 * Copyright (C) 2004 by Symmetric Systems Ltd (NZ)11 *12 * Various driver changes and rewrites, port to new kernels13 * Copyright (C) 2006-2007 Jiri Kosina14 *15 * Misc code cleanups and updates16 * Copyright (C) 2007 David Sterba17 */18 19#include "hardware.h"20#include "network.h"21#include "main.h"22#include "tty.h"23 24#include <linux/delay.h>25#include <linux/init.h>26#include <linux/io.h>27#include <linux/kernel.h>28#include <linux/module.h>29#include <linux/sched.h>30#include <linux/slab.h>31 32#include <pcmcia/cisreg.h>33#include <pcmcia/device_id.h>34#include <pcmcia/ss.h>35#include <pcmcia/ds.h>36 37static const struct pcmcia_device_id ipw_ids[] = {38 PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),39 PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),40 PCMCIA_DEVICE_NULL41};42MODULE_DEVICE_TABLE(pcmcia, ipw_ids);43 44static void ipwireless_detach(struct pcmcia_device *link);45 46/*47 * Module params48 */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, void *priv_data)80{81 struct ipw_dev *ipw = priv_data;82 int ret;83 84 p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;85 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;86 87 /* 0x40 causes it to generate level mode interrupts. */88 /* 0x04 enables IREQ pin. */89 p_dev->config_index |= 0x44;90 p_dev->io_lines = 16;91 ret = pcmcia_request_io(p_dev);92 if (ret)93 return ret;94 95 if (!request_region(p_dev->resource[0]->start,96 resource_size(p_dev->resource[0]),97 IPWIRELESS_PCCARD_NAME)) {98 ret = -EBUSY;99 goto exit;100 }101 102 p_dev->resource[2]->flags |=103 WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;104 105 ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0);106 if (ret != 0)107 goto exit1;108 109 ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);110 if (ret != 0)111 goto exit1;112 113 ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;114 115 ipw->common_memory = ioremap(p_dev->resource[2]->start,116 resource_size(p_dev->resource[2]));117 if (!ipw->common_memory) {118 ret = -ENOMEM;119 goto exit1;120 }121 if (!request_mem_region(p_dev->resource[2]->start,122 resource_size(p_dev->resource[2]),123 IPWIRELESS_PCCARD_NAME)) {124 ret = -EBUSY;125 goto exit2;126 }127 128 p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |129 WIN_ENABLE;130 p_dev->resource[3]->end = 0; /* this used to be 0x1000 */131 ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);132 if (ret != 0)133 goto exit3;134 135 ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);136 if (ret != 0)137 goto exit3;138 139 ipw->attr_memory = ioremap(p_dev->resource[3]->start,140 resource_size(p_dev->resource[3]));141 if (!ipw->attr_memory) {142 ret = -ENOMEM;143 goto exit3;144 }145 if (!request_mem_region(p_dev->resource[3]->start,146 resource_size(p_dev->resource[3]),147 IPWIRELESS_PCCARD_NAME)) {148 ret = -EBUSY;149 goto exit4;150 }151 152 return 0;153 154exit4:155 iounmap(ipw->attr_memory);156exit3:157 release_mem_region(p_dev->resource[2]->start,158 resource_size(p_dev->resource[2]));159exit2:160 iounmap(ipw->common_memory);161exit1:162 release_region(p_dev->resource[0]->start,163 resource_size(p_dev->resource[0]));164exit:165 pcmcia_disable_device(p_dev);166 return ret;167}168 169static int config_ipwireless(struct ipw_dev *ipw)170{171 struct pcmcia_device *link = ipw->link;172 int ret = 0;173 174 ipw->is_v2_card = 0;175 link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM |176 CONF_ENABLE_IRQ;177 178 ret = pcmcia_loop_config(link, ipwireless_probe, ipw);179 if (ret != 0)180 return ret;181 182 INIT_WORK(&ipw->work_reboot, signalled_reboot_work);183 184 ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,185 ipw->attr_memory, ipw->common_memory,186 ipw->is_v2_card, signalled_reboot_callback,187 ipw);188 189 ret = pcmcia_request_irq(link, ipwireless_interrupt);190 if (ret != 0)191 goto exit;192 193 printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",194 ipw->is_v2_card ? "V2/V3" : "V1");195 printk(KERN_INFO IPWIRELESS_PCCARD_NAME196 ": I/O ports %pR, irq %d\n", link->resource[0],197 (unsigned int) link->irq);198 if (ipw->attr_memory && ipw->common_memory)199 printk(KERN_INFO IPWIRELESS_PCCARD_NAME200 ": attr memory %pR, common memory %pR\n",201 link->resource[3],202 link->resource[2]);203 204 ipw->network = ipwireless_network_create(ipw->hardware);205 if (!ipw->network)206 goto exit;207 208 ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network);209 if (!ipw->tty)210 goto exit;211 212 ipwireless_init_hardware_v2_v3(ipw->hardware);213 214 /*215 * Do the RequestConfiguration last, because it enables interrupts.216 * Then we don't get any interrupts before we're ready for them.217 */218 ret = pcmcia_enable_device(link);219 if (ret != 0)220 goto exit;221 222 return 0;223 224exit:225 if (ipw->common_memory) {226 release_mem_region(link->resource[2]->start,227 resource_size(link->resource[2]));228 iounmap(ipw->common_memory);229 }230 if (ipw->attr_memory) {231 release_mem_region(link->resource[3]->start,232 resource_size(link->resource[3]));233 iounmap(ipw->attr_memory);234 }235 pcmcia_disable_device(link);236 return -1;237}238 239static void release_ipwireless(struct ipw_dev *ipw)240{241 release_region(ipw->link->resource[0]->start,242 resource_size(ipw->link->resource[0]));243 if (ipw->common_memory) {244 release_mem_region(ipw->link->resource[2]->start,245 resource_size(ipw->link->resource[2]));246 iounmap(ipw->common_memory);247 }248 if (ipw->attr_memory) {249 release_mem_region(ipw->link->resource[3]->start,250 resource_size(ipw->link->resource[3]));251 iounmap(ipw->attr_memory);252 }253 pcmcia_disable_device(ipw->link);254}255 256/*257 * ipwireless_attach() creates an "instance" of the driver, allocating258 * local data structures for one device (one interface). The device259 * is registered with Card Services.260 *261 * The pcmcia_device structure is initialized, but we don't actually262 * configure the card at this point -- we wait until we receive a263 * card insertion event.264 */265static int ipwireless_attach(struct pcmcia_device *link)266{267 struct ipw_dev *ipw;268 int ret;269 270 ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL);271 if (!ipw)272 return -ENOMEM;273 274 ipw->link = link;275 link->priv = ipw;276 277 ipw->hardware = ipwireless_hardware_create();278 if (!ipw->hardware) {279 kfree(ipw);280 return -ENOMEM;281 }282 /* RegisterClient will call config_ipwireless */283 284 ret = config_ipwireless(ipw);285 286 if (ret != 0) {287 ipwireless_detach(link);288 return ret;289 }290 291 return 0;292}293 294/*295 * This deletes a driver "instance". The device is de-registered with296 * Card Services. If it has been released, all local data structures297 * are freed. Otherwise, the structures will be freed when the device298 * is released.299 */300static void ipwireless_detach(struct pcmcia_device *link)301{302 struct ipw_dev *ipw = link->priv;303 304 release_ipwireless(ipw);305 306 if (ipw->tty != NULL)307 ipwireless_tty_free(ipw->tty);308 if (ipw->network != NULL)309 ipwireless_network_free(ipw->network);310 if (ipw->hardware != NULL)311 ipwireless_hardware_free(ipw->hardware);312 kfree(ipw);313}314 315static struct pcmcia_driver me = {316 .owner = THIS_MODULE,317 .probe = ipwireless_attach,318 .remove = ipwireless_detach,319 .name = IPWIRELESS_PCCARD_NAME,320 .id_table = ipw_ids321};322 323/*324 * Module insertion : initialisation of the module.325 * Register the card with cardmgr...326 */327static int __init init_ipwireless(void)328{329 int ret;330 331 ret = ipwireless_tty_init();332 if (ret != 0)333 return ret;334 335 ret = pcmcia_register_driver(&me);336 if (ret != 0)337 ipwireless_tty_release();338 339 return ret;340}341 342/*343 * Module removal344 */345static void __exit exit_ipwireless(void)346{347 pcmcia_unregister_driver(&me);348 ipwireless_tty_release();349}350 351module_init(init_ipwireless);352module_exit(exit_ipwireless);353 354MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);355MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);356MODULE_LICENSE("GPL");357