xref: /openbmc/linux/drivers/tty/ipwireless/tty.c (revision 63dc02bd)
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 <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/mutex.h>
22 #include <linux/ppp_defs.h>
23 #include <linux/if.h>
24 #include <linux/ppp-ioctl.h>
25 #include <linux/sched.h>
26 #include <linux/serial.h>
27 #include <linux/slab.h>
28 #include <linux/tty.h>
29 #include <linux/tty_driver.h>
30 #include <linux/tty_flip.h>
31 #include <linux/uaccess.h>
32 
33 #include "tty.h"
34 #include "network.h"
35 #include "hardware.h"
36 #include "main.h"
37 
38 #define IPWIRELESS_PCMCIA_START 	(0)
39 #define IPWIRELESS_PCMCIA_MINORS	(24)
40 #define IPWIRELESS_PCMCIA_MINOR_RANGE	(8)
41 
42 #define TTYTYPE_MODEM    (0)
43 #define TTYTYPE_MONITOR  (1)
44 #define TTYTYPE_RAS_RAW  (2)
45 
46 struct ipw_tty {
47 	int index;
48 	struct ipw_hardware *hardware;
49 	unsigned int channel_idx;
50 	unsigned int secondary_channel_idx;
51 	int tty_type;
52 	struct ipw_network *network;
53 	struct tty_struct *linux_tty;
54 	int open_count;
55 	unsigned int control_lines;
56 	struct mutex ipw_tty_mutex;
57 	int tx_bytes_queued;
58 	int closing;
59 };
60 
61 static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
62 
63 static struct tty_driver *ipw_tty_driver;
64 
65 static char *tty_type_name(int tty_type)
66 {
67 	static char *channel_names[] = {
68 		"modem",
69 		"monitor",
70 		"RAS-raw"
71 	};
72 
73 	return channel_names[tty_type];
74 }
75 
76 static void report_registering(struct ipw_tty *tty)
77 {
78 	char *iftype = tty_type_name(tty->tty_type);
79 
80 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
81 	       ": registering %s device ttyIPWp%d\n", iftype, tty->index);
82 }
83 
84 static void report_deregistering(struct ipw_tty *tty)
85 {
86 	char *iftype = tty_type_name(tty->tty_type);
87 
88 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
89 	       ": deregistering %s device ttyIPWp%d\n", iftype,
90 	       tty->index);
91 }
92 
93 static struct ipw_tty *get_tty(int index)
94 {
95 	/*
96 	 * The 'ras_raw' channel is only available when 'loopback' mode
97 	 * is enabled.
98 	 * Number of minor starts with 16 (_RANGE * _RAS_RAW).
99 	 */
100 	if (!ipwireless_loopback && index >=
101 			 IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
102 		return NULL;
103 
104 	return ttys[index];
105 }
106 
107 static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
108 {
109 	struct ipw_tty *tty = get_tty(linux_tty->index);
110 
111 	if (!tty)
112 		return -ENODEV;
113 
114 	mutex_lock(&tty->ipw_tty_mutex);
115 
116 	if (tty->closing) {
117 		mutex_unlock(&tty->ipw_tty_mutex);
118 		return -ENODEV;
119 	}
120 	if (tty->open_count == 0)
121 		tty->tx_bytes_queued = 0;
122 
123 	tty->open_count++;
124 
125 	tty->linux_tty = linux_tty;
126 	linux_tty->driver_data = tty;
127 	linux_tty->low_latency = 1;
128 
129 	if (tty->tty_type == TTYTYPE_MODEM)
130 		ipwireless_ppp_open(tty->network);
131 
132 	mutex_unlock(&tty->ipw_tty_mutex);
133 
134 	return 0;
135 }
136 
137 static void do_ipw_close(struct ipw_tty *tty)
138 {
139 	tty->open_count--;
140 
141 	if (tty->open_count == 0) {
142 		struct tty_struct *linux_tty = tty->linux_tty;
143 
144 		if (linux_tty != NULL) {
145 			tty->linux_tty = NULL;
146 			linux_tty->driver_data = NULL;
147 
148 			if (tty->tty_type == TTYTYPE_MODEM)
149 				ipwireless_ppp_close(tty->network);
150 		}
151 	}
152 }
153 
154 static void ipw_hangup(struct tty_struct *linux_tty)
155 {
156 	struct ipw_tty *tty = linux_tty->driver_data;
157 
158 	if (!tty)
159 		return;
160 
161 	mutex_lock(&tty->ipw_tty_mutex);
162 	if (tty->open_count == 0) {
163 		mutex_unlock(&tty->ipw_tty_mutex);
164 		return;
165 	}
166 
167 	do_ipw_close(tty);
168 
169 	mutex_unlock(&tty->ipw_tty_mutex);
170 }
171 
172 static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
173 {
174 	ipw_hangup(linux_tty);
175 }
176 
177 /* Take data received from hardware, and send it out the tty */
178 void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
179 			unsigned int length)
180 {
181 	struct tty_struct *linux_tty;
182 	int work = 0;
183 
184 	mutex_lock(&tty->ipw_tty_mutex);
185 	linux_tty = tty->linux_tty;
186 	if (linux_tty == NULL) {
187 		mutex_unlock(&tty->ipw_tty_mutex);
188 		return;
189 	}
190 
191 	if (!tty->open_count) {
192 		mutex_unlock(&tty->ipw_tty_mutex);
193 		return;
194 	}
195 	mutex_unlock(&tty->ipw_tty_mutex);
196 
197 	work = tty_insert_flip_string(linux_tty, data, length);
198 
199 	if (work != length)
200 		printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
201 				": %d chars not inserted to flip buffer!\n",
202 				length - work);
203 
204 	/*
205 	 * This may sleep if ->low_latency is set
206 	 */
207 	if (work)
208 		tty_flip_buffer_push(linux_tty);
209 }
210 
211 static void ipw_write_packet_sent_callback(void *callback_data,
212 					   unsigned int packet_length)
213 {
214 	struct ipw_tty *tty = callback_data;
215 
216 	/*
217 	 * Packet has been sent, so we subtract the number of bytes from our
218 	 * tally of outstanding TX bytes.
219 	 */
220 	tty->tx_bytes_queued -= packet_length;
221 }
222 
223 static int ipw_write(struct tty_struct *linux_tty,
224 		     const unsigned char *buf, int count)
225 {
226 	struct ipw_tty *tty = linux_tty->driver_data;
227 	int room, ret;
228 
229 	if (!tty)
230 		return -ENODEV;
231 
232 	mutex_lock(&tty->ipw_tty_mutex);
233 	if (!tty->open_count) {
234 		mutex_unlock(&tty->ipw_tty_mutex);
235 		return -EINVAL;
236 	}
237 
238 	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
239 	if (room < 0)
240 		room = 0;
241 	/* Don't allow caller to write any more than we have room for */
242 	if (count > room)
243 		count = room;
244 
245 	if (count == 0) {
246 		mutex_unlock(&tty->ipw_tty_mutex);
247 		return 0;
248 	}
249 
250 	ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
251 			       buf, count,
252 			       ipw_write_packet_sent_callback, tty);
253 	if (ret == -1) {
254 		mutex_unlock(&tty->ipw_tty_mutex);
255 		return 0;
256 	}
257 
258 	tty->tx_bytes_queued += count;
259 	mutex_unlock(&tty->ipw_tty_mutex);
260 
261 	return count;
262 }
263 
264 static int ipw_write_room(struct tty_struct *linux_tty)
265 {
266 	struct ipw_tty *tty = linux_tty->driver_data;
267 	int room;
268 
269 	/* FIXME: Exactly how is the tty object locked here .. */
270 	if (!tty)
271 		return -ENODEV;
272 
273 	if (!tty->open_count)
274 		return -EINVAL;
275 
276 	room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
277 	if (room < 0)
278 		room = 0;
279 
280 	return room;
281 }
282 
283 static int ipwireless_get_serial_info(struct ipw_tty *tty,
284 				      struct serial_struct __user *retinfo)
285 {
286 	struct serial_struct tmp;
287 
288 	if (!retinfo)
289 		return (-EFAULT);
290 
291 	memset(&tmp, 0, sizeof(tmp));
292 	tmp.type = PORT_UNKNOWN;
293 	tmp.line = tty->index;
294 	tmp.port = 0;
295 	tmp.irq = 0;
296 	tmp.flags = 0;
297 	tmp.baud_base = 115200;
298 	tmp.close_delay = 0;
299 	tmp.closing_wait = 0;
300 	tmp.custom_divisor = 0;
301 	tmp.hub6 = 0;
302 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
303 		return -EFAULT;
304 
305 	return 0;
306 }
307 
308 static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
309 {
310 	struct ipw_tty *tty = linux_tty->driver_data;
311 
312 	if (!tty)
313 		return 0;
314 
315 	if (!tty->open_count)
316 		return 0;
317 
318 	return tty->tx_bytes_queued;
319 }
320 
321 static int get_control_lines(struct ipw_tty *tty)
322 {
323 	unsigned int my = tty->control_lines;
324 	unsigned int out = 0;
325 
326 	if (my & IPW_CONTROL_LINE_RTS)
327 		out |= TIOCM_RTS;
328 	if (my & IPW_CONTROL_LINE_DTR)
329 		out |= TIOCM_DTR;
330 	if (my & IPW_CONTROL_LINE_CTS)
331 		out |= TIOCM_CTS;
332 	if (my & IPW_CONTROL_LINE_DSR)
333 		out |= TIOCM_DSR;
334 	if (my & IPW_CONTROL_LINE_DCD)
335 		out |= TIOCM_CD;
336 
337 	return out;
338 }
339 
340 static int set_control_lines(struct ipw_tty *tty, unsigned int set,
341 			     unsigned int clear)
342 {
343 	int ret;
344 
345 	if (set & TIOCM_RTS) {
346 		ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
347 		if (ret)
348 			return ret;
349 		if (tty->secondary_channel_idx != -1) {
350 			ret = ipwireless_set_RTS(tty->hardware,
351 					  tty->secondary_channel_idx, 1);
352 			if (ret)
353 				return ret;
354 		}
355 	}
356 	if (set & TIOCM_DTR) {
357 		ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
358 		if (ret)
359 			return ret;
360 		if (tty->secondary_channel_idx != -1) {
361 			ret = ipwireless_set_DTR(tty->hardware,
362 					  tty->secondary_channel_idx, 1);
363 			if (ret)
364 				return ret;
365 		}
366 	}
367 	if (clear & TIOCM_RTS) {
368 		ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
369 		if (tty->secondary_channel_idx != -1) {
370 			ret = ipwireless_set_RTS(tty->hardware,
371 					  tty->secondary_channel_idx, 0);
372 			if (ret)
373 				return ret;
374 		}
375 	}
376 	if (clear & TIOCM_DTR) {
377 		ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
378 		if (tty->secondary_channel_idx != -1) {
379 			ret = ipwireless_set_DTR(tty->hardware,
380 					  tty->secondary_channel_idx, 0);
381 			if (ret)
382 				return ret;
383 		}
384 	}
385 	return 0;
386 }
387 
388 static int ipw_tiocmget(struct tty_struct *linux_tty)
389 {
390 	struct ipw_tty *tty = linux_tty->driver_data;
391 	/* FIXME: Exactly how is the tty object locked here .. */
392 
393 	if (!tty)
394 		return -ENODEV;
395 
396 	if (!tty->open_count)
397 		return -EINVAL;
398 
399 	return get_control_lines(tty);
400 }
401 
402 static int
403 ipw_tiocmset(struct tty_struct *linux_tty,
404 	     unsigned int set, unsigned int clear)
405 {
406 	struct ipw_tty *tty = linux_tty->driver_data;
407 	/* FIXME: Exactly how is the tty object locked here .. */
408 
409 	if (!tty)
410 		return -ENODEV;
411 
412 	if (!tty->open_count)
413 		return -EINVAL;
414 
415 	return set_control_lines(tty, set, clear);
416 }
417 
418 static int ipw_ioctl(struct tty_struct *linux_tty,
419 		     unsigned int cmd, unsigned long arg)
420 {
421 	struct ipw_tty *tty = linux_tty->driver_data;
422 
423 	if (!tty)
424 		return -ENODEV;
425 
426 	if (!tty->open_count)
427 		return -EINVAL;
428 
429 	/* FIXME: Exactly how is the tty object locked here .. */
430 
431 	switch (cmd) {
432 	case TIOCGSERIAL:
433 		return ipwireless_get_serial_info(tty, (void __user *) arg);
434 
435 	case TIOCSSERIAL:
436 		return 0;	/* Keeps the PCMCIA scripts happy. */
437 	}
438 
439 	if (tty->tty_type == TTYTYPE_MODEM) {
440 		switch (cmd) {
441 		case PPPIOCGCHAN:
442 			{
443 				int chan = ipwireless_ppp_channel_index(
444 							tty->network);
445 
446 				if (chan < 0)
447 					return -ENODEV;
448 				if (put_user(chan, (int __user *) arg))
449 					return -EFAULT;
450 			}
451 			return 0;
452 
453 		case PPPIOCGUNIT:
454 			{
455 				int unit = ipwireless_ppp_unit_number(
456 						tty->network);
457 
458 				if (unit < 0)
459 					return -ENODEV;
460 				if (put_user(unit, (int __user *) arg))
461 					return -EFAULT;
462 			}
463 			return 0;
464 
465 		case FIONREAD:
466 			{
467 				int val = 0;
468 
469 				if (put_user(val, (int __user *) arg))
470 					return -EFAULT;
471 			}
472 			return 0;
473 		case TCFLSH:
474 			return tty_perform_flush(linux_tty, arg);
475 		}
476 	}
477 	return -ENOIOCTLCMD;
478 }
479 
480 static int add_tty(int j,
481 		    struct ipw_hardware *hardware,
482 		    struct ipw_network *network, int channel_idx,
483 		    int secondary_channel_idx, int tty_type)
484 {
485 	ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL);
486 	if (!ttys[j])
487 		return -ENOMEM;
488 	ttys[j]->index = j;
489 	ttys[j]->hardware = hardware;
490 	ttys[j]->channel_idx = channel_idx;
491 	ttys[j]->secondary_channel_idx = secondary_channel_idx;
492 	ttys[j]->network = network;
493 	ttys[j]->tty_type = tty_type;
494 	mutex_init(&ttys[j]->ipw_tty_mutex);
495 
496 	tty_register_device(ipw_tty_driver, j, NULL);
497 	ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
498 
499 	if (secondary_channel_idx != -1)
500 		ipwireless_associate_network_tty(network,
501 						 secondary_channel_idx,
502 						 ttys[j]);
503 	if (get_tty(j) == ttys[j])
504 		report_registering(ttys[j]);
505 	return 0;
506 }
507 
508 struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
509 				      struct ipw_network *network)
510 {
511 	int i, j;
512 
513 	for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
514 		int allfree = 1;
515 
516 		for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
517 				j += IPWIRELESS_PCMCIA_MINOR_RANGE)
518 			if (ttys[j] != NULL) {
519 				allfree = 0;
520 				break;
521 			}
522 
523 		if (allfree) {
524 			j = i;
525 
526 			if (add_tty(j, hardware, network,
527 					IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
528 					TTYTYPE_MODEM))
529 				return NULL;
530 
531 			j += IPWIRELESS_PCMCIA_MINOR_RANGE;
532 			if (add_tty(j, hardware, network,
533 					IPW_CHANNEL_DIALLER, -1,
534 					TTYTYPE_MONITOR))
535 				return NULL;
536 
537 			j += IPWIRELESS_PCMCIA_MINOR_RANGE;
538 			if (add_tty(j, hardware, network,
539 					IPW_CHANNEL_RAS, -1,
540 					TTYTYPE_RAS_RAW))
541 				return NULL;
542 
543 			return ttys[i];
544 		}
545 	}
546 	return NULL;
547 }
548 
549 /*
550  * Must be called before ipwireless_network_free().
551  */
552 void ipwireless_tty_free(struct ipw_tty *tty)
553 {
554 	int j;
555 	struct ipw_network *network = ttys[tty->index]->network;
556 
557 	for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
558 			j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
559 		struct ipw_tty *ttyj = ttys[j];
560 
561 		if (ttyj) {
562 			mutex_lock(&ttyj->ipw_tty_mutex);
563 			if (get_tty(j) == ttyj)
564 				report_deregistering(ttyj);
565 			ttyj->closing = 1;
566 			if (ttyj->linux_tty != NULL) {
567 				mutex_unlock(&ttyj->ipw_tty_mutex);
568 				tty_hangup(ttyj->linux_tty);
569 				/* Wait till the tty_hangup has completed */
570 				flush_work_sync(&ttyj->linux_tty->hangup_work);
571 				/* FIXME: Exactly how is the tty object locked here
572 				   against a parallel ioctl etc */
573 				mutex_lock(&ttyj->ipw_tty_mutex);
574 			}
575 			while (ttyj->open_count)
576 				do_ipw_close(ttyj);
577 			ipwireless_disassociate_network_ttys(network,
578 							     ttyj->channel_idx);
579 			tty_unregister_device(ipw_tty_driver, j);
580 			ttys[j] = NULL;
581 			mutex_unlock(&ttyj->ipw_tty_mutex);
582 			kfree(ttyj);
583 		}
584 	}
585 }
586 
587 static const struct tty_operations tty_ops = {
588 	.open = ipw_open,
589 	.close = ipw_close,
590 	.hangup = ipw_hangup,
591 	.write = ipw_write,
592 	.write_room = ipw_write_room,
593 	.ioctl = ipw_ioctl,
594 	.chars_in_buffer = ipw_chars_in_buffer,
595 	.tiocmget = ipw_tiocmget,
596 	.tiocmset = ipw_tiocmset,
597 };
598 
599 int ipwireless_tty_init(void)
600 {
601 	int result;
602 
603 	ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS);
604 	if (!ipw_tty_driver)
605 		return -ENOMEM;
606 
607 	ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
608 	ipw_tty_driver->name = "ttyIPWp";
609 	ipw_tty_driver->major = 0;
610 	ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
611 	ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
612 	ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
613 	ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
614 	ipw_tty_driver->init_termios = tty_std_termios;
615 	ipw_tty_driver->init_termios.c_cflag =
616 	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
617 	ipw_tty_driver->init_termios.c_ispeed = 9600;
618 	ipw_tty_driver->init_termios.c_ospeed = 9600;
619 	tty_set_operations(ipw_tty_driver, &tty_ops);
620 	result = tty_register_driver(ipw_tty_driver);
621 	if (result) {
622 		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
623 		       ": failed to register tty driver\n");
624 		put_tty_driver(ipw_tty_driver);
625 		return result;
626 	}
627 
628 	return 0;
629 }
630 
631 void ipwireless_tty_release(void)
632 {
633 	int ret;
634 
635 	ret = tty_unregister_driver(ipw_tty_driver);
636 	put_tty_driver(ipw_tty_driver);
637 	if (ret != 0)
638 		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
639 			": tty_unregister_driver failed with code %d\n", ret);
640 }
641 
642 int ipwireless_tty_is_modem(struct ipw_tty *tty)
643 {
644 	return tty->tty_type == TTYTYPE_MODEM;
645 }
646 
647 void
648 ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
649 					  unsigned int channel_idx,
650 					  unsigned int control_lines,
651 					  unsigned int changed_mask)
652 {
653 	unsigned int old_control_lines = tty->control_lines;
654 
655 	tty->control_lines = (tty->control_lines & ~changed_mask)
656 		| (control_lines & changed_mask);
657 
658 	/*
659 	 * If DCD is de-asserted, we close the tty so pppd can tell that we
660 	 * have gone offline.
661 	 */
662 	if ((old_control_lines & IPW_CONTROL_LINE_DCD)
663 			&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
664 			&& tty->linux_tty) {
665 		tty_hangup(tty->linux_tty);
666 	}
667 }
668 
669