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