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