1ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/*
2ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp * interface to user space for the gigaset driver
3ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp *
4ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
5ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp *
6ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp * =====================================================================
7ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp *    This program is free software; you can redistribute it and/or
8ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp *    modify it under the terms of the GNU General Public License as
9ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp *    published by the Free Software Foundation; either version 2 of
10ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp *    the License, or (at your option) any later version.
11ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp * =====================================================================
12ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp */
13ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
14ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp#include "gigaset.h"
15ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp#include <linux/gigaset_dev.h>
16ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp#include <linux/tty_flip.h>
1707a97fe8864a38cedd24a2c8c89cce8c3efd6095Paul Gortmaker#include <linux/module.h>
18ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
19ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/*** our ioctls ***/
20ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
21ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_lock(struct cardstate *cs, int *arg)
22ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
23ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int cmd = *arg;
24ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
25784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
26ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
27ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (cmd > 1)
28ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return -EINVAL;
29ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
30ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (cmd < 0) {
319d4bee2b9de9e30057a860d2d6794f874caffc5eTilman Schmidt		*arg = cs->mstate == MS_LOCKED;
32ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return 0;
33ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
34ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
359d4bee2b9de9e30057a860d2d6794f874caffc5eTilman Schmidt	if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
36475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR | TIOCM_RTS);
37ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->ops->baud_rate(cs, B115200);
38ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->ops->set_line_ctrl(cs, CS8);
39475be4d85a274d0961593db41cf85689db1d583cJoe Perches		cs->control_state = TIOCM_DTR | TIOCM_RTS;
40ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
41ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
42ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	cs->waiting = 1;
43ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
44784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt			       NULL, cmd, NULL)) {
45ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->waiting = 0;
46ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return -ENOMEM;
47ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
48ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	gigaset_schedule_event(cs);
49ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
50ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	wait_event(cs->waitqueue, !cs->waiting);
51ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
52ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (cs->cmd_result >= 0) {
53ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		*arg = cs->cmd_result;
54ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return 0;
55ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
56ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
57ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return cs->cmd_result;
58ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
59ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
60ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_version(struct cardstate *cs, unsigned arg[4])
61ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
62ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	static const unsigned version[4] = GIG_VERSION;
63ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	static const unsigned compat[4] = GIG_COMPAT;
64ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned cmd = arg[0];
65ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
66784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
67ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
68ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	switch (cmd) {
69ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	case GIGVER_DRIVER:
70ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		memcpy(arg, version, sizeof version);
71ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return 0;
72ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	case GIGVER_COMPAT:
73ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		memcpy(arg, compat, sizeof compat);
74ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return 0;
75ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	case GIGVER_FWBASE:
76ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->waiting = 1;
77ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
78784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt				       NULL, 0, arg)) {
79ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			cs->waiting = 0;
80ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			return -ENOMEM;
81ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		}
82ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		gigaset_schedule_event(cs);
83ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
84ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		wait_event(cs->waitqueue, !cs->waiting);
85ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
86ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		if (cs->cmd_result >= 0)
87ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			return 0;
88ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
89ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return cs->cmd_result;
90ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	default:
91ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return -EINVAL;
92ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
93ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
94ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
95ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_config(struct cardstate *cs, int *arg)
96ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
97784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
98ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
99ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (*arg != 1)
100ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return -EINVAL;
101ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
1029d4bee2b9de9e30057a860d2d6794f874caffc5eTilman Schmidt	if (cs->mstate != MS_LOCKED)
103ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return -EBUSY;
104ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
10569049cc87dccb1e6fb54aa25c63033efac805dbdTilman Schmidt	if (!cs->connected) {
106c8770dcabd6a615b155c25dc4d57251d3e7f151cTilman Schmidt		pr_err("%s: not connected\n", __func__);
10769049cc87dccb1e6fb54aa25c63033efac805dbdTilman Schmidt		return -ENODEV;
10869049cc87dccb1e6fb54aa25c63033efac805dbdTilman Schmidt	}
10969049cc87dccb1e6fb54aa25c63033efac805dbdTilman Schmidt
110ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	*arg = 0;
111ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return gigaset_enterconfigmode(cs);
112ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
113ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
114ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/*** the terminal driver ***/
115ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/* stolen from usbserial and some other tty drivers */
116ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
117ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int  if_open(struct tty_struct *tty, struct file *filp);
118ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_close(struct tty_struct *tty, struct file *filp);
1196caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int  if_ioctl(struct tty_struct *tty,
120784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		     unsigned int cmd, unsigned long arg);
121ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int  if_write_room(struct tty_struct *tty);
122ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int  if_chars_in_buffer(struct tty_struct *tty);
123ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_throttle(struct tty_struct *tty);
124ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_unthrottle(struct tty_struct *tty);
125606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void if_set_termios(struct tty_struct *tty, struct ktermios *old);
12660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int  if_tiocmget(struct tty_struct *tty);
12720b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int  if_tiocmset(struct tty_struct *tty,
128784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt			unsigned int set, unsigned int clear);
129ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int  if_write(struct tty_struct *tty,
130784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		     const unsigned char *buf, int count);
131ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
132b68e31d0ebbcc909d1941f9f230c9d062a3a13d3Jeff Dikestatic const struct tty_operations if_ops = {
133ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.open =			if_open,
134ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.close =		if_close,
135ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.ioctl =		if_ioctl,
136ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.write =		if_write,
137ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.write_room =		if_write_room,
138ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.chars_in_buffer =	if_chars_in_buffer,
139ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.set_termios =		if_set_termios,
140ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.throttle =		if_throttle,
141ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.unthrottle =		if_unthrottle,
142ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.tiocmget =		if_tiocmget,
143ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	.tiocmset =		if_tiocmset,
144ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp};
145ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
146ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_open(struct tty_struct *tty, struct file *filp)
147ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
148ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	struct cardstate *cs;
149ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
150784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%d+%d: %s()",
151784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		tty->driver->minor_start, tty->index, __func__);
152ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
153ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	cs = gigaset_get_cs_by_tty(tty);
154e468c04894f36045cf93d1384183a461014b6840Tilman Schmidt	if (!cs || !try_module_get(cs->driver->owner))
155ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return -ENODEV;
156ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
1572f9381e98471837b631743270de988e78aad1f96Pavel Shved	if (mutex_lock_interruptible(&cs->mutex)) {
1582f9381e98471837b631743270de988e78aad1f96Pavel Shved		module_put(cs->driver->owner);
159d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		return -ERESTARTSYS;
1602f9381e98471837b631743270de988e78aad1f96Pavel Shved	}
161ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty->driver_data = cs;
162ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
16348a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	++cs->port.count;
164ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
16548a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	if (cs->port.count == 1) {
16648a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby		tty_port_tty_set(&cs->port, tty);
167d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		tty->low_latency = 1;
168ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
169ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
170abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
171ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return 0;
172ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
173ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
174ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_close(struct tty_struct *tty, struct file *filp)
175ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
176fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
177ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
178fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	if (!cs) { /* happens if we didn't find cs in open */
179ef37ea34cac19ef46173b26ee47a102f3b987d1eTilman Schmidt		gig_dbg(DEBUG_IF, "%s: no cardstate", __func__);
180ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return;
181ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
182ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
183784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
184ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
185abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_lock(&cs->mutex);
186ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
18751370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected)
18851370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
18948a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	else if (!cs->port.count)
1905002779d37b261271da9883e06c14b097d4781c4Tilman Schmidt		dev_warn(cs->dev, "%s: device not opened\n", __func__);
19148a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	else if (!--cs->port.count)
19248a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby		tty_port_tty_set(&cs->port, NULL);
193ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
194abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
195e468c04894f36045cf93d1384183a461014b6840Tilman Schmidt
196e468c04894f36045cf93d1384183a461014b6840Tilman Schmidt	module_put(cs->driver->owner);
197ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
198ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
1996caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int if_ioctl(struct tty_struct *tty,
200784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		    unsigned int cmd, unsigned long arg)
201ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
202fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
203ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int retval = -ENODEV;
204ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int int_arg;
205ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned char buf[6];
206ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned version[4];
207ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
208784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
209ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
210abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	if (mutex_lock_interruptible(&cs->mutex))
211d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		return -ERESTARTSYS;
212ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
21351370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected) {
21451370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");
21551370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		retval = -ENODEV;
216fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	} else {
217ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		retval = 0;
218ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		switch (cmd) {
219ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		case GIGASET_REDIR:
220ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			retval = get_user(int_arg, (int __user *) arg);
221ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			if (retval >= 0)
222ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp				retval = if_lock(cs, &int_arg);
223ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			if (retval >= 0)
224ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp				retval = put_user(int_arg, (int __user *) arg);
225ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			break;
226ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		case GIGASET_CONFIG:
227ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			retval = get_user(int_arg, (int __user *) arg);
228ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			if (retval >= 0)
229ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp				retval = if_config(cs, &int_arg);
230ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			if (retval >= 0)
231ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp				retval = put_user(int_arg, (int __user *) arg);
232ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			break;
233ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		case GIGASET_BRKCHARS:
234ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			retval = copy_from_user(&buf,
235475be4d85a274d0961593db41cf85689db1d583cJoe Perches						(const unsigned char __user *) arg, 6)
236784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt				? -EFAULT : 0;
23701371500b245ae63f542d74140a3d8ccb74d0318Tilman Schmidt			if (retval >= 0) {
23801371500b245ae63f542d74140a3d8ccb74d0318Tilman Schmidt				gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
239475be4d85a274d0961593db41cf85689db1d583cJoe Perches						   6, (const unsigned char *) arg);
240ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp				retval = cs->ops->brkchars(cs, buf);
24101371500b245ae63f542d74140a3d8ccb74d0318Tilman Schmidt			}
242ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			break;
243ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		case GIGASET_VERSION:
244917f5085ddb3498033551e711fb22f48ddeb8378Tilman Schmidt			retval = copy_from_user(version,
245475be4d85a274d0961593db41cf85689db1d583cJoe Perches						(unsigned __user *) arg, sizeof version)
246784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt				? -EFAULT : 0;
247ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			if (retval >= 0)
248ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp				retval = if_version(cs, version);
249ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			if (retval >= 0)
250917f5085ddb3498033551e711fb22f48ddeb8378Tilman Schmidt				retval = copy_to_user((unsigned __user *) arg,
251784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt						      version, sizeof version)
252784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt					? -EFAULT : 0;
253ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			break;
254784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		default:
2551528b18f7ec2b907711f37667c68e10d9296c882Tilman Schmidt			gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x",
256784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt				__func__, cmd);
257ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			retval = -ENOIOCTLCMD;
258ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		}
259ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
260ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
261abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
262ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
263ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return retval;
264ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
265ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
26660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int if_tiocmget(struct tty_struct *tty)
267ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
268fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
269ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int retval;
270ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
271784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
272ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
273abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	if (mutex_lock_interruptible(&cs->mutex))
274d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		return -ERESTARTSYS;
275ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
276475be4d85a274d0961593db41cf85689db1d583cJoe Perches	retval = cs->control_state & (TIOCM_RTS | TIOCM_DTR);
277ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
278abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
279ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
280ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return retval;
281ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
282ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
28320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int if_tiocmset(struct tty_struct *tty,
284784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		       unsigned int set, unsigned int clear)
285ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
286fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
287ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int retval;
288ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned mc;
289ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
290784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
291784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		cs->minor_index, __func__, set, clear);
292ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
293abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	if (mutex_lock_interruptible(&cs->mutex))
294d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		return -ERESTARTSYS;
295ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
29669049cc87dccb1e6fb54aa25c63033efac805dbdTilman Schmidt	if (!cs->connected) {
29751370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");
298ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		retval = -ENODEV;
299ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	} else {
300475be4d85a274d0961593db41cf85689db1d583cJoe Perches		mc = (cs->control_state | set) & ~clear & (TIOCM_RTS | TIOCM_DTR);
301ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
302ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->control_state = mc;
303ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
304ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
305abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
306ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
307ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return retval;
308ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
309ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
310ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
311ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
312fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
313e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	struct cmdbuf_t *cb;
314e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	int retval;
315ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
316784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
317ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
318abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	if (mutex_lock_interruptible(&cs->mutex))
319d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		return -ERESTARTSYS;
320ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
32151370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected) {
32251370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");
32351370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		retval = -ENODEV;
324e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		goto done;
325e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	}
326e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	if (cs->mstate != MS_LOCKED) {
3275002779d37b261271da9883e06c14b097d4781c4Tilman Schmidt		dev_warn(cs->dev, "can't write to unlocked device\n");
328ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		retval = -EBUSY;
329e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		goto done;
330e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	}
331e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	if (count <= 0) {
332e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		/* nothing to do */
333e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		retval = 0;
334e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		goto done;
335ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
336ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
337e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL);
338e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	if (!cb) {
339e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		dev_err(cs->dev, "%s: out of memory\n", __func__);
340e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		retval = -ENOMEM;
341e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt		goto done;
342e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	}
343ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
344e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	memcpy(cb->buf, buf, count);
345e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	cb->len = count;
346e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	cb->offset = 0;
347e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	cb->next = NULL;
348e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	cb->wake_tasklet = &cs->if_wake_tasklet;
349e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	retval = cs->ops->write_cmd(cs, cb);
350e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidtdone:
351e3628dd176ba3ed329991ef042c29aae60617630Tilman Schmidt	mutex_unlock(&cs->mutex);
352ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return retval;
353ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
354ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
355ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_write_room(struct tty_struct *tty)
356ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
357fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
358ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int retval = -ENODEV;
359ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
360784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
361ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
362abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	if (mutex_lock_interruptible(&cs->mutex))
363d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt		return -ERESTARTSYS;
364ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
36551370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected) {
36651370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");
36751370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		retval = -ENODEV;
368fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	} else if (cs->mstate != MS_LOCKED) {
3695002779d37b261271da9883e06c14b097d4781c4Tilman Schmidt		dev_warn(cs->dev, "can't write to unlocked device\n");
3709d4bee2b9de9e30057a860d2d6794f874caffc5eTilman Schmidt		retval = -EBUSY;
371ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	} else
372ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		retval = cs->ops->write_room(cs);
373ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
374abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
375ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
376ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return retval;
377ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
378ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
379ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic int if_chars_in_buffer(struct tty_struct *tty)
380ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
381fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
382a4304f2d5a3823deea894026ec95e43b33912357Tilman Schmidt	int retval = 0;
383ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
384784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
385ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
386a4304f2d5a3823deea894026ec95e43b33912357Tilman Schmidt	mutex_lock(&cs->mutex);
387ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
388a4304f2d5a3823deea894026ec95e43b33912357Tilman Schmidt	if (!cs->connected)
38951370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");
390a4304f2d5a3823deea894026ec95e43b33912357Tilman Schmidt	else if (cs->mstate != MS_LOCKED)
3915002779d37b261271da9883e06c14b097d4781c4Tilman Schmidt		dev_warn(cs->dev, "can't write to unlocked device\n");
392a4304f2d5a3823deea894026ec95e43b33912357Tilman Schmidt	else
393ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		retval = cs->ops->chars_in_buffer(cs);
394ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
395abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
396ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
397ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return retval;
398ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
399ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
400ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_throttle(struct tty_struct *tty)
401ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
402fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
403ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
404784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
405ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
406abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_lock(&cs->mutex);
407ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
40851370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected)
40951370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
410d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt	else
4111528b18f7ec2b907711f37667c68e10d9296c882Tilman Schmidt		gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
412ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
413abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
414ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
415ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
416ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_unthrottle(struct tty_struct *tty)
417ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
418fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
419ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
420784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
421ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
422abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_lock(&cs->mutex);
423ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
42451370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected)
42551370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");	/* nothing to do */
426d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt	else
4271528b18f7ec2b907711f37667c68e10d9296c882Tilman Schmidt		gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__);
428ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
429abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
430ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
431ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
432606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxstatic void if_set_termios(struct tty_struct *tty, struct ktermios *old)
433ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
434fc258f89405f63b379324d1f8388ae4810297997Jiri Slaby	struct cardstate *cs = tty->driver_data;
435ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned int iflag;
436ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned int cflag;
437ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned int old_cflag;
438ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	unsigned int control_state, new_state;
439ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
440784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
441ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
442abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_lock(&cs->mutex);
443ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
44451370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt	if (!cs->connected) {
44551370e5b21c5825cff7482e1c38f4e7c5dab3e2bTilman Schmidt		gig_dbg(DEBUG_IF, "not connected");
446ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		goto out;
447ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
448ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
449ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	iflag = tty->termios->c_iflag;
450ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	cflag = tty->termios->c_cflag;
451d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt	old_cflag = old ? old->c_cflag : cflag;
452784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
453784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		cs->minor_index, iflag, cflag, old_cflag);
454ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
455ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	/* get a local copy of the current port settings */
456ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	control_state = cs->control_state;
457ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
458ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	/*
459ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 * Update baud rate.
460ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 * Do not attempt to cache old rates and skip settings,
461ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 * disconnects screw such tricks up completely.
462ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 * Premature optimization is the root of all evil.
463ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 */
464ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
465784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	/* reassert DTR and (maybe) RTS on transition from B0 */
466ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if ((old_cflag & CBAUD) == B0) {
467ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		new_state = control_state | TIOCM_DTR;
468ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		/* don't set RTS if using hardware flow control */
469ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		if (!(old_cflag & CRTSCTS))
470ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp			new_state |= TIOCM_RTS;
471784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
472784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt			cs->minor_index,
473784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt			(new_state & TIOCM_RTS) ? " only" : "/RTS");
474ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->ops->set_modem_ctrl(cs, control_state, new_state);
475ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		control_state = new_state;
476ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
477ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
478ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	cs->ops->baud_rate(cs, cflag & CBAUD);
479ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
480ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if ((cflag & CBAUD) == B0) {
481ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		/* Drop RTS and DTR */
482784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt		gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
483ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
484ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		cs->ops->set_modem_ctrl(cs, control_state, new_state);
485ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		control_state = new_state;
486ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
487ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
488ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	/*
489ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 * Update line control register (LCR)
490ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	 */
491ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
492ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	cs->ops->set_line_ctrl(cs, cflag);
493ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
494ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	/* save off the modified port settings */
495ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	cs->control_state = control_state;
496ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
497ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippout:
498abfd1dc7c18e4be89715071a524324c7b2515565Tilman Schmidt	mutex_unlock(&cs->mutex);
499ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
500ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
501ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
502ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/* wakeup tasklet for the write operation */
503ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippstatic void if_wake(unsigned long data)
504ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
50548a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	struct cardstate *cs = (struct cardstate *)data;
50648a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	struct tty_struct *tty = tty_port_tty_get(&cs->port);
507ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
50848a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	if (tty) {
50948a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby		tty_wakeup(tty);
51048a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby		tty_kref_put(tty);
51148a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	}
512ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
513ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
514ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/*** interface to common ***/
515ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
516ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippvoid gigaset_if_init(struct cardstate *cs)
517ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
518ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	struct gigaset_driver *drv;
519ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
520ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	drv = cs->driver;
521ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (!drv->have_tty)
522ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return;
523ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
5245452fee23eddb5ebb46f13aba50c8930c160e1daJoe Perches	tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
5257435f50e1261f569c660efb4ae52e8bc21a92cbdTilman Schmidt
5267435f50e1261f569c660efb4ae52e8bc21a92cbdTilman Schmidt	mutex_lock(&cs->mutex);
52701107d343076c34b9e1ce5d073292bd7f3097fdaGreg Kroah-Hartman	cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
5283dda4e373c7474cfe280f4270b70c1563f92a2a7Hansjoerg Lipp
52901107d343076c34b9e1ce5d073292bd7f3097fdaGreg Kroah-Hartman	if (!IS_ERR(cs->tty_dev))
53001107d343076c34b9e1ce5d073292bd7f3097fdaGreg Kroah-Hartman		dev_set_drvdata(cs->tty_dev, cs);
5313dda4e373c7474cfe280f4270b70c1563f92a2a7Hansjoerg Lipp	else {
53242e3d611158faa2d372ccfb1e17bfde13935de68Tilman Schmidt		pr_warning("could not register device to the tty subsystem\n");
53301107d343076c34b9e1ce5d073292bd7f3097fdaGreg Kroah-Hartman		cs->tty_dev = NULL;
5343dda4e373c7474cfe280f4270b70c1563f92a2a7Hansjoerg Lipp	}
5357435f50e1261f569c660efb4ae52e8bc21a92cbdTilman Schmidt	mutex_unlock(&cs->mutex);
536ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
537ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
538ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippvoid gigaset_if_free(struct cardstate *cs)
539ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
540ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	struct gigaset_driver *drv;
541ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
542ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	drv = cs->driver;
543ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (!drv->have_tty)
544ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return;
545ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
546ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tasklet_disable(&cs->if_wake_tasklet);
547ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tasklet_kill(&cs->if_wake_tasklet);
54801107d343076c34b9e1ce5d073292bd7f3097fdaGreg Kroah-Hartman	cs->tty_dev = NULL;
549ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty_unregister_device(drv->tty, cs->minor_index);
550ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
551ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
5521cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt/**
5531cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt * gigaset_if_receive() - pass a received block of data to the tty device
5541cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt * @cs:		device descriptor structure.
5551cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt * @buffer:	received data.
5561cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt * @len:	number of bytes received.
5571cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt *
5581cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt * Called by asyncdata/isocdata if a block of data received from the
5591cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt * device must be sent to userspace through the ttyG* device.
5601cec9727fbfd7baff2034796154be1a0297bceddTilman Schmidt */
561ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippvoid gigaset_if_receive(struct cardstate *cs,
562784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt			unsigned char *buffer, size_t len)
563ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
56448a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	struct tty_struct *tty = tty_port_tty_get(&cs->port);
565ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
56648a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	if (tty == NULL) {
5671528b18f7ec2b907711f37667c68e10d9296c882Tilman Schmidt		gig_dbg(DEBUG_IF, "receive on closed device");
56848a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby		return;
569ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
57048a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby
57148a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	tty_insert_flip_string(tty, buffer, len);
57248a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	tty_flip_buffer_push(tty);
57348a7466f4dd0104d87a6d8dd0f25027be89c8453Jiri Slaby	tty_kref_put(tty);
574ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
575ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg LippEXPORT_SYMBOL_GPL(gigaset_if_receive);
576ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
577ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp/* gigaset_if_initdriver
578ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp * Initialize tty interface.
579ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp * parameters:
580784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt *	drv		Driver
581784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt *	procname	Name of the driver (e.g. for /proc/tty/drivers)
582784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt *	devname		Name of the device files (prefix without minor number)
583ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp */
584ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippvoid gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
585f4eaa37017a5a68f67ef86729508022c13fb8e6dGreg Kroah-Hartman			   const char *devname)
586ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
587ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	int ret;
588ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	struct tty_driver *tty;
589ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
590ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	drv->have_tty = 0;
591ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
5922f16669d322e05171c9e1cfd94f402f7399bd2a3Jiri Slaby	drv->tty = tty = alloc_tty_driver(drv->minors);
593d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt	if (tty == NULL)
594ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		goto enomem;
595ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
5965bd49735db39c1c1360cb91b1f1e1c999d90eb94Joe Perches	tty->type =		TTY_DRIVER_TYPE_SERIAL;
5975bd49735db39c1c1360cb91b1f1e1c999d90eb94Joe Perches	tty->subtype =		SERIAL_TYPE_NORMAL;
598331b831983f9d706f4a40d08a996d5c2c7a6ea7bGreg Kroah-Hartman	tty->flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
599ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
600ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty->driver_name =	procname;
601ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty->name =		devname;
602ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty->minor_start =	drv->minor;
603ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
604d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt	tty->init_termios          = tty_std_termios;
605d9ba9c9125d89e246dc0a0702446528acceb6ddbTilman Schmidt	tty->init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
606ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty_set_operations(tty, &if_ops);
607ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
608ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	ret = tty_register_driver(tty);
609ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (ret < 0) {
610c8770dcabd6a615b155c25dc4d57251d3e7f151cTilman Schmidt		pr_err("error %d registering tty driver\n", ret);
611ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		goto error;
612ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	}
613784d5858aac58c06608def862d73ae9a32f5ee23Tilman Schmidt	gig_dbg(DEBUG_IF, "tty driver initialized");
614ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	drv->have_tty = 1;
615ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	return;
616ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
617ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippenomem:
618c8770dcabd6a615b155c25dc4d57251d3e7f151cTilman Schmidt	pr_err("out of memory\n");
619ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipperror:
620ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (drv->tty)
621ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		put_tty_driver(drv->tty);
622ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
623ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
624ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lippvoid gigaset_if_freedriver(struct gigaset_driver *drv)
625ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp{
626ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	if (!drv->have_tty)
627ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp		return;
628ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp
629ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	drv->have_tty = 0;
630ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	tty_unregister_driver(drv->tty);
631ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp	put_tty_driver(drv->tty);
632ee8a4b7f857fe7ba243e65c8925798cf8eda5ab0Hansjoerg Lipp}
633