blob: 39a6e0191434287f20896103f637b2399a1981de [file] [log] [blame]
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +08001/*
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +08002 * UART driver for the Greybus "generic" UART module.
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +08003 *
4 * Copyright 2014 Google Inc.
5 *
6 * Released under the GPLv2 only.
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +08007 *
8 * Heavily based on drivers/usb/class/cdc-acm.c and
9 * drivers/usb/serial/usb-serial.c.
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080010 */
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -070011#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080012
13#include <linux/kernel.h>
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080014#include <linux/errno.h>
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080015#include <linux/module.h>
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080016#include <linux/sched.h>
17#include <linux/wait.h>
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080018#include <linux/slab.h>
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080019#include <linux/uaccess.h>
20#include <linux/mutex.h>
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080021#include <linux/tty.h>
22#include <linux/serial.h>
23#include <linux/tty_driver.h>
24#include <linux/tty_flip.h>
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080025#include <linux/serial.h>
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +080026#include <linux/idr.h>
Marti Bolivar7fabc882014-09-05 23:56:10 -040027#include <linux/fs.h>
28#include <linux/kdev_t.h>
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080029#include "greybus.h"
30
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +080031#define GB_NUM_MINORS 255 /* 255 is enough for anyone... */
Marti Bolivar7fabc882014-09-05 23:56:10 -040032#define GB_NAME "ttyGB"
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080033
34struct gb_tty {
35 struct tty_port port;
36 struct greybus_device *gdev;
37 int cport;
38 unsigned int minor;
39 unsigned char clocal;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +080040 unsigned int throttled:1;
41 unsigned int throttle_req:1;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080042 bool disconnected;
43 int writesize; // FIXME - set this somehow.
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +080044 spinlock_t read_lock;
45 spinlock_t write_lock;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080046 struct async_icount iocount;
47 struct async_icount oldcount;
48 wait_queue_head_t wioctl;
49 struct mutex mutex;
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080050};
51
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -070052static const struct greybus_module_id id_table[] = {
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +080053 { GREYBUS_DEVICE(0x45, 0x45) }, /* make shit up */
54 { }, /* terminating NULL entry */
55};
56
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +080057static struct tty_driver *gb_tty_driver;
58static DEFINE_IDR(tty_minors);
59static DEFINE_MUTEX(table_lock);
60
61static struct gb_tty *get_gb_by_minor(unsigned minor)
62{
63 struct gb_tty *gb_tty;
64
65 mutex_lock(&table_lock);
66 gb_tty = idr_find(&tty_minors, minor);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +080067 if (gb_tty) {
68 mutex_lock(&gb_tty->mutex);
69 if (gb_tty->disconnected) {
70 mutex_unlock(&gb_tty->mutex);
71 gb_tty = NULL;
72 } else {
73 tty_port_get(&gb_tty->port);
74 mutex_unlock(&gb_tty->mutex);
75 }
76 }
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +080077 mutex_unlock(&table_lock);
78 return gb_tty;
79}
80
81static int alloc_minor(struct gb_tty *gb_tty)
82{
83 int minor;
84
85 mutex_lock(&table_lock);
Alex Elderff5f0b32014-08-18 18:25:11 -050086 minor = idr_alloc(&tty_minors, gb_tty, 0, GB_NUM_MINORS, GFP_KERNEL);
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +080087 mutex_unlock(&table_lock);
Alex Elderff5f0b32014-08-18 18:25:11 -050088 if (minor >= 0)
89 gb_tty->minor = minor;
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +080090 return minor;
91}
92
93static void release_minor(struct gb_tty *gb_tty)
94{
Alex Elderff5f0b32014-08-18 18:25:11 -050095 int minor = gb_tty->minor;
96
97 gb_tty->minor = 0; /* Maybe should use an invalid value instead */
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +080098 mutex_lock(&table_lock);
Alex Elderff5f0b32014-08-18 18:25:11 -050099 idr_remove(&tty_minors, minor);
Greg Kroah-Hartmanff45c262014-08-15 18:33:33 +0800100 mutex_unlock(&table_lock);
101}
102
103static int gb_tty_install(struct tty_driver *driver, struct tty_struct *tty)
104{
105 struct gb_tty *gb_tty;
106 int retval;
107
108 gb_tty = get_gb_by_minor(tty->index);
109 if (!gb_tty)
110 return -ENODEV;
111
112 retval = tty_standard_install(driver, tty);
113 if (retval)
114 goto error;
115
116 tty->driver_data = gb_tty;
117 return 0;
118error:
119 tty_port_put(&gb_tty->port);
120 return retval;
121}
122
123static int gb_tty_open(struct tty_struct *tty, struct file *file)
124{
125 struct gb_tty *gb_tty = tty->driver_data;
126
127 return tty_port_open(&gb_tty->port, tty, file);
128}
129
130static void gb_tty_close(struct tty_struct *tty, struct file *file)
131{
132 struct gb_tty *gb_tty = tty->driver_data;
133
134 tty_port_close(&gb_tty->port, tty, file);
135}
136
137static void gb_tty_cleanup(struct tty_struct *tty)
138{
139 struct gb_tty *gb_tty = tty->driver_data;
140
141 tty_port_put(&gb_tty->port);
142}
143
144static void gb_tty_hangup(struct tty_struct *tty)
145{
146 struct gb_tty *gb_tty = tty->driver_data;
147
148 tty_port_hangup(&gb_tty->port);
149}
150
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800151static int gb_tty_write(struct tty_struct *tty, const unsigned char *buf,
152 int count)
153{
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800154// struct gb_tty *gb_tty = tty->driver_data;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800155
156 // FIXME - actually implement...
157
158 return 0;
159}
160
161static int gb_tty_write_room(struct tty_struct *tty)
162{
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800163// struct gb_tty *gb_tty = tty->driver_data;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800164
165 // FIXME - how much do we want to say we have room for?
166 return 0;
167}
168
169static int gb_tty_chars_in_buffer(struct tty_struct *tty)
170{
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800171// struct gb_tty *gb_tty = tty->driver_data;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800172
173 // FIXME - how many left to send?
174 return 0;
175}
176
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800177static int gb_tty_break_ctl(struct tty_struct *tty, int state)
178{
179// struct gb_tty *gb_tty = tty->driver_data;
180
181 // FIXME - send a break, if asked to...
182 return 0;
183}
184
185static void gb_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
186{
187 // FIXME - is this it???
188 tty_termios_copy_hw(&tty->termios, old);
189}
190
191static int gb_tty_tiocmget(struct tty_struct *tty)
192{
193// struct gb_tty *gb_tty = tty->driver_data;
194
195 // FIXME - get some tiocms!
196 return 0;
197}
198
199static int gb_tty_tiocmset(struct tty_struct *tty, unsigned int set,
200 unsigned int clear)
201{
202// struct gb_tty *gb_tty = tty->driver_data;
203
204 // FIXME - set some tiocms!
205 return 0;
206}
207
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800208static void gb_tty_throttle(struct tty_struct *tty)
209{
210 struct gb_tty *gb_tty = tty->driver_data;
211
212 spin_lock_irq(&gb_tty->read_lock);
213 gb_tty->throttle_req = 1;
214 spin_unlock_irq(&gb_tty->read_lock);
215}
216
217static void gb_tty_unthrottle(struct tty_struct *tty)
218{
219 struct gb_tty *gb_tty = tty->driver_data;
220 unsigned int was_throttled;
221
222 spin_lock_irq(&gb_tty->read_lock);
223 was_throttled = gb_tty->throttled;
224 gb_tty->throttle_req = 0;
225 gb_tty->throttled = 0;
226 spin_unlock_irq(&gb_tty->read_lock);
227
228 if (was_throttled) {
229 // FIXME - send more data
230 }
231}
232
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800233static int get_serial_info(struct gb_tty *gb_tty,
234 struct serial_struct __user *info)
235{
236 struct serial_struct tmp;
237
238 if (!info)
239 return -EINVAL;
240
241 memset(&tmp, 0, sizeof(tmp));
242 tmp.flags = ASYNC_LOW_LATENCY;
243 tmp.xmit_fifo_size = gb_tty->writesize;
244 tmp.baud_base = 0; // FIXME
245 tmp.close_delay = gb_tty->port.close_delay / 10;
246 tmp.closing_wait = gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
247 ASYNC_CLOSING_WAIT_NONE : gb_tty->port.closing_wait / 10;
248
249 if (copy_to_user(info, &tmp, sizeof(tmp)))
250 return -EFAULT;
Greg Kroah-Hartman3be03d42014-09-01 19:10:06 -0700251 return 0;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800252}
253
254static int set_serial_info(struct gb_tty *gb_tty,
255 struct serial_struct __user *newinfo)
256{
257 struct serial_struct new_serial;
258 unsigned int closing_wait;
259 unsigned int close_delay;
260 int retval;
261
262 if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
263 return -EFAULT;
264
265 close_delay = new_serial.close_delay * 10;
266 closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
267 ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10;
268
269 mutex_lock(&gb_tty->port.mutex);
270 if (!capable(CAP_SYS_ADMIN)) {
271 if ((close_delay != gb_tty->port.close_delay) ||
272 (closing_wait != gb_tty->port.closing_wait))
273 retval = -EPERM;
274 else
275 retval = -EOPNOTSUPP;
276 } else {
277 gb_tty->port.close_delay = close_delay;
278 gb_tty->port.closing_wait = closing_wait;
279 }
280 mutex_unlock(&gb_tty->port.mutex);
281 return retval;
282}
283
284static int wait_serial_change(struct gb_tty *gb_tty, unsigned long arg)
285{
286 int retval = 0;
287 DECLARE_WAITQUEUE(wait, current);
288 struct async_icount old;
289 struct async_icount new;
290
Alex Eldercaaa8a82014-08-18 18:25:12 -0500291 if (!(arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD)))
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800292 return -EINVAL;
293
294 do {
295 spin_lock_irq(&gb_tty->read_lock);
296 old = gb_tty->oldcount;
297 new = gb_tty->iocount;
298 gb_tty->oldcount = new;
Alex Eldercaaa8a82014-08-18 18:25:12 -0500299 spin_unlock_irq(&gb_tty->read_lock);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800300
301 if ((arg & TIOCM_DSR) && (old.dsr != new.dsr))
302 break;
303 if ((arg & TIOCM_CD) && (old.dcd != new.dcd))
304 break;
305 if ((arg & TIOCM_RI) && (old.rng != new.rng))
306 break;
307
308 add_wait_queue(&gb_tty->wioctl, &wait);
309 set_current_state(TASK_INTERRUPTIBLE);
310 schedule();
311 remove_wait_queue(&gb_tty->wioctl, &wait);
312 if (gb_tty->disconnected) {
313 if (arg & TIOCM_CD)
314 break;
Alex Eldercaaa8a82014-08-18 18:25:12 -0500315 retval = -ENODEV;
316 } else if (signal_pending(current)) {
317 retval = -ERESTARTSYS;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800318 }
319 } while (!retval);
320
321 return retval;
322}
323
324static int get_serial_usage(struct gb_tty *gb_tty,
325 struct serial_icounter_struct __user *count)
326{
327 struct serial_icounter_struct icount;
328 int retval = 0;
329
330 memset(&icount, 0, sizeof(icount));
331 icount.dsr = gb_tty->iocount.dsr;
332 icount.rng = gb_tty->iocount.rng;
333 icount.dcd = gb_tty->iocount.dcd;
334 icount.frame = gb_tty->iocount.frame;
335 icount.overrun = gb_tty->iocount.overrun;
336 icount.parity = gb_tty->iocount.parity;
337 icount.brk = gb_tty->iocount.brk;
338
339 if (copy_to_user(count, &icount, sizeof(icount)) > 0)
340 retval = -EFAULT;
341
342 return retval;
343}
344
345static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
346 unsigned long arg)
347{
348 struct gb_tty *gb_tty = tty->driver_data;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800349
350 switch (cmd) {
351 case TIOCGSERIAL:
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700352 return get_serial_info(gb_tty,
353 (struct serial_struct __user *)arg);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800354 case TIOCSSERIAL:
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700355 return set_serial_info(gb_tty,
356 (struct serial_struct __user *)arg);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800357 case TIOCMIWAIT:
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700358 return wait_serial_change(gb_tty, arg);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800359 case TIOCGICOUNT:
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700360 return get_serial_usage(gb_tty,
361 (struct serial_icounter_struct __user *)arg);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800362 }
363
Greg Kroah-Hartman199d68d2014-08-30 16:20:22 -0700364 return -ENOIOCTLCMD;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800365}
366
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800367
368static const struct tty_operations gb_ops = {
369 .install = gb_tty_install,
370 .open = gb_tty_open,
371 .close = gb_tty_close,
372 .cleanup = gb_tty_cleanup,
373 .hangup = gb_tty_hangup,
374 .write = gb_tty_write,
375 .write_room = gb_tty_write_room,
376 .ioctl = gb_tty_ioctl,
377 .throttle = gb_tty_throttle,
378 .unthrottle = gb_tty_unthrottle,
379 .chars_in_buffer = gb_tty_chars_in_buffer,
380 .break_ctl = gb_tty_break_ctl,
381 .set_termios = gb_tty_set_termios,
382 .tiocmget = gb_tty_tiocmget,
383 .tiocmset = gb_tty_tiocmset,
384};
385
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800386
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700387int gb_tty_probe(struct greybus_device *gdev,
Greg Kroah-Hartman6584c8a2014-09-01 13:31:31 -0700388 const struct greybus_module_id *id)
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800389{
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800390 struct gb_tty *gb_tty;
391 struct device *tty_dev;
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800392 int retval;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800393 int minor;
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800394
Greg Kroah-Hartman8bf23e82014-08-30 17:18:04 -0700395 gb_tty = kzalloc(sizeof(*gb_tty), GFP_KERNEL);
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800396 if (!gb_tty)
397 return -ENOMEM;
398
399 minor = alloc_minor(gb_tty);
Alex Elderff5f0b32014-08-18 18:25:11 -0500400 if (minor < 0) {
401 if (minor == -ENOSPC) {
402 dev_err(&gdev->dev, "no more free minor numbers\n");
403 return -ENODEV;
404 }
405 return minor;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800406 }
407
408 gb_tty->minor = minor;
409 gb_tty->gdev = gdev;
410 spin_lock_init(&gb_tty->write_lock);
411 spin_lock_init(&gb_tty->read_lock);
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800412 init_waitqueue_head(&gb_tty->wioctl);
413 mutex_init(&gb_tty->mutex);
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800414
415 /* FIXME - allocate gb buffers */
416
Greg Kroah-Hartmaneca17c52014-08-30 16:54:05 -0700417 gdev->gb_tty = gb_tty;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800418
419 tty_dev = tty_port_register_device(&gb_tty->port, gb_tty_driver, minor,
420 &gdev->dev);
421 if (IS_ERR(tty_dev)) {
422 retval = PTR_ERR(tty_dev);
423 goto error;
424 }
425
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800426 return 0;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800427error:
Greg Kroah-Hartmaneca17c52014-08-30 16:54:05 -0700428 gdev->gb_tty = NULL;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800429 release_minor(gb_tty);
430 return retval;
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800431}
432
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700433void gb_tty_disconnect(struct greybus_device *gdev)
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800434{
Greg Kroah-Hartmaneca17c52014-08-30 16:54:05 -0700435 struct gb_tty *gb_tty = gdev->gb_tty;
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800436 struct tty_struct *tty;
437
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800438 if (!gb_tty)
439 return;
440
441 mutex_lock(&gb_tty->mutex);
442 gb_tty->disconnected = true;
443
444 wake_up_all(&gb_tty->wioctl);
Greg Kroah-Hartmaneca17c52014-08-30 16:54:05 -0700445 gdev->gb_tty = NULL;
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800446 mutex_unlock(&gb_tty->mutex);
447
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800448 tty = tty_port_tty_get(&gb_tty->port);
449 if (tty) {
450 tty_vhangup(tty);
451 tty_kref_put(tty);
452 }
453 /* FIXME - stop all traffic */
454
455 tty_unregister_device(gb_tty_driver, gb_tty->minor);
456
Greg Kroah-Hartmane68453e2014-08-15 19:44:32 +0800457 /* FIXME - free transmit / recieve buffers */
458
Greg Kroah-Hartmana18e1512014-08-15 18:54:11 +0800459 tty_port_put(&gb_tty->port);
Greg Kroah-Hartmane5f167f2014-08-30 17:11:41 -0700460
461 kfree(gb_tty);
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800462}
463
Greg Kroah-Hartman543b8ed2014-09-13 17:02:47 -0700464#if 0
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800465static struct greybus_driver tty_gb_driver = {
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700466 .probe = gb_tty_probe,
467 .disconnect = gb_tty_disconnect,
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800468 .id_table = id_table,
469};
Greg Kroah-Hartman543b8ed2014-09-13 17:02:47 -0700470#endif
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800471
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700472int __init gb_tty_init(void)
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800473{
Marti Bolivar7fabc882014-09-05 23:56:10 -0400474 int retval = 0;
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800475
Marti Bolivarf8089c02014-09-05 23:56:09 -0400476 gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, 0);
Marti Bolivar7fabc882014-09-05 23:56:10 -0400477 if (IS_ERR(gb_tty_driver)) {
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700478 pr_err("Can not allocate tty driver\n");
Marti Bolivar7fabc882014-09-05 23:56:10 -0400479 retval = -ENOMEM;
480 goto fail_unregister_dev;
481 }
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800482
483 gb_tty_driver->driver_name = "gb";
Marti Bolivar7fabc882014-09-05 23:56:10 -0400484 gb_tty_driver->name = GB_NAME;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700485 gb_tty_driver->major = 0;
486 gb_tty_driver->minor_start = 0;
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800487 gb_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
488 gb_tty_driver->subtype = SERIAL_TYPE_NORMAL;
489 gb_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
490 gb_tty_driver->init_termios = tty_std_termios;
491 gb_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
492 tty_set_operations(gb_tty_driver, &gb_ops);
493
494 retval = tty_register_driver(gb_tty_driver);
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700495 if (retval) {
496 pr_err("Can not register tty driver: %d\n", retval);
Marti Bolivar7fabc882014-09-05 23:56:10 -0400497 goto fail_put_gb_tty;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700498 }
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800499
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700500#if 0
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800501 retval = greybus_register(&tty_gb_driver);
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700502 if (retval) {
503 pr_err("Can not register greybus driver.\n");
Marti Bolivar7fabc882014-09-05 23:56:10 -0400504 goto fail_unregister_gb_tty;
Greg Kroah-Hartman168db1c2014-09-13 16:15:52 -0700505 }
506#endif
Marti Bolivar7fabc882014-09-05 23:56:10 -0400507
508 return 0;
509
Greg Kroah-Hartman543b8ed2014-09-13 17:02:47 -0700510/* fail_unregister_gb_tty: */
Marti Bolivar7fabc882014-09-05 23:56:10 -0400511 tty_unregister_driver(gb_tty_driver);
Greg Kroah-Hartman543b8ed2014-09-13 17:02:47 -0700512fail_put_gb_tty:
Marti Bolivar7fabc882014-09-05 23:56:10 -0400513 put_tty_driver(gb_tty_driver);
Greg Kroah-Hartman543b8ed2014-09-13 17:02:47 -0700514fail_unregister_dev:
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800515 return retval;
516}
517
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700518void __exit gb_tty_exit(void)
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800519{
Marti Bolivar7fabc882014-09-05 23:56:10 -0400520 int major = MAJOR(gb_tty_driver->major);
521 int minor = gb_tty_driver->minor_start;
Greg Kroah-Hartman543b8ed2014-09-13 17:02:47 -0700522
523#if 0
524 greybus_deregister(&tty_gb_driver);
525#endif
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800526 tty_unregister_driver(gb_tty_driver);
527 put_tty_driver(gb_tty_driver);
Marti Bolivar7fabc882014-09-05 23:56:10 -0400528 unregister_chrdev_region(MKDEV(major, minor), GB_NUM_MINORS);
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800529}
530
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700531#if 0
Greg Kroah-Hartman79c822b2014-08-15 16:01:23 +0800532module_init(gb_tty_init);
533module_exit(gb_tty_exit);
534MODULE_LICENSE("GPL");
535MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
Greg Kroah-Hartmandb6e1fd2014-08-30 16:47:26 -0700536#endif