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