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