TTY: remove re-assignments to tty_driver members
[linux-2.6.git] / 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 /* stolen from usbserial and some other tty drivers */
116
117 static int  if_open(struct tty_struct *tty, struct file *filp);
118 static void if_close(struct tty_struct *tty, struct file *filp);
119 static int  if_ioctl(struct tty_struct *tty,
120                      unsigned int cmd, unsigned long arg);
121 static int  if_write_room(struct tty_struct *tty);
122 static int  if_chars_in_buffer(struct tty_struct *tty);
123 static void if_throttle(struct tty_struct *tty);
124 static void if_unthrottle(struct tty_struct *tty);
125 static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
126 static int  if_tiocmget(struct tty_struct *tty);
127 static int  if_tiocmset(struct tty_struct *tty,
128                         unsigned int set, unsigned int clear);
129 static int  if_write(struct tty_struct *tty,
130                      const unsigned char *buf, int count);
131
132 static const struct tty_operations if_ops = {
133         .open =                 if_open,
134         .close =                if_close,
135         .ioctl =                if_ioctl,
136         .write =                if_write,
137         .write_room =           if_write_room,
138         .chars_in_buffer =      if_chars_in_buffer,
139         .set_termios =          if_set_termios,
140         .throttle =             if_throttle,
141         .unthrottle =           if_unthrottle,
142         .tiocmget =             if_tiocmget,
143         .tiocmset =             if_tiocmset,
144 };
145
146 static int if_open(struct tty_struct *tty, struct file *filp)
147 {
148         struct cardstate *cs;
149         unsigned long flags;
150
151         gig_dbg(DEBUG_IF, "%d+%d: %s()",
152                 tty->driver->minor_start, tty->index, __func__);
153
154         tty->driver_data = NULL;
155
156         cs = gigaset_get_cs_by_tty(tty);
157         if (!cs || !try_module_get(cs->driver->owner))
158                 return -ENODEV;
159
160         if (mutex_lock_interruptible(&cs->mutex)) {
161                 module_put(cs->driver->owner);
162                 return -ERESTARTSYS;
163         }
164         tty->driver_data = cs;
165
166         ++cs->open_count;
167
168         if (cs->open_count == 1) {
169                 spin_lock_irqsave(&cs->lock, flags);
170                 cs->tty = tty;
171                 spin_unlock_irqrestore(&cs->lock, flags);
172                 tty->low_latency = 1;
173         }
174
175         mutex_unlock(&cs->mutex);
176         return 0;
177 }
178
179 static void if_close(struct tty_struct *tty, struct file *filp)
180 {
181         struct cardstate *cs;
182         unsigned long flags;
183
184         cs = (struct cardstate *) tty->driver_data;
185         if (!cs) {
186                 pr_err("%s: no cardstate\n", __func__);
187                 return;
188         }
189
190         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
191
192         mutex_lock(&cs->mutex);
193
194         if (!cs->connected)
195                 gig_dbg(DEBUG_IF, "not connected");     /* nothing to do */
196         else if (!cs->open_count)
197                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
198         else {
199                 if (!--cs->open_count) {
200                         spin_lock_irqsave(&cs->lock, flags);
201                         cs->tty = NULL;
202                         spin_unlock_irqrestore(&cs->lock, flags);
203                 }
204         }
205
206         mutex_unlock(&cs->mutex);
207
208         module_put(cs->driver->owner);
209 }
210
211 static int if_ioctl(struct tty_struct *tty,
212                     unsigned int cmd, unsigned long arg)
213 {
214         struct cardstate *cs;
215         int retval = -ENODEV;
216         int int_arg;
217         unsigned char buf[6];
218         unsigned version[4];
219
220         cs = (struct cardstate *) tty->driver_data;
221         if (!cs) {
222                 pr_err("%s: no cardstate\n", __func__);
223                 return -ENODEV;
224         }
225
226         gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
227
228         if (mutex_lock_interruptible(&cs->mutex))
229                 return -ERESTARTSYS;
230
231         if (!cs->connected) {
232                 gig_dbg(DEBUG_IF, "not connected");
233                 retval = -ENODEV;
234         } else if (!cs->open_count)
235                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
236         else {
237                 retval = 0;
238                 switch (cmd) {
239                 case GIGASET_REDIR:
240                         retval = get_user(int_arg, (int __user *) arg);
241                         if (retval >= 0)
242                                 retval = if_lock(cs, &int_arg);
243                         if (retval >= 0)
244                                 retval = put_user(int_arg, (int __user *) arg);
245                         break;
246                 case GIGASET_CONFIG:
247                         retval = get_user(int_arg, (int __user *) arg);
248                         if (retval >= 0)
249                                 retval = if_config(cs, &int_arg);
250                         if (retval >= 0)
251                                 retval = put_user(int_arg, (int __user *) arg);
252                         break;
253                 case GIGASET_BRKCHARS:
254                         retval = copy_from_user(&buf,
255                                         (const unsigned char __user *) arg, 6)
256                                 ? -EFAULT : 0;
257                         if (retval >= 0) {
258                                 gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
259                                                 6, (const unsigned char *) arg);
260                                 retval = cs->ops->brkchars(cs, buf);
261                         }
262                         break;
263                 case GIGASET_VERSION:
264                         retval = copy_from_user(version,
265                                         (unsigned __user *) arg, sizeof version)
266                                 ? -EFAULT : 0;
267                         if (retval >= 0)
268                                 retval = if_version(cs, version);
269                         if (retval >= 0)
270                                 retval = copy_to_user((unsigned __user *) arg,
271                                                       version, sizeof version)
272                                         ? -EFAULT : 0;
273                         break;
274                 default:
275                         gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x",
276                                 __func__, cmd);
277                         retval = -ENOIOCTLCMD;
278                 }
279         }
280
281         mutex_unlock(&cs->mutex);
282
283         return retval;
284 }
285
286 static int if_tiocmget(struct tty_struct *tty)
287 {
288         struct cardstate *cs;
289         int retval;
290
291         cs = (struct cardstate *) tty->driver_data;
292         if (!cs) {
293                 pr_err("%s: no cardstate\n", __func__);
294                 return -ENODEV;
295         }
296
297         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
298
299         if (mutex_lock_interruptible(&cs->mutex))
300                 return -ERESTARTSYS;
301
302         retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
303
304         mutex_unlock(&cs->mutex);
305
306         return retval;
307 }
308
309 static int if_tiocmset(struct tty_struct *tty,
310                        unsigned int set, unsigned int clear)
311 {
312         struct cardstate *cs;
313         int retval;
314         unsigned mc;
315
316         cs = (struct cardstate *) tty->driver_data;
317         if (!cs) {
318                 pr_err("%s: no cardstate\n", __func__);
319                 return -ENODEV;
320         }
321
322         gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
323                 cs->minor_index, __func__, set, clear);
324
325         if (mutex_lock_interruptible(&cs->mutex))
326                 return -ERESTARTSYS;
327
328         if (!cs->connected) {
329                 gig_dbg(DEBUG_IF, "not connected");
330                 retval = -ENODEV;
331         } else {
332                 mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
333                 retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
334                 cs->control_state = mc;
335         }
336
337         mutex_unlock(&cs->mutex);
338
339         return retval;
340 }
341
342 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
343 {
344         struct cardstate *cs;
345         struct cmdbuf_t *cb;
346         int retval;
347
348         cs = (struct cardstate *) tty->driver_data;
349         if (!cs) {
350                 pr_err("%s: no cardstate\n", __func__);
351                 return -ENODEV;
352         }
353
354         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
355
356         if (mutex_lock_interruptible(&cs->mutex))
357                 return -ERESTARTSYS;
358
359         if (!cs->connected) {
360                 gig_dbg(DEBUG_IF, "not connected");
361                 retval = -ENODEV;
362                 goto done;
363         }
364         if (!cs->open_count) {
365                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
366                 retval = -ENODEV;
367                 goto done;
368         }
369         if (cs->mstate != MS_LOCKED) {
370                 dev_warn(cs->dev, "can't write to unlocked device\n");
371                 retval = -EBUSY;
372                 goto done;
373         }
374         if (count <= 0) {
375                 /* nothing to do */
376                 retval = 0;
377                 goto done;
378         }
379
380         cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL);
381         if (!cb) {
382                 dev_err(cs->dev, "%s: out of memory\n", __func__);
383                 retval = -ENOMEM;
384                 goto done;
385         }
386
387         memcpy(cb->buf, buf, count);
388         cb->len = count;
389         cb->offset = 0;
390         cb->next = NULL;
391         cb->wake_tasklet = &cs->if_wake_tasklet;
392         retval = cs->ops->write_cmd(cs, cb);
393 done:
394         mutex_unlock(&cs->mutex);
395         return retval;
396 }
397
398 static int if_write_room(struct tty_struct *tty)
399 {
400         struct cardstate *cs;
401         int retval = -ENODEV;
402
403         cs = (struct cardstate *) tty->driver_data;
404         if (!cs) {
405                 pr_err("%s: no cardstate\n", __func__);
406                 return -ENODEV;
407         }
408
409         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
410
411         if (mutex_lock_interruptible(&cs->mutex))
412                 return -ERESTARTSYS;
413
414         if (!cs->connected) {
415                 gig_dbg(DEBUG_IF, "not connected");
416                 retval = -ENODEV;
417         } else if (!cs->open_count)
418                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
419         else if (cs->mstate != MS_LOCKED) {
420                 dev_warn(cs->dev, "can't write to unlocked device\n");
421                 retval = -EBUSY;
422         } else
423                 retval = cs->ops->write_room(cs);
424
425         mutex_unlock(&cs->mutex);
426
427         return retval;
428 }
429
430 static int if_chars_in_buffer(struct tty_struct *tty)
431 {
432         struct cardstate *cs;
433         int retval = 0;
434
435         cs = (struct cardstate *) tty->driver_data;
436         if (!cs) {
437                 pr_err("%s: no cardstate\n", __func__);
438                 return 0;
439         }
440
441         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
442
443         mutex_lock(&cs->mutex);
444
445         if (!cs->connected)
446                 gig_dbg(DEBUG_IF, "not connected");
447         else if (!cs->open_count)
448                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
449         else if (cs->mstate != MS_LOCKED)
450                 dev_warn(cs->dev, "can't write to unlocked device\n");
451         else
452                 retval = cs->ops->chars_in_buffer(cs);
453
454         mutex_unlock(&cs->mutex);
455
456         return retval;
457 }
458
459 static void if_throttle(struct tty_struct *tty)
460 {
461         struct cardstate *cs;
462
463         cs = (struct cardstate *) tty->driver_data;
464         if (!cs) {
465                 pr_err("%s: no cardstate\n", __func__);
466                 return;
467         }
468
469         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
470
471         mutex_lock(&cs->mutex);
472
473         if (!cs->connected)
474                 gig_dbg(DEBUG_IF, "not connected");     /* nothing to do */
475         else if (!cs->open_count)
476                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
477         else
478                 gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
479
480         mutex_unlock(&cs->mutex);
481 }
482
483 static void if_unthrottle(struct tty_struct *tty)
484 {
485         struct cardstate *cs;
486
487         cs = (struct cardstate *) tty->driver_data;
488         if (!cs) {
489                 pr_err("%s: no cardstate\n", __func__);
490                 return;
491         }
492
493         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
494
495         mutex_lock(&cs->mutex);
496
497         if (!cs->connected)
498                 gig_dbg(DEBUG_IF, "not connected");     /* nothing to do */
499         else if (!cs->open_count)
500                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
501         else
502                 gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
503
504         mutex_unlock(&cs->mutex);
505 }
506
507 static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
508 {
509         struct cardstate *cs;
510         unsigned int iflag;
511         unsigned int cflag;
512         unsigned int old_cflag;
513         unsigned int control_state, new_state;
514
515         cs = (struct cardstate *) tty->driver_data;
516         if (!cs) {
517                 pr_err("%s: no cardstate\n", __func__);
518                 return;
519         }
520
521         gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
522
523         mutex_lock(&cs->mutex);
524
525         if (!cs->connected) {
526                 gig_dbg(DEBUG_IF, "not connected");
527                 goto out;
528         }
529
530         if (!cs->open_count) {
531                 dev_warn(cs->dev, "%s: device not opened\n", __func__);
532                 goto out;
533         }
534
535         iflag = tty->termios->c_iflag;
536         cflag = tty->termios->c_cflag;
537         old_cflag = old ? old->c_cflag : cflag;
538         gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
539                 cs->minor_index, iflag, cflag, old_cflag);
540
541         /* get a local copy of the current port settings */
542         control_state = cs->control_state;
543
544         /*
545          * Update baud rate.
546          * Do not attempt to cache old rates and skip settings,
547          * disconnects screw such tricks up completely.
548          * Premature optimization is the root of all evil.
549          */
550
551         /* reassert DTR and (maybe) RTS on transition from B0 */
552         if ((old_cflag & CBAUD) == B0) {
553                 new_state = control_state | TIOCM_DTR;
554                 /* don't set RTS if using hardware flow control */
555                 if (!(old_cflag & CRTSCTS))
556                         new_state |= TIOCM_RTS;
557                 gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
558                         cs->minor_index,
559                         (new_state & TIOCM_RTS) ? " only" : "/RTS");
560                 cs->ops->set_modem_ctrl(cs, control_state, new_state);
561                 control_state = new_state;
562         }
563
564         cs->ops->baud_rate(cs, cflag & CBAUD);
565
566         if ((cflag & CBAUD) == B0) {
567                 /* Drop RTS and DTR */
568                 gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
569                 new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
570                 cs->ops->set_modem_ctrl(cs, control_state, new_state);
571                 control_state = new_state;
572         }
573
574         /*
575          * Update line control register (LCR)
576          */
577
578         cs->ops->set_line_ctrl(cs, cflag);
579
580         /* save off the modified port settings */
581         cs->control_state = control_state;
582
583 out:
584         mutex_unlock(&cs->mutex);
585 }
586
587
588 /* wakeup tasklet for the write operation */
589 static void if_wake(unsigned long data)
590 {
591         struct cardstate *cs = (struct cardstate *) data;
592
593         if (cs->tty)
594                 tty_wakeup(cs->tty);
595 }
596
597 /*** interface to common ***/
598
599 void gigaset_if_init(struct cardstate *cs)
600 {
601         struct gigaset_driver *drv;
602
603         drv = cs->driver;
604         if (!drv->have_tty)
605                 return;
606
607         tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
608
609         mutex_lock(&cs->mutex);
610         cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
611
612         if (!IS_ERR(cs->tty_dev))
613                 dev_set_drvdata(cs->tty_dev, cs);
614         else {
615                 pr_warning("could not register device to the tty subsystem\n");
616                 cs->tty_dev = NULL;
617         }
618         mutex_unlock(&cs->mutex);
619 }
620
621 void gigaset_if_free(struct cardstate *cs)
622 {
623         struct gigaset_driver *drv;
624
625         drv = cs->driver;
626         if (!drv->have_tty)
627                 return;
628
629         tasklet_disable(&cs->if_wake_tasklet);
630         tasklet_kill(&cs->if_wake_tasklet);
631         cs->tty_dev = NULL;
632         tty_unregister_device(drv->tty, cs->minor_index);
633 }
634
635 /**
636  * gigaset_if_receive() - pass a received block of data to the tty device
637  * @cs:         device descriptor structure.
638  * @buffer:     received data.
639  * @len:        number of bytes received.
640  *
641  * Called by asyncdata/isocdata if a block of data received from the
642  * device must be sent to userspace through the ttyG* device.
643  */
644 void gigaset_if_receive(struct cardstate *cs,
645                         unsigned char *buffer, size_t len)
646 {
647         unsigned long flags;
648         struct tty_struct *tty;
649
650         spin_lock_irqsave(&cs->lock, flags);
651         tty = cs->tty;
652         if (tty == NULL)
653                 gig_dbg(DEBUG_IF, "receive on closed device");
654         else {
655                 tty_insert_flip_string(tty, buffer, len);
656                 tty_flip_buffer_push(tty);
657         }
658         spin_unlock_irqrestore(&cs->lock, flags);
659 }
660 EXPORT_SYMBOL_GPL(gigaset_if_receive);
661
662 /* gigaset_if_initdriver
663  * Initialize tty interface.
664  * parameters:
665  *      drv             Driver
666  *      procname        Name of the driver (e.g. for /proc/tty/drivers)
667  *      devname         Name of the device files (prefix without minor number)
668  */
669 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
670                            const char *devname)
671 {
672         int ret;
673         struct tty_driver *tty;
674
675         drv->have_tty = 0;
676
677         drv->tty = tty = alloc_tty_driver(drv->minors);
678         if (tty == NULL)
679                 goto enomem;
680
681         tty->type =             TTY_DRIVER_TYPE_SERIAL,
682         tty->subtype =          SERIAL_TYPE_NORMAL,
683         tty->flags =            TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
684
685         tty->driver_name =      procname;
686         tty->name =             devname;
687         tty->minor_start =      drv->minor;
688
689         tty->init_termios          = tty_std_termios;
690         tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
691         tty_set_operations(tty, &if_ops);
692
693         ret = tty_register_driver(tty);
694         if (ret < 0) {
695                 pr_err("error %d registering tty driver\n", ret);
696                 goto error;
697         }
698         gig_dbg(DEBUG_IF, "tty driver initialized");
699         drv->have_tty = 1;
700         return;
701
702 enomem:
703         pr_err("out of memory\n");
704 error:
705         if (drv->tty)
706                 put_tty_driver(drv->tty);
707 }
708
709 void gigaset_if_freedriver(struct gigaset_driver *drv)
710 {
711         if (!drv->have_tty)
712                 return;
713
714         drv->have_tty = 0;
715         tty_unregister_driver(drv->tty);
716         put_tty_driver(drv->tty);
717 }