Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / isdn / gigaset / interface.c
1 /*
2  * interface to user space for the gigaset driver
3  *
4  * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
5  *
6  * =====================================================================
7  *    This program is free software; you can redistribute it and/or
8  *    modify it under the terms of the GNU General Public License as
9  *    published by the Free Software Foundation; either version 2 of
10  *    the License, or (at your option) any later version.
11  * =====================================================================
12  */
13
14 #include "gigaset.h"
15 #include <linux/gigaset_dev.h>
16 #include <linux/tty_flip.h>
17 #include <linux/module.h>
18
19 /*** our ioctls ***/
20
21 static int if_lock(struct cardstate *cs, int *arg)
22 {
23         int cmd = *arg;
24
25         gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
26
27         if (cmd > 1)
28                 return -EINVAL;
29
30         if (cmd < 0) {
31                 *arg = cs->mstate == MS_LOCKED;
32                 return 0;
33         }
34
35         if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
36                 cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR | TIOCM_RTS);
37                 cs->ops->baud_rate(cs, B115200);
38                 cs->ops->set_line_ctrl(cs, CS8);
39                 cs->control_state = TIOCM_DTR | TIOCM_RTS;
40         }
41
42         cs->waiting = 1;
43         if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
44                                NULL, cmd, NULL)) {
45                 cs->waiting = 0;
46                 return -ENOMEM;
47         }
48         gigaset_schedule_event(cs);
49
50         wait_event(cs->waitqueue, !cs->waiting);
51
52         if (cs->cmd_result >= 0) {
53                 *arg = cs->cmd_result;
54                 return 0;
55         }
56
57         return cs->cmd_result;
58 }
59
60 static int if_version(struct cardstate *cs, unsigned arg[4])
61 {
62         static const unsigned version[4] = GIG_VERSION;
63         static const unsigned compat[4] = GIG_COMPAT;
64         unsigned cmd = arg[0];
65
66         gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
67
68         switch (cmd) {
69         case GIGVER_DRIVER:
70                 memcpy(arg, version, sizeof version);
71                 return 0;
72         case GIGVER_COMPAT:
73                 memcpy(arg, compat, sizeof compat);
74                 return 0;
75         case GIGVER_FWBASE:
76                 cs->waiting = 1;
77                 if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
78                                        NULL, 0, arg)) {
79                         cs->waiting = 0;
80                         return -ENOMEM;
81                 }
82                 gigaset_schedule_event(cs);
83
84                 wait_event(cs->waitqueue, !cs->waiting);
85
86                 if (cs->cmd_result >= 0)
87                         return 0;
88
89                 return cs->cmd_result;
90         default:
91                 return -EINVAL;
92         }
93 }
94
95 static int if_config(struct cardstate *cs, int *arg)
96 {
97         gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
98
99         if (*arg != 1)
100                 return -EINVAL;
101
102         if (cs->mstate != MS_LOCKED)
103                 return -EBUSY;
104
105         if (!cs->connected) {
106                 pr_err("%s: not connected\n", __func__);
107                 return -ENODEV;
108         }
109
110         *arg = 0;
111         return gigaset_enterconfigmode(cs);
112 }
113
114 /*** the terminal driver ***/
115
116 static int if_open(struct tty_struct *tty, struct file *filp)
117 {
118         struct cardstate *cs;
119
120         gig_dbg(DEBUG_IF, "%d+%d: %s()",
121                 tty->driver->minor_start, tty->index, __func__);
122
123         cs = gigaset_get_cs_by_tty(tty);
124         if (!cs || !try_module_get(cs->driver->owner))
125                 return -ENODEV;
126
127         if (mutex_lock_interruptible(&cs->mutex)) {
128                 module_put(cs->driver->owner);
129                 return -ERESTARTSYS;
130         }
131         tty->driver_data = cs;
132
133         ++cs->port.count;
134
135         if (cs->port.count == 1) {
136                 tty_port_tty_set(&cs->port, tty);
137                 cs->port.low_latency = 1;
138         }
139
140         mutex_unlock(&cs->mutex);
141         return 0;
142 }
143
144 static void if_close(struct tty_struct *tty, struct file *filp)
145 {
146         struct cardstate *cs = tty->driver_data;
147
148         if (!cs) { /* happens if we didn't find cs in open */
149                 gig_dbg(DEBUG_IF, "%s: no cardstate", __func__);
150                 return;
151         }
152
153         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
154
155         mutex_lock(&cs->mutex);
156
157         if (!cs->connected)
158                 gig_dbg(DEBUG_IF, "not connected");     /* nothing to do */
159         else if (!cs->port.count)
160                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
161         else if (!--cs->port.count)
162                 tty_port_tty_set(&cs->port, NULL);
163
164         mutex_unlock(&cs->mutex);
165
166         module_put(cs->driver->owner);
167 }
168
169 static int if_ioctl(struct tty_struct *tty,
170                     unsigned int cmd, unsigned long arg)
171 {
172         struct cardstate *cs = tty->driver_data;
173         int retval = -ENODEV;
174         int int_arg;
175         unsigned char buf[6];
176         unsigned version[4];
177
178         gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
179
180         if (mutex_lock_interruptible(&cs->mutex))
181                 return -ERESTARTSYS;
182
183         if (!cs->connected) {
184                 gig_dbg(DEBUG_IF, "not connected");
185                 retval = -ENODEV;
186         } else {
187                 retval = 0;
188                 switch (cmd) {
189                 case GIGASET_REDIR:
190                         retval = get_user(int_arg, (int __user *) arg);
191                         if (retval >= 0)
192                                 retval = if_lock(cs, &int_arg);
193                         if (retval >= 0)
194                                 retval = put_user(int_arg, (int __user *) arg);
195                         break;
196                 case GIGASET_CONFIG:
197                         retval = get_user(int_arg, (int __user *) arg);
198                         if (retval >= 0)
199                                 retval = if_config(cs, &int_arg);
200                         if (retval >= 0)
201                                 retval = put_user(int_arg, (int __user *) arg);
202                         break;
203                 case GIGASET_BRKCHARS:
204                         retval = copy_from_user(&buf,
205                                                 (const unsigned char __user *) arg, 6)
206                                 ? -EFAULT : 0;
207                         if (retval >= 0) {
208                                 gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
209                                                    6, (const unsigned char *) arg);
210                                 retval = cs->ops->brkchars(cs, buf);
211                         }
212                         break;
213                 case GIGASET_VERSION:
214                         retval = copy_from_user(version,
215                                                 (unsigned __user *) arg, sizeof version)
216                                 ? -EFAULT : 0;
217                         if (retval >= 0)
218                                 retval = if_version(cs, version);
219                         if (retval >= 0)
220                                 retval = copy_to_user((unsigned __user *) arg,
221                                                       version, sizeof version)
222                                         ? -EFAULT : 0;
223                         break;
224                 default:
225                         gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x",
226                                 __func__, cmd);
227                         retval = -ENOIOCTLCMD;
228                 }
229         }
230
231         mutex_unlock(&cs->mutex);
232
233         return retval;
234 }
235
236 static int if_tiocmget(struct tty_struct *tty)
237 {
238         struct cardstate *cs = tty->driver_data;
239         int retval;
240
241         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
242
243         if (mutex_lock_interruptible(&cs->mutex))
244                 return -ERESTARTSYS;
245
246         retval = cs->control_state & (TIOCM_RTS | TIOCM_DTR);
247
248         mutex_unlock(&cs->mutex);
249
250         return retval;
251 }
252
253 static int if_tiocmset(struct tty_struct *tty,
254                        unsigned int set, unsigned int clear)
255 {
256         struct cardstate *cs = tty->driver_data;
257         int retval;
258         unsigned mc;
259
260         gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
261                 cs->minor_index, __func__, set, clear);
262
263         if (mutex_lock_interruptible(&cs->mutex))
264                 return -ERESTARTSYS;
265
266         if (!cs->connected) {
267                 gig_dbg(DEBUG_IF, "not connected");
268                 retval = -ENODEV;
269         } else {
270                 mc = (cs->control_state | set) & ~clear & (TIOCM_RTS | TIOCM_DTR);
271                 retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
272                 cs->control_state = mc;
273         }
274
275         mutex_unlock(&cs->mutex);
276
277         return retval;
278 }
279
280 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
281 {
282         struct cardstate *cs = tty->driver_data;
283         struct cmdbuf_t *cb;
284         int retval;
285
286         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
287
288         if (mutex_lock_interruptible(&cs->mutex))
289                 return -ERESTARTSYS;
290
291         if (!cs->connected) {
292                 gig_dbg(DEBUG_IF, "not connected");
293                 retval = -ENODEV;
294                 goto done;
295         }
296         if (cs->mstate != MS_LOCKED) {
297                 dev_warn(cs->dev, "can't write to unlocked device\n");
298                 retval = -EBUSY;
299                 goto done;
300         }
301         if (count <= 0) {
302                 /* nothing to do */
303                 retval = 0;
304                 goto done;
305         }
306
307         cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL);
308         if (!cb) {
309                 dev_err(cs->dev, "%s: out of memory\n", __func__);
310                 retval = -ENOMEM;
311                 goto done;
312         }
313
314         memcpy(cb->buf, buf, count);
315         cb->len = count;
316         cb->offset = 0;
317         cb->next = NULL;
318         cb->wake_tasklet = &cs->if_wake_tasklet;
319         retval = cs->ops->write_cmd(cs, cb);
320 done:
321         mutex_unlock(&cs->mutex);
322         return retval;
323 }
324
325 static int if_write_room(struct tty_struct *tty)
326 {
327         struct cardstate *cs = tty->driver_data;
328         int retval;
329
330         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
331
332         if (mutex_lock_interruptible(&cs->mutex))
333                 return -ERESTARTSYS;
334
335         if (!cs->connected) {
336                 gig_dbg(DEBUG_IF, "not connected");
337                 retval = -ENODEV;
338         } else if (cs->mstate != MS_LOCKED) {
339                 dev_warn(cs->dev, "can't write to unlocked device\n");
340                 retval = -EBUSY;
341         } else
342                 retval = cs->ops->write_room(cs);
343
344         mutex_unlock(&cs->mutex);
345
346         return retval;
347 }
348
349 static int if_chars_in_buffer(struct tty_struct *tty)
350 {
351         struct cardstate *cs = tty->driver_data;
352         int retval = 0;
353
354         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
355
356         mutex_lock(&cs->mutex);
357
358         if (!cs->connected)
359                 gig_dbg(DEBUG_IF, "not connected");
360         else if (cs->mstate != MS_LOCKED)
361                 dev_warn(cs->dev, "can't write to unlocked device\n");
362         else
363                 retval = cs->ops->chars_in_buffer(cs);
364
365         mutex_unlock(&cs->mutex);
366
367         return retval;
368 }
369
370 static void if_throttle(struct tty_struct *tty)
371 {
372         struct cardstate *cs = tty->driver_data;
373
374         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
375
376         mutex_lock(&cs->mutex);
377
378         if (!cs->connected)
379                 gig_dbg(DEBUG_IF, "not connected");     /* nothing to do */
380         else
381                 gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
382
383         mutex_unlock(&cs->mutex);
384 }
385
386 static void if_unthrottle(struct tty_struct *tty)
387 {
388         struct cardstate *cs = tty->driver_data;
389
390         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
391
392         mutex_lock(&cs->mutex);
393
394         if (!cs->connected)
395                 gig_dbg(DEBUG_IF, "not connected");     /* nothing to do */
396         else
397                 gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
398
399         mutex_unlock(&cs->mutex);
400 }
401
402 static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
403 {
404         struct cardstate *cs = tty->driver_data;
405         unsigned int iflag;
406         unsigned int cflag;
407         unsigned int old_cflag;
408         unsigned int control_state, new_state;
409
410         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
411
412         mutex_lock(&cs->mutex);
413
414         if (!cs->connected) {
415                 gig_dbg(DEBUG_IF, "not connected");
416                 goto out;
417         }
418
419         iflag = tty->termios.c_iflag;
420         cflag = tty->termios.c_cflag;
421         old_cflag = old ? old->c_cflag : cflag;
422         gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
423                 cs->minor_index, iflag, cflag, old_cflag);
424
425         /* get a local copy of the current port settings */
426         control_state = cs->control_state;
427
428         /*
429          * Update baud rate.
430          * Do not attempt to cache old rates and skip settings,
431          * disconnects screw such tricks up completely.
432          * Premature optimization is the root of all evil.
433          */
434
435         /* reassert DTR and (maybe) RTS on transition from B0 */
436         if ((old_cflag & CBAUD) == B0) {
437                 new_state = control_state | TIOCM_DTR;
438                 /* don't set RTS if using hardware flow control */
439                 if (!(old_cflag & CRTSCTS))
440                         new_state |= TIOCM_RTS;
441                 gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
442                         cs->minor_index,
443                         (new_state & TIOCM_RTS) ? " only" : "/RTS");
444                 cs->ops->set_modem_ctrl(cs, control_state, new_state);
445                 control_state = new_state;
446         }
447
448         cs->ops->baud_rate(cs, cflag & CBAUD);
449
450         if ((cflag & CBAUD) == B0) {
451                 /* Drop RTS and DTR */
452                 gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
453                 new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
454                 cs->ops->set_modem_ctrl(cs, control_state, new_state);
455                 control_state = new_state;
456         }
457
458         /*
459          * Update line control register (LCR)
460          */
461
462         cs->ops->set_line_ctrl(cs, cflag);
463
464         /* save off the modified port settings */
465         cs->control_state = control_state;
466
467 out:
468         mutex_unlock(&cs->mutex);
469 }
470
471 static const struct tty_operations if_ops = {
472         .open =                 if_open,
473         .close =                if_close,
474         .ioctl =                if_ioctl,
475         .write =                if_write,
476         .write_room =           if_write_room,
477         .chars_in_buffer =      if_chars_in_buffer,
478         .set_termios =          if_set_termios,
479         .throttle =             if_throttle,
480         .unthrottle =           if_unthrottle,
481         .tiocmget =             if_tiocmget,
482         .tiocmset =             if_tiocmset,
483 };
484
485
486 /* wakeup tasklet for the write operation */
487 static void if_wake(unsigned long data)
488 {
489         struct cardstate *cs = (struct cardstate *)data;
490
491         tty_port_tty_wakeup(&cs->port);
492 }
493
494 /*** interface to common ***/
495
496 void gigaset_if_init(struct cardstate *cs)
497 {
498         struct gigaset_driver *drv;
499
500         drv = cs->driver;
501         if (!drv->have_tty)
502                 return;
503
504         tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
505
506         mutex_lock(&cs->mutex);
507         cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
508                         cs->minor_index, NULL);
509
510         if (!IS_ERR(cs->tty_dev))
511                 dev_set_drvdata(cs->tty_dev, cs);
512         else {
513                 pr_warning("could not register device to the tty subsystem\n");
514                 cs->tty_dev = NULL;
515         }
516         mutex_unlock(&cs->mutex);
517 }
518
519 void gigaset_if_free(struct cardstate *cs)
520 {
521         struct gigaset_driver *drv;
522
523         drv = cs->driver;
524         if (!drv->have_tty)
525                 return;
526
527         tasklet_disable(&cs->if_wake_tasklet);
528         tasklet_kill(&cs->if_wake_tasklet);
529         cs->tty_dev = NULL;
530         tty_unregister_device(drv->tty, cs->minor_index);
531 }
532
533 /**
534  * gigaset_if_receive() - pass a received block of data to the tty device
535  * @cs:         device descriptor structure.
536  * @buffer:     received data.
537  * @len:        number of bytes received.
538  *
539  * Called by asyncdata/isocdata if a block of data received from the
540  * device must be sent to userspace through the ttyG* device.
541  */
542 void gigaset_if_receive(struct cardstate *cs,
543                         unsigned char *buffer, size_t len)
544 {
545         tty_insert_flip_string(&cs->port, buffer, len);
546         tty_flip_buffer_push(&cs->port);
547 }
548 EXPORT_SYMBOL_GPL(gigaset_if_receive);
549
550 /* gigaset_if_initdriver
551  * Initialize tty interface.
552  * parameters:
553  *      drv             Driver
554  *      procname        Name of the driver (e.g. for /proc/tty/drivers)
555  *      devname         Name of the device files (prefix without minor number)
556  */
557 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
558                            const char *devname)
559 {
560         int ret;
561         struct tty_driver *tty;
562
563         drv->have_tty = 0;
564
565         drv->tty = tty = alloc_tty_driver(drv->minors);
566         if (tty == NULL)
567                 goto enomem;
568
569         tty->type =             TTY_DRIVER_TYPE_SERIAL;
570         tty->subtype =          SERIAL_TYPE_NORMAL;
571         tty->flags =            TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
572
573         tty->driver_name =      procname;
574         tty->name =             devname;
575         tty->minor_start =      drv->minor;
576
577         tty->init_termios          = tty_std_termios;
578         tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
579         tty_set_operations(tty, &if_ops);
580
581         ret = tty_register_driver(tty);
582         if (ret < 0) {
583                 pr_err("error %d registering tty driver\n", ret);
584                 goto error;
585         }
586         gig_dbg(DEBUG_IF, "tty driver initialized");
587         drv->have_tty = 1;
588         return;
589
590 enomem:
591         pr_err("out of memory\n");
592 error:
593         if (drv->tty)
594                 put_tty_driver(drv->tty);
595 }
596
597 void gigaset_if_freedriver(struct gigaset_driver *drv)
598 {
599         if (!drv->have_tty)
600                 return;
601
602         drv->have_tty = 0;
603         tty_unregister_driver(drv->tty);
604         put_tty_driver(drv->tty);
605 }