blob: af195b07c191b6b02b09c57548f6477334672a92 [file] [log] [blame]
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -08001/*
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 * =====================================================================
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080012 */
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
21static int if_lock(struct cardstate *cs, int *arg)
22{
23 int cmd = *arg;
24
Tilman Schmidt784d5852006-04-10 22:55:04 -070025 gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080026
27 if (cmd > 1)
28 return -EINVAL;
29
30 if (cmd < 0) {
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080031 *arg = cs->mstate == MS_LOCKED;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080032 return 0;
33 }
34
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080035 if (!cmd && cs->mstate == MS_LOCKED && cs->connected) {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080036 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,
Tilman Schmidt784d5852006-04-10 22:55:04 -070044 NULL, cmd, NULL)) {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080045 cs->waiting = 0;
46 return -ENOMEM;
47 }
48
Tilman Schmidt784d5852006-04-10 22:55:04 -070049 gig_dbg(DEBUG_CMD, "scheduling IF_LOCK");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080050 gigaset_schedule_event(cs);
51
52 wait_event(cs->waitqueue, !cs->waiting);
53
54 if (cs->cmd_result >= 0) {
55 *arg = cs->cmd_result;
56 return 0;
57 }
58
59 return cs->cmd_result;
60}
61
62static int if_version(struct cardstate *cs, unsigned arg[4])
63{
64 static const unsigned version[4] = GIG_VERSION;
65 static const unsigned compat[4] = GIG_COMPAT;
66 unsigned cmd = arg[0];
67
Tilman Schmidt784d5852006-04-10 22:55:04 -070068 gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080069
70 switch (cmd) {
71 case GIGVER_DRIVER:
72 memcpy(arg, version, sizeof version);
73 return 0;
74 case GIGVER_COMPAT:
75 memcpy(arg, compat, sizeof compat);
76 return 0;
77 case GIGVER_FWBASE:
78 cs->waiting = 1;
79 if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
Tilman Schmidt784d5852006-04-10 22:55:04 -070080 NULL, 0, arg)) {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080081 cs->waiting = 0;
82 return -ENOMEM;
83 }
84
Tilman Schmidt784d5852006-04-10 22:55:04 -070085 gig_dbg(DEBUG_CMD, "scheduling IF_VER");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -080086 gigaset_schedule_event(cs);
87
88 wait_event(cs->waitqueue, !cs->waiting);
89
90 if (cs->cmd_result >= 0)
91 return 0;
92
93 return cs->cmd_result;
94 default:
95 return -EINVAL;
96 }
97}
98
99static int if_config(struct cardstate *cs, int *arg)
100{
Tilman Schmidt784d5852006-04-10 22:55:04 -0700101 gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800102
103 if (*arg != 1)
104 return -EINVAL;
105
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800106 if (cs->mstate != MS_LOCKED)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800107 return -EBUSY;
108
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700109 if (!cs->connected) {
110 err("not connected!");
111 return -ENODEV;
112 }
113
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800114 *arg = 0;
115 return gigaset_enterconfigmode(cs);
116}
117
118/*** the terminal driver ***/
119/* stolen from usbserial and some other tty drivers */
120
121static int if_open(struct tty_struct *tty, struct file *filp);
122static void if_close(struct tty_struct *tty, struct file *filp);
123static int if_ioctl(struct tty_struct *tty, struct file *file,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700124 unsigned int cmd, unsigned long arg);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800125static int if_write_room(struct tty_struct *tty);
126static int if_chars_in_buffer(struct tty_struct *tty);
127static void if_throttle(struct tty_struct *tty);
128static void if_unthrottle(struct tty_struct *tty);
Alan Cox606d0992006-12-08 02:38:45 -0800129static void if_set_termios(struct tty_struct *tty, struct ktermios *old);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800130static int if_tiocmget(struct tty_struct *tty, struct file *file);
131static int if_tiocmset(struct tty_struct *tty, struct file *file,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700132 unsigned int set, unsigned int clear);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800133static int if_write(struct tty_struct *tty,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700134 const unsigned char *buf, int count);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800135
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700136static const struct tty_operations if_ops = {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800137 .open = if_open,
138 .close = if_close,
139 .ioctl = if_ioctl,
140 .write = if_write,
141 .write_room = if_write_room,
142 .chars_in_buffer = if_chars_in_buffer,
143 .set_termios = if_set_termios,
144 .throttle = if_throttle,
145 .unthrottle = if_unthrottle,
146#if 0
147 .break_ctl = serial_break,
148#endif
149 .tiocmget = if_tiocmget,
150 .tiocmset = if_tiocmset,
151};
152
153static int if_open(struct tty_struct *tty, struct file *filp)
154{
155 struct cardstate *cs;
156 unsigned long flags;
157
Tilman Schmidt784d5852006-04-10 22:55:04 -0700158 gig_dbg(DEBUG_IF, "%d+%d: %s()",
159 tty->driver->minor_start, tty->index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800160
161 tty->driver_data = NULL;
162
163 cs = gigaset_get_cs_by_tty(tty);
Tilman Schmidte468c042008-02-06 01:38:29 -0800164 if (!cs || !try_module_get(cs->driver->owner))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800165 return -ENODEV;
166
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700167 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800168 return -ERESTARTSYS; // FIXME -EINTR?
169 tty->driver_data = cs;
170
171 ++cs->open_count;
172
173 if (cs->open_count == 1) {
174 spin_lock_irqsave(&cs->lock, flags);
175 cs->tty = tty;
176 spin_unlock_irqrestore(&cs->lock, flags);
177 tty->low_latency = 1; //FIXME test
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800178 }
179
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700180 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800181 return 0;
182}
183
184static void if_close(struct tty_struct *tty, struct file *filp)
185{
186 struct cardstate *cs;
187 unsigned long flags;
188
189 cs = (struct cardstate *) tty->driver_data;
190 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700191 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800192 return;
193 }
194
Tilman Schmidt784d5852006-04-10 22:55:04 -0700195 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800196
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700197 mutex_lock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800198
199 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700200 warn("%s: device not opened", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800201 else {
202 if (!--cs->open_count) {
203 spin_lock_irqsave(&cs->lock, flags);
204 cs->tty = NULL;
205 spin_unlock_irqrestore(&cs->lock, flags);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800206 }
207 }
208
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700209 mutex_unlock(&cs->mutex);
Tilman Schmidte468c042008-02-06 01:38:29 -0800210
211 module_put(cs->driver->owner);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800212}
213
214static int if_ioctl(struct tty_struct *tty, struct file *file,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700215 unsigned int cmd, unsigned long arg)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800216{
217 struct cardstate *cs;
218 int retval = -ENODEV;
219 int int_arg;
220 unsigned char buf[6];
221 unsigned version[4];
222
223 cs = (struct cardstate *) tty->driver_data;
224 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700225 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800226 return -ENODEV;
227 }
228
Tilman Schmidt784d5852006-04-10 22:55:04 -0700229 gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800230
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700231 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800232 return -ERESTARTSYS; // FIXME -EINTR?
233
234 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700235 warn("%s: device not opened", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800236 else {
237 retval = 0;
238 switch (cmd) {
239 case GIGASET_REDIR:
240 retval = get_user(int_arg, (int __user *) arg);
241 if (retval >= 0)
242 retval = if_lock(cs, &int_arg);
243 if (retval >= 0)
244 retval = put_user(int_arg, (int __user *) arg);
245 break;
246 case GIGASET_CONFIG:
247 retval = get_user(int_arg, (int __user *) arg);
248 if (retval >= 0)
249 retval = if_config(cs, &int_arg);
250 if (retval >= 0)
251 retval = put_user(int_arg, (int __user *) arg);
252 break;
253 case GIGASET_BRKCHARS:
254 //FIXME test if MS_LOCKED
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700255 if (!cs->connected) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700256 gig_dbg(DEBUG_ANY,
Tilman Schmidt917f5082006-04-10 22:55:00 -0700257 "can't communicate with unplugged device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800258 retval = -ENODEV;
259 break;
260 }
261 retval = copy_from_user(&buf,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700262 (const unsigned char __user *) arg, 6)
263 ? -EFAULT : 0;
Tilman Schmidt01371502006-04-10 22:55:11 -0700264 if (retval >= 0) {
265 gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
266 6, (const unsigned char *) arg);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800267 retval = cs->ops->brkchars(cs, buf);
Tilman Schmidt01371502006-04-10 22:55:11 -0700268 }
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800269 break;
270 case GIGASET_VERSION:
Tilman Schmidt917f5082006-04-10 22:55:00 -0700271 retval = copy_from_user(version,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700272 (unsigned __user *) arg, sizeof version)
273 ? -EFAULT : 0;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800274 if (retval >= 0)
275 retval = if_version(cs, version);
276 if (retval >= 0)
Tilman Schmidt917f5082006-04-10 22:55:00 -0700277 retval = copy_to_user((unsigned __user *) arg,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700278 version, sizeof version)
279 ? -EFAULT : 0;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800280 break;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700281 default:
282 gig_dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
283 __func__, cmd);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800284 retval = -ENOIOCTLCMD;
285 }
286 }
287
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700288 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800289
290 return retval;
291}
292
293static int if_tiocmget(struct tty_struct *tty, struct file *file)
294{
295 struct cardstate *cs;
296 int retval;
297
298 cs = (struct cardstate *) tty->driver_data;
299 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700300 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800301 return -ENODEV;
302 }
303
Tilman Schmidt784d5852006-04-10 22:55:04 -0700304 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800305
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700306 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800307 return -ERESTARTSYS; // FIXME -EINTR?
308
309 // FIXME read from device?
310 retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
311
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700312 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800313
314 return retval;
315}
316
317static int if_tiocmset(struct tty_struct *tty, struct file *file,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700318 unsigned int set, unsigned int clear)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800319{
320 struct cardstate *cs;
321 int retval;
322 unsigned mc;
323
324 cs = (struct cardstate *) tty->driver_data;
325 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700326 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800327 return -ENODEV;
328 }
329
Tilman Schmidt784d5852006-04-10 22:55:04 -0700330 gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)",
331 cs->minor_index, __func__, set, clear);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800332
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700333 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800334 return -ERESTARTSYS; // FIXME -EINTR?
335
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700336 if (!cs->connected) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700337 gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800338 retval = -ENODEV;
339 } else {
340 mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
341 retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
342 cs->control_state = mc;
343 }
344
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700345 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800346
347 return retval;
348}
349
350static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
351{
352 struct cardstate *cs;
353 int retval = -ENODEV;
354
355 cs = (struct cardstate *) tty->driver_data;
356 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700357 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800358 return -ENODEV;
359 }
360
Tilman Schmidt784d5852006-04-10 22:55:04 -0700361 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800362
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700363 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800364 return -ERESTARTSYS; // FIXME -EINTR?
365
366 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700367 warn("%s: device not opened", __func__);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800368 else if (cs->mstate != MS_LOCKED) {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800369 warn("can't write to unlocked device");
370 retval = -EBUSY;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700371 } else if (!cs->connected) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700372 gig_dbg(DEBUG_ANY, "can't write to unplugged device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800373 retval = -EBUSY; //FIXME
374 } else {
375 retval = cs->ops->write_cmd(cs, buf, count,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700376 &cs->if_wake_tasklet);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800377 }
378
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700379 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800380
381 return retval;
382}
383
384static int if_write_room(struct tty_struct *tty)
385{
386 struct cardstate *cs;
387 int retval = -ENODEV;
388
389 cs = (struct cardstate *) tty->driver_data;
390 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700391 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800392 return -ENODEV;
393 }
394
Tilman Schmidt784d5852006-04-10 22:55:04 -0700395 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800396
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700397 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800398 return -ERESTARTSYS; // FIXME -EINTR?
399
400 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700401 warn("%s: device not opened", __func__);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800402 else if (cs->mstate != MS_LOCKED) {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800403 warn("can't write to unlocked device");
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800404 retval = -EBUSY;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700405 } else if (!cs->connected) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700406 gig_dbg(DEBUG_ANY, "can't write to unplugged device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800407 retval = -EBUSY; //FIXME
408 } else
409 retval = cs->ops->write_room(cs);
410
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700411 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800412
413 return retval;
414}
415
416static int if_chars_in_buffer(struct tty_struct *tty)
417{
418 struct cardstate *cs;
419 int retval = -ENODEV;
420
421 cs = (struct cardstate *) tty->driver_data;
422 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700423 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800424 return -ENODEV;
425 }
426
Tilman Schmidt784d5852006-04-10 22:55:04 -0700427 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800428
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700429 if (mutex_lock_interruptible(&cs->mutex))
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800430 return -ERESTARTSYS; // FIXME -EINTR?
431
432 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700433 warn("%s: device not opened", __func__);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800434 else if (cs->mstate != MS_LOCKED) {
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800435 warn("can't write to unlocked device");
436 retval = -EBUSY;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700437 } else if (!cs->connected) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700438 gig_dbg(DEBUG_ANY, "can't write to unplugged device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800439 retval = -EBUSY; //FIXME
440 } else
441 retval = cs->ops->chars_in_buffer(cs);
442
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700443 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800444
445 return retval;
446}
447
448static void if_throttle(struct tty_struct *tty)
449{
450 struct cardstate *cs;
451
452 cs = (struct cardstate *) tty->driver_data;
453 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700454 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800455 return;
456 }
457
Tilman Schmidt784d5852006-04-10 22:55:04 -0700458 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800459
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700460 mutex_lock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800461
462 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700463 warn("%s: device not opened", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800464 else {
465 //FIXME
466 }
467
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700468 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800469}
470
471static void if_unthrottle(struct tty_struct *tty)
472{
473 struct cardstate *cs;
474
475 cs = (struct cardstate *) tty->driver_data;
476 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700477 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800478 return;
479 }
480
Tilman Schmidt784d5852006-04-10 22:55:04 -0700481 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800482
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700483 mutex_lock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800484
485 if (!cs->open_count)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700486 warn("%s: device not opened", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800487 else {
488 //FIXME
489 }
490
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700491 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800492}
493
Alan Cox606d0992006-12-08 02:38:45 -0800494static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800495{
496 struct cardstate *cs;
497 unsigned int iflag;
498 unsigned int cflag;
499 unsigned int old_cflag;
500 unsigned int control_state, new_state;
501
502 cs = (struct cardstate *) tty->driver_data;
503 if (!cs) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700504 err("cs==NULL in %s", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800505 return;
506 }
507
Tilman Schmidt784d5852006-04-10 22:55:04 -0700508 gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800509
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700510 mutex_lock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800511
512 if (!cs->open_count) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700513 warn("%s: device not opened", __func__);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800514 goto out;
515 }
516
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700517 if (!cs->connected) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700518 gig_dbg(DEBUG_ANY, "can't communicate with unplugged device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800519 goto out;
520 }
521
522 // stolen from mct_u232.c
523 iflag = tty->termios->c_iflag;
524 cflag = tty->termios->c_cflag;
525 old_cflag = old ? old->c_cflag : cflag; //FIXME?
Tilman Schmidt784d5852006-04-10 22:55:04 -0700526 gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
527 cs->minor_index, iflag, cflag, old_cflag);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800528
529 /* get a local copy of the current port settings */
530 control_state = cs->control_state;
531
532 /*
533 * Update baud rate.
534 * Do not attempt to cache old rates and skip settings,
535 * disconnects screw such tricks up completely.
536 * Premature optimization is the root of all evil.
537 */
538
Tilman Schmidt784d5852006-04-10 22:55:04 -0700539 /* reassert DTR and (maybe) RTS on transition from B0 */
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800540 if ((old_cflag & CBAUD) == B0) {
541 new_state = control_state | TIOCM_DTR;
542 /* don't set RTS if using hardware flow control */
543 if (!(old_cflag & CRTSCTS))
544 new_state |= TIOCM_RTS;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700545 gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s",
546 cs->minor_index,
547 (new_state & TIOCM_RTS) ? " only" : "/RTS");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800548 cs->ops->set_modem_ctrl(cs, control_state, new_state);
549 control_state = new_state;
550 }
551
552 cs->ops->baud_rate(cs, cflag & CBAUD);
553
554 if ((cflag & CBAUD) == B0) {
555 /* Drop RTS and DTR */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700556 gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800557 new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
558 cs->ops->set_modem_ctrl(cs, control_state, new_state);
559 control_state = new_state;
560 }
561
562 /*
563 * Update line control register (LCR)
564 */
565
566 cs->ops->set_line_ctrl(cs, cflag);
567
568#if 0
569 //FIXME this hangs M101 [ts 2005-03-09]
570 //FIXME do we need this?
571 /*
572 * Set flow control: well, I do not really now how to handle DTR/RTS.
573 * Just do what we have seen with SniffUSB on Win98.
574 */
575 /* Drop DTR/RTS if no flow control otherwise assert */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700576 gig_dbg(DEBUG_IF, "%u: control_state %x",
577 cs->minor_index, control_state);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800578 new_state = control_state;
579 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
580 new_state |= TIOCM_DTR | TIOCM_RTS;
581 else
582 new_state &= ~(TIOCM_DTR | TIOCM_RTS);
583 if (new_state != control_state) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700584 gig_dbg(DEBUG_IF, "%u: new_state %x",
585 cs->minor_index, new_state);
Tilman Schmidt917f5082006-04-10 22:55:00 -0700586 gigaset_set_modem_ctrl(cs, control_state, new_state);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800587 control_state = new_state;
588 }
589#endif
590
591 /* save off the modified port settings */
592 cs->control_state = control_state;
593
594out:
Tilman Schmidtabfd1dc2006-04-10 22:55:12 -0700595 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800596}
597
598
599/* wakeup tasklet for the write operation */
600static void if_wake(unsigned long data)
601{
602 struct cardstate *cs = (struct cardstate *) data;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800603
Jiri Slabyb963a842007-02-10 01:44:55 -0800604 if (cs->tty)
605 tty_wakeup(cs->tty);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800606}
607
608/*** interface to common ***/
609
610void gigaset_if_init(struct cardstate *cs)
611{
612 struct gigaset_driver *drv;
613
614 drv = cs->driver;
615 if (!drv->have_tty)
616 return;
617
618 tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
Tilman Schmidt7435f502007-02-12 00:52:24 -0800619
620 mutex_lock(&cs->mutex);
Greg Kroah-Hartman01107d32006-08-07 22:19:37 -0700621 cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
Hansjoerg Lipp3dda4e32006-04-22 18:43:00 +0200622
Greg Kroah-Hartman01107d32006-08-07 22:19:37 -0700623 if (!IS_ERR(cs->tty_dev))
624 dev_set_drvdata(cs->tty_dev, cs);
Hansjoerg Lipp3dda4e32006-04-22 18:43:00 +0200625 else {
626 warn("could not register device to the tty subsystem");
Greg Kroah-Hartman01107d32006-08-07 22:19:37 -0700627 cs->tty_dev = NULL;
Hansjoerg Lipp3dda4e32006-04-22 18:43:00 +0200628 }
Tilman Schmidt7435f502007-02-12 00:52:24 -0800629 mutex_unlock(&cs->mutex);
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800630}
631
632void gigaset_if_free(struct cardstate *cs)
633{
634 struct gigaset_driver *drv;
635
636 drv = cs->driver;
637 if (!drv->have_tty)
638 return;
639
640 tasklet_disable(&cs->if_wake_tasklet);
641 tasklet_kill(&cs->if_wake_tasklet);
Greg Kroah-Hartman01107d32006-08-07 22:19:37 -0700642 cs->tty_dev = NULL;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800643 tty_unregister_device(drv->tty, cs->minor_index);
644}
645
646void gigaset_if_receive(struct cardstate *cs,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700647 unsigned char *buffer, size_t len)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800648{
649 unsigned long flags;
650 struct tty_struct *tty;
651
652 spin_lock_irqsave(&cs->lock, flags);
653 if ((tty = cs->tty) == NULL)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700654 gig_dbg(DEBUG_ANY, "receive on closed device");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800655 else {
656 tty_buffer_request_room(tty, len);
657 tty_insert_flip_string(tty, buffer, len);
658 tty_flip_buffer_push(tty);
659 }
660 spin_unlock_irqrestore(&cs->lock, flags);
661}
662EXPORT_SYMBOL_GPL(gigaset_if_receive);
663
664/* gigaset_if_initdriver
665 * Initialize tty interface.
666 * parameters:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700667 * drv Driver
668 * procname Name of the driver (e.g. for /proc/tty/drivers)
669 * devname Name of the device files (prefix without minor number)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800670 */
671void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
Greg Kroah-Hartmanf4eaa372005-06-20 21:15:16 -0700672 const char *devname)
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800673{
674 unsigned minors = drv->minors;
675 int ret;
676 struct tty_driver *tty;
677
678 drv->have_tty = 0;
679
680 if ((drv->tty = alloc_tty_driver(minors)) == NULL)
681 goto enomem;
682 tty = drv->tty;
683
684 tty->magic = TTY_DRIVER_MAGIC,
685 tty->major = GIG_MAJOR,
686 tty->type = TTY_DRIVER_TYPE_SERIAL,
687 tty->subtype = SERIAL_TYPE_NORMAL,
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -0700688 tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800689
690 tty->driver_name = procname;
691 tty->name = devname;
692 tty->minor_start = drv->minor;
693 tty->num = drv->minors;
694
695 tty->owner = THIS_MODULE;
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800696
697 tty->init_termios = tty_std_termios; //FIXME
698 tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
699 tty_set_operations(tty, &if_ops);
700
701 ret = tty_register_driver(tty);
702 if (ret < 0) {
703 warn("failed to register tty driver (error %d)", ret);
704 goto error;
705 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700706 gig_dbg(DEBUG_IF, "tty driver initialized");
Hansjoerg Lippee8a4b72006-03-26 01:38:32 -0800707 drv->have_tty = 1;
708 return;
709
710enomem:
711 warn("could not allocate tty structures");
712error:
713 if (drv->tty)
714 put_tty_driver(drv->tty);
715}
716
717void gigaset_if_freedriver(struct gigaset_driver *drv)
718{
719 if (!drv->have_tty)
720 return;
721
722 drv->have_tty = 0;
723 tty_unregister_driver(drv->tty);
724 put_tty_driver(drv->tty);
725}