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