• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 static 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 };
42 MODULE_DEVICE_TABLE(pcmcia, ipw_ids);
43 
44 static void ipwireless_detach(struct pcmcia_device *link);
45 
46 /*
47  * Module params
48  */
49 /* Debug mode: more verbose, print sent/recv bytes */
50 int ipwireless_debug;
51 int ipwireless_loopback;
52 int ipwireless_out_queue = 10;
53 
54 module_param_named(debug, ipwireless_debug, int, 0);
55 module_param_named(loopback, ipwireless_loopback, int, 0);
56 module_param_named(out_queue, ipwireless_out_queue, int, 0);
57 MODULE_PARM_DESC(debug, "switch on debug messages [0]");
58 MODULE_PARM_DESC(loopback,
59 		"debug: enable ras_raw channel [0]");
60 MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]");
61 
62 /* Executes in process context. */
signalled_reboot_work(struct work_struct * work_reboot)63 static 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 	int ret = pcmcia_reset_card(link->socket);
69 
70 	if (ret != 0)
71 		cs_error(link, ResetCard, ret);
72 }
73 
signalled_reboot_callback(void * callback_data)74 static void signalled_reboot_callback(void *callback_data)
75 {
76 	struct ipw_dev *ipw = (struct ipw_dev *) callback_data;
77 
78 	/* Delegate to process context. */
79 	schedule_work(&ipw->work_reboot);
80 }
81 
config_ipwireless(struct ipw_dev * ipw)82 static int config_ipwireless(struct ipw_dev *ipw)
83 {
84 	struct pcmcia_device *link = ipw->link;
85 	int ret;
86 	tuple_t tuple;
87 	unsigned short buf[64];
88 	cisparse_t parse;
89 	unsigned short cor_value;
90 	memreq_t memreq_attr_memory;
91 	memreq_t memreq_common_memory;
92 
93 	ipw->is_v2_card = 0;
94 
95 	tuple.Attributes = 0;
96 	tuple.TupleData = (cisdata_t *) buf;
97 	tuple.TupleDataMax = sizeof(buf);
98 	tuple.TupleOffset = 0;
99 
100 	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
101 
102 	ret = pcmcia_get_first_tuple(link, &tuple);
103 
104 	while (ret == 0) {
105 		ret = pcmcia_get_tuple_data(link, &tuple);
106 
107 		if (ret != 0) {
108 			cs_error(link, GetTupleData, ret);
109 			goto exit0;
110 		}
111 		ret = pcmcia_get_next_tuple(link, &tuple);
112 	}
113 
114 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
115 
116 	ret = pcmcia_get_first_tuple(link, &tuple);
117 
118 	if (ret != 0) {
119 		cs_error(link, GetFirstTuple, ret);
120 		goto exit0;
121 	}
122 
123 	ret = pcmcia_get_tuple_data(link, &tuple);
124 
125 	if (ret != 0) {
126 		cs_error(link, GetTupleData, ret);
127 		goto exit0;
128 	}
129 
130 	ret = pcmcia_parse_tuple(&tuple, &parse);
131 
132 	if (ret != 0) {
133 		cs_error(link, ParseTuple, ret);
134 		goto exit0;
135 	}
136 
137 	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
138 	link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
139 	link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
140 	link->io.IOAddrLines = 16;
141 
142 	link->irq.IRQInfo1 = parse.cftable_entry.irq.IRQInfo1;
143 
144 	/* 0x40 causes it to generate level mode interrupts. */
145 	/* 0x04 enables IREQ pin. */
146 	cor_value = parse.cftable_entry.index | 0x44;
147 	link->conf.ConfigIndex = cor_value;
148 
149 	/* IRQ and I/O settings */
150 	tuple.DesiredTuple = CISTPL_CONFIG;
151 
152 	ret = pcmcia_get_first_tuple(link, &tuple);
153 
154 	if (ret != 0) {
155 		cs_error(link, GetFirstTuple, ret);
156 		goto exit0;
157 	}
158 
159 	ret = pcmcia_get_tuple_data(link, &tuple);
160 
161 	if (ret != 0) {
162 		cs_error(link, GetTupleData, ret);
163 		goto exit0;
164 	}
165 
166 	ret = pcmcia_parse_tuple(&tuple, &parse);
167 
168 	if (ret != 0) {
169 		cs_error(link, GetTupleData, ret);
170 		goto exit0;
171 	}
172 	link->conf.Attributes = CONF_ENABLE_IRQ;
173 	link->conf.ConfigBase = parse.config.base;
174 	link->conf.Present = parse.config.rmask[0];
175 	link->conf.IntType = INT_MEMORY_AND_IO;
176 
177 	link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
178 	link->irq.Handler = ipwireless_interrupt;
179 	link->irq.Instance = ipw->hardware;
180 
181 	ret = pcmcia_request_io(link, &link->io);
182 
183 	if (ret != 0) {
184 		cs_error(link, RequestIO, ret);
185 		goto exit0;
186 	}
187 
188 	request_region(link->io.BasePort1, link->io.NumPorts1,
189 			IPWIRELESS_PCCARD_NAME);
190 
191 	/* memory settings */
192 
193 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
194 
195 	ret = pcmcia_get_first_tuple(link, &tuple);
196 
197 	if (ret != 0) {
198 		cs_error(link, GetFirstTuple, ret);
199 		goto exit1;
200 	}
201 
202 	ret = pcmcia_get_tuple_data(link, &tuple);
203 
204 	if (ret != 0) {
205 		cs_error(link, GetTupleData, ret);
206 		goto exit1;
207 	}
208 
209 	ret = pcmcia_parse_tuple(&tuple, &parse);
210 
211 	if (ret != 0) {
212 		cs_error(link, ParseTuple, ret);
213 		goto exit1;
214 	}
215 
216 	if (parse.cftable_entry.mem.nwin > 0) {
217 		ipw->request_common_memory.Attributes =
218 			WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
219 		ipw->request_common_memory.Base =
220 			parse.cftable_entry.mem.win[0].host_addr;
221 		ipw->request_common_memory.Size = parse.cftable_entry.mem.win[0].len;
222 		if (ipw->request_common_memory.Size < 0x1000)
223 			ipw->request_common_memory.Size = 0x1000;
224 		ipw->request_common_memory.AccessSpeed = 0;
225 
226 		ret = pcmcia_request_window(&link, &ipw->request_common_memory,
227 				&ipw->handle_common_memory);
228 
229 		if (ret != 0) {
230 			cs_error(link, RequestWindow, ret);
231 			goto exit1;
232 		}
233 
234 		memreq_common_memory.CardOffset =
235 			parse.cftable_entry.mem.win[0].card_addr;
236 		memreq_common_memory.Page = 0;
237 
238 		ret = pcmcia_map_mem_page(ipw->handle_common_memory,
239 				&memreq_common_memory);
240 
241 		if (ret != 0) {
242 			cs_error(link, MapMemPage, ret);
243 			goto exit1;
244 		}
245 
246 		ipw->is_v2_card =
247 			parse.cftable_entry.mem.win[0].len == 0x100;
248 
249 		ipw->common_memory = ioremap(ipw->request_common_memory.Base,
250 				ipw->request_common_memory.Size);
251 		request_mem_region(ipw->request_common_memory.Base,
252 				ipw->request_common_memory.Size, IPWIRELESS_PCCARD_NAME);
253 
254 		ipw->request_attr_memory.Attributes =
255 			WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
256 		ipw->request_attr_memory.Base = 0;
257 		ipw->request_attr_memory.Size = 0;	/* this used to be 0x1000 */
258 		ipw->request_attr_memory.AccessSpeed = 0;
259 
260 		ret = pcmcia_request_window(&link, &ipw->request_attr_memory,
261 				&ipw->handle_attr_memory);
262 
263 		if (ret != 0) {
264 			cs_error(link, RequestWindow, ret);
265 			goto exit2;
266 		}
267 
268 		memreq_attr_memory.CardOffset = 0;
269 		memreq_attr_memory.Page = 0;
270 
271 		ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
272 				&memreq_attr_memory);
273 
274 		if (ret != 0) {
275 			cs_error(link, MapMemPage, ret);
276 			goto exit2;
277 		}
278 
279 		ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
280 				ipw->request_attr_memory.Size);
281 		request_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size,
282 				IPWIRELESS_PCCARD_NAME);
283 	}
284 
285 	INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
286 
287 	ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1,
288 				    ipw->attr_memory, ipw->common_memory,
289 				    ipw->is_v2_card, signalled_reboot_callback,
290 				    ipw);
291 
292 	ret = pcmcia_request_irq(link, &link->irq);
293 
294 	if (ret != 0) {
295 		cs_error(link, RequestIRQ, ret);
296 		goto exit3;
297 	}
298 
299 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
300 			ipw->is_v2_card ? "V2/V3" : "V1");
301 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
302 			": I/O ports 0x%04x-0x%04x, irq %d\n",
303 			(unsigned int) link->io.BasePort1,
304 			(unsigned int) (link->io.BasePort1 +
305 				link->io.NumPorts1 - 1),
306 			(unsigned int) link->irq.AssignedIRQ);
307 	if (ipw->attr_memory && ipw->common_memory)
308 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
309 			": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n",
310 			ipw->request_attr_memory.Base,
311 			ipw->request_attr_memory.Base
312 			+ ipw->request_attr_memory.Size - 1,
313 			ipw->request_common_memory.Base,
314 			ipw->request_common_memory.Base
315 			+ ipw->request_common_memory.Size - 1);
316 
317 	ipw->network = ipwireless_network_create(ipw->hardware);
318 	if (!ipw->network)
319 		goto exit3;
320 
321 	ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network,
322 			ipw->nodes);
323 	if (!ipw->tty)
324 		goto exit3;
325 
326 	ipwireless_init_hardware_v2_v3(ipw->hardware);
327 
328 	/*
329 	 * Do the RequestConfiguration last, because it enables interrupts.
330 	 * Then we don't get any interrupts before we're ready for them.
331 	 */
332 	ret = pcmcia_request_configuration(link, &link->conf);
333 
334 	if (ret != 0) {
335 		cs_error(link, RequestConfiguration, ret);
336 		goto exit4;
337 	}
338 
339 	link->dev_node = &ipw->nodes[0];
340 
341 	return 0;
342 
343 exit4:
344 	pcmcia_disable_device(link);
345 exit3:
346 	if (ipw->attr_memory) {
347 		release_mem_region(ipw->request_attr_memory.Base,
348 				ipw->request_attr_memory.Size);
349 		iounmap(ipw->attr_memory);
350 		pcmcia_release_window(ipw->handle_attr_memory);
351 		pcmcia_disable_device(link);
352 	}
353 exit2:
354 	if (ipw->common_memory) {
355 		release_mem_region(ipw->request_common_memory.Base,
356 				ipw->request_common_memory.Size);
357 		iounmap(ipw->common_memory);
358 		pcmcia_release_window(ipw->handle_common_memory);
359 	}
360 exit1:
361 	pcmcia_disable_device(link);
362 exit0:
363 	return -1;
364 }
365 
release_ipwireless(struct ipw_dev * ipw)366 static void release_ipwireless(struct ipw_dev *ipw)
367 {
368 	pcmcia_disable_device(ipw->link);
369 
370 	if (ipw->common_memory) {
371 		release_mem_region(ipw->request_common_memory.Base,
372 				ipw->request_common_memory.Size);
373 		iounmap(ipw->common_memory);
374 	}
375 	if (ipw->attr_memory) {
376 		release_mem_region(ipw->request_attr_memory.Base,
377 				ipw->request_attr_memory.Size);
378 		iounmap(ipw->attr_memory);
379 	}
380 	if (ipw->common_memory)
381 		pcmcia_release_window(ipw->handle_common_memory);
382 	if (ipw->attr_memory)
383 		pcmcia_release_window(ipw->handle_attr_memory);
384 
385 	/* Break the link with Card Services */
386 	pcmcia_disable_device(ipw->link);
387 }
388 
389 /*
390  * ipwireless_attach() creates an "instance" of the driver, allocating
391  * local data structures for one device (one interface).  The device
392  * is registered with Card Services.
393  *
394  * The pcmcia_device structure is initialized, but we don't actually
395  * configure the card at this point -- we wait until we receive a
396  * card insertion event.
397  */
ipwireless_attach(struct pcmcia_device * link)398 static int ipwireless_attach(struct pcmcia_device *link)
399 {
400 	struct ipw_dev *ipw;
401 	int ret;
402 
403 	ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL);
404 	if (!ipw)
405 		return -ENOMEM;
406 
407 	ipw->link = link;
408 	link->priv = ipw;
409 	link->irq.Instance = ipw;
410 
411 	/* Link this device into our device list. */
412 	link->dev_node = &ipw->nodes[0];
413 
414 	ipw->hardware = ipwireless_hardware_create();
415 	if (!ipw->hardware) {
416 		kfree(ipw);
417 		return -ENOMEM;
418 	}
419 	/* RegisterClient will call config_ipwireless */
420 
421 	ret = config_ipwireless(ipw);
422 
423 	if (ret != 0) {
424 		cs_error(link, RegisterClient, ret);
425 		ipwireless_detach(link);
426 		return ret;
427 	}
428 
429 	return 0;
430 }
431 
432 /*
433  * This deletes a driver "instance".  The device is de-registered with
434  * Card Services.  If it has been released, all local data structures
435  * are freed.  Otherwise, the structures will be freed when the device
436  * is released.
437  */
ipwireless_detach(struct pcmcia_device * link)438 static void ipwireless_detach(struct pcmcia_device *link)
439 {
440 	struct ipw_dev *ipw = link->priv;
441 
442 	release_ipwireless(ipw);
443 
444 	if (ipw->tty != NULL)
445 		ipwireless_tty_free(ipw->tty);
446 	if (ipw->network != NULL)
447 		ipwireless_network_free(ipw->network);
448 	if (ipw->hardware != NULL)
449 		ipwireless_hardware_free(ipw->hardware);
450 	kfree(ipw);
451 }
452 
453 static struct pcmcia_driver me = {
454 	.owner		= THIS_MODULE,
455 	.probe          = ipwireless_attach,
456 	.remove         = ipwireless_detach,
457 	.drv = { .name  = IPWIRELESS_PCCARD_NAME },
458 	.id_table       = ipw_ids
459 };
460 
461 /*
462  * Module insertion : initialisation of the module.
463  * Register the card with cardmgr...
464  */
init_ipwireless(void)465 static int __init init_ipwireless(void)
466 {
467 	int ret;
468 
469 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
470 	       IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n");
471 
472 	ret = ipwireless_tty_init();
473 	if (ret != 0)
474 		return ret;
475 
476 	ret = pcmcia_register_driver(&me);
477 	if (ret != 0)
478 		ipwireless_tty_release();
479 
480 	return ret;
481 }
482 
483 /*
484  * Module removal
485  */
exit_ipwireless(void)486 static void __exit exit_ipwireless(void)
487 {
488 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
489 			IPWIRELESS_PCMCIA_VERSION " removed\n");
490 
491 	pcmcia_unregister_driver(&me);
492 	ipwireless_tty_release();
493 }
494 
495 module_init(init_ipwireless);
496 module_exit(exit_ipwireless);
497 
498 MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);
499 MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);
500 MODULE_LICENSE("GPL");
501