Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. |
| 3 | * |
| 4 | * This software is licensed under the terms of the GNU General Public |
| 5 | * License version 2, as published by the Free Software Foundation, and |
| 6 | * may be copied, distributed, and modified under those terms. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | */ |
| 13 | |
Joe Perches | 0ec473b | 2013-07-24 14:13:03 -0700 | [diff] [blame] | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 15 | |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 16 | #include <linux/kernel.h> |
| 17 | #include <linux/errno.h> |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 18 | #include <linux/tty.h> |
| 19 | #include <linux/tty_driver.h> |
| 20 | #include <linux/tty_flip.h> |
| 21 | #include <linux/module.h> |
| 22 | #include <linux/slab.h> |
| 23 | #include <linux/usb/cdc.h> |
| 24 | #include <linux/serial.h> |
| 25 | #include "gdm_tty.h" |
| 26 | |
| 27 | #define GDM_TTY_MAJOR 0 |
| 28 | #define GDM_TTY_MINOR 32 |
| 29 | |
| 30 | #define ACM_CTRL_DTR 0x01 |
| 31 | #define ACM_CTRL_RTS 0x02 |
| 32 | #define ACM_CTRL_DSR 0x02 |
| 33 | #define ACM_CTRL_RI 0x08 |
| 34 | #define ACM_CTRL_DCD 0x01 |
| 35 | |
| 36 | #define WRITE_SIZE 2048 |
| 37 | |
| 38 | #define MUX_TX_MAX_SIZE 2048 |
| 39 | |
| 40 | #define gdm_tty_send(n, d, l, i, c, b) (\ |
| 41 | n->tty_dev->send_func(n->tty_dev->priv_dev, d, l, i, c, b)) |
| 42 | #define gdm_tty_recv(n, c) (\ |
| 43 | n->tty_dev->recv_func(n->tty_dev->priv_dev, c)) |
| 44 | #define gdm_tty_send_control(n, r, v, d, l) (\ |
| 45 | n->tty_dev->send_control(n->tty_dev->priv_dev, r, v, d, l)) |
| 46 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 47 | #define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 48 | |
Fengguang Wu | 7ca1ea6 | 2013-08-27 17:08:16 -0700 | [diff] [blame] | 49 | static struct tty_driver *gdm_driver[TTY_MAX_COUNT]; |
| 50 | static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR]; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 51 | static DEFINE_MUTEX(gdm_table_lock); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 52 | |
| 53 | static char *DRIVER_STRING[TTY_MAX_COUNT] = {"GCTATC", "GCTDM"}; |
| 54 | static char *DEVICE_STRING[TTY_MAX_COUNT] = {"GCT-ATC", "GCT-DM"}; |
| 55 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 56 | static void gdm_port_destruct(struct tty_port *port) |
| 57 | { |
| 58 | struct gdm *gdm = container_of(port, struct gdm, port); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 59 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 60 | mutex_lock(&gdm_table_lock); |
| 61 | gdm_table[gdm->index][gdm->minor] = NULL; |
| 62 | mutex_unlock(&gdm_table_lock); |
| 63 | |
| 64 | kfree(gdm); |
| 65 | } |
| 66 | |
Aya Mahfouz | e16a488 | 2015-12-15 01:27:27 +0200 | [diff] [blame] | 67 | static const struct tty_port_operations gdm_port_ops = { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 68 | .destruct = gdm_port_destruct, |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 69 | }; |
| 70 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 71 | static int gdm_tty_install(struct tty_driver *driver, struct tty_struct *tty) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 72 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 73 | struct gdm *gdm = NULL; |
| 74 | int ret; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 75 | int i; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 76 | int j; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 77 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 78 | j = GDM_TTY_MINOR; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 79 | for (i = 0; i < TTY_MAX_COUNT; i++) { |
| 80 | if (!strcmp(tty->driver->driver_name, DRIVER_STRING[i])) { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 81 | j = tty->index; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 82 | break; |
| 83 | } |
| 84 | } |
| 85 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 86 | if (j == GDM_TTY_MINOR) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 87 | return -ENODEV; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 88 | |
| 89 | mutex_lock(&gdm_table_lock); |
| 90 | gdm = gdm_table[i][j]; |
Ioana Ciornei | b6f6fd8 | 2015-10-18 15:51:49 +0300 | [diff] [blame] | 91 | if (!gdm) { |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 92 | mutex_unlock(&gdm_table_lock); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 93 | return -ENODEV; |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 94 | } |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 95 | |
| 96 | tty_port_get(&gdm->port); |
| 97 | |
| 98 | ret = tty_standard_install(driver, tty); |
| 99 | if (ret) { |
| 100 | tty_port_put(&gdm->port); |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 101 | mutex_unlock(&gdm_table_lock); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 102 | return ret; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 103 | } |
| 104 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 105 | tty->driver_data = gdm; |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 106 | mutex_unlock(&gdm_table_lock); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 107 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 108 | return 0; |
| 109 | } |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 110 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 111 | static int gdm_tty_open(struct tty_struct *tty, struct file *filp) |
| 112 | { |
| 113 | struct gdm *gdm = tty->driver_data; |
Kiran Padwal | f4ef08f | 2014-07-17 09:35:18 +0530 | [diff] [blame] | 114 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 115 | return tty_port_open(&gdm->port, tty, filp); |
| 116 | } |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 117 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 118 | static void gdm_tty_cleanup(struct tty_struct *tty) |
| 119 | { |
| 120 | struct gdm *gdm = tty->driver_data; |
Kiran Padwal | f4ef08f | 2014-07-17 09:35:18 +0530 | [diff] [blame] | 121 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 122 | tty_port_put(&gdm->port); |
| 123 | } |
| 124 | |
| 125 | static void gdm_tty_hangup(struct tty_struct *tty) |
| 126 | { |
| 127 | struct gdm *gdm = tty->driver_data; |
Kiran Padwal | f4ef08f | 2014-07-17 09:35:18 +0530 | [diff] [blame] | 128 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 129 | tty_port_hangup(&gdm->port); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | static void gdm_tty_close(struct tty_struct *tty, struct file *filp) |
| 133 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 134 | struct gdm *gdm = tty->driver_data; |
Kiran Padwal | f4ef08f | 2014-07-17 09:35:18 +0530 | [diff] [blame] | 135 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 136 | tty_port_close(&gdm->port, tty, filp); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 137 | } |
| 138 | |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 139 | static int gdm_tty_recv_complete(void *data, |
| 140 | int len, |
| 141 | int index, |
| 142 | struct tty_dev *tty_dev, |
| 143 | int complete) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 144 | { |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 145 | struct gdm *gdm = tty_dev->gdm[index]; |
Kiran Padwal | f4ef08f | 2014-07-17 09:35:18 +0530 | [diff] [blame] | 146 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 147 | if (!GDM_TTY_READY(gdm)) { |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 148 | if (complete == RECV_PACKET_PROCESS_COMPLETE) |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 149 | gdm_tty_recv(gdm, gdm_tty_recv_complete); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 150 | return TO_HOST_PORT_CLOSE; |
| 151 | } |
| 152 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 153 | if (data && len) { |
| 154 | if (tty_buffer_request_room(&gdm->port, len) == len) { |
| 155 | tty_insert_flip_string(&gdm->port, data, len); |
| 156 | tty_flip_buffer_push(&gdm->port); |
| 157 | } else { |
| 158 | return TO_HOST_BUFFER_REQUEST_FAIL; |
| 159 | } |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 160 | } |
| 161 | |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 162 | if (complete == RECV_PACKET_PROCESS_COMPLETE) |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 163 | gdm_tty_recv(gdm, gdm_tty_recv_complete); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 164 | |
Greg Kroah-Hartman | 497a2e0 | 2013-07-24 13:22:29 -0700 | [diff] [blame] | 165 | return 0; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | static void gdm_tty_send_complete(void *arg) |
| 169 | { |
Shraddha Barke | 2594ca3 | 2015-10-15 00:58:20 +0530 | [diff] [blame] | 170 | struct gdm *gdm = arg; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 171 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 172 | if (!GDM_TTY_READY(gdm)) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 173 | return; |
| 174 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 175 | tty_port_tty_wakeup(&gdm->port); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 176 | } |
| 177 | |
Ebru Akagunduz | 208b867 | 2013-10-10 15:08:32 +0300 | [diff] [blame] | 178 | static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, |
| 179 | int len) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 180 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 181 | struct gdm *gdm = tty->driver_data; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 182 | int remain = len; |
| 183 | int sent_len = 0; |
| 184 | int sending_len = 0; |
| 185 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 186 | if (!GDM_TTY_READY(gdm)) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 187 | return -ENODEV; |
| 188 | |
| 189 | if (!len) |
| 190 | return 0; |
| 191 | |
| 192 | while (1) { |
Ebru Akagunduz | 208b867 | 2013-10-10 15:08:32 +0300 | [diff] [blame] | 193 | sending_len = remain > MUX_TX_MAX_SIZE ? MUX_TX_MAX_SIZE : |
| 194 | remain; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 195 | gdm_tty_send(gdm, |
Ioana Ciornei | ba7f55b | 2015-10-18 15:51:50 +0300 | [diff] [blame] | 196 | (void *)(buf + sent_len), |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 197 | sending_len, |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 198 | gdm->index, |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 199 | gdm_tty_send_complete, |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 200 | gdm |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 201 | ); |
| 202 | sent_len += sending_len; |
| 203 | remain -= sending_len; |
| 204 | if (remain <= 0) |
| 205 | break; |
| 206 | } |
| 207 | |
| 208 | return len; |
| 209 | } |
| 210 | |
| 211 | static int gdm_tty_write_room(struct tty_struct *tty) |
| 212 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 213 | struct gdm *gdm = tty->driver_data; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 214 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 215 | if (!GDM_TTY_READY(gdm)) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 216 | return -ENODEV; |
| 217 | |
| 218 | return WRITE_SIZE; |
| 219 | } |
| 220 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 221 | int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 222 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 223 | struct gdm *gdm; |
| 224 | int i; |
| 225 | int j; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 226 | |
| 227 | for (i = 0; i < TTY_MAX_COUNT; i++) { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 228 | |
Ioana Ciornei | 7b7df12 | 2015-10-18 15:51:51 +0300 | [diff] [blame] | 229 | gdm = kmalloc(sizeof(*gdm), GFP_KERNEL); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 230 | if (!gdm) |
| 231 | return -ENOMEM; |
| 232 | |
| 233 | mutex_lock(&gdm_table_lock); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 234 | for (j = 0; j < GDM_TTY_MINOR; j++) { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 235 | if (!gdm_table[i][j]) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 236 | break; |
| 237 | } |
| 238 | |
| 239 | if (j == GDM_TTY_MINOR) { |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 240 | kfree(gdm); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 241 | mutex_unlock(&gdm_table_lock); |
| 242 | return -EINVAL; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 243 | } |
| 244 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 245 | gdm_table[i][j] = gdm; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 246 | mutex_unlock(&gdm_table_lock); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 247 | |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 248 | tty_dev->gdm[i] = gdm; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 249 | tty_port_init(&gdm->port); |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 250 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 251 | gdm->port.ops = &gdm_port_ops; |
| 252 | gdm->index = i; |
| 253 | gdm->minor = j; |
| 254 | gdm->tty_dev = tty_dev; |
| 255 | |
Ebru Akagunduz | 208b867 | 2013-10-10 15:08:32 +0300 | [diff] [blame] | 256 | tty_port_register_device(&gdm->port, gdm_driver[i], |
| 257 | gdm->minor, device); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 258 | } |
| 259 | |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 260 | for (i = 0; i < MAX_ISSUE_NUM; i++) |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 261 | gdm_tty_recv(gdm, gdm_tty_recv_complete); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 262 | |
| 263 | return 0; |
| 264 | } |
| 265 | |
| 266 | void unregister_lte_tty_device(struct tty_dev *tty_dev) |
| 267 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 268 | struct gdm *gdm; |
| 269 | struct tty_struct *tty; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 270 | int i; |
| 271 | |
| 272 | for (i = 0; i < TTY_MAX_COUNT; i++) { |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 273 | gdm = tty_dev->gdm[i]; |
| 274 | if (!gdm) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 275 | continue; |
| 276 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 277 | mutex_lock(&gdm_table_lock); |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 278 | gdm_table[gdm->index][gdm->minor] = NULL; |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 279 | mutex_unlock(&gdm_table_lock); |
| 280 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 281 | tty = tty_port_tty_get(&gdm->port); |
| 282 | if (tty) { |
| 283 | tty_vhangup(tty); |
| 284 | tty_kref_put(tty); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 285 | } |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 286 | |
Won Kang | bf0373f | 2013-08-16 13:13:44 +0900 | [diff] [blame] | 287 | tty_unregister_device(gdm_driver[i], gdm->minor); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 288 | tty_port_put(&gdm->port); |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 289 | } |
| 290 | } |
| 291 | |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 292 | static const struct tty_operations gdm_tty_ops = { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 293 | .install = gdm_tty_install, |
| 294 | .open = gdm_tty_open, |
| 295 | .close = gdm_tty_close, |
| 296 | .cleanup = gdm_tty_cleanup, |
| 297 | .hangup = gdm_tty_hangup, |
| 298 | .write = gdm_tty_write, |
| 299 | .write_room = gdm_tty_write_room, |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 300 | }; |
| 301 | |
| 302 | int register_lte_tty_driver(void) |
| 303 | { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 304 | struct tty_driver *tty_driver; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 305 | int i; |
| 306 | int ret; |
| 307 | |
| 308 | for (i = 0; i < TTY_MAX_COUNT; i++) { |
| 309 | tty_driver = alloc_tty_driver(GDM_TTY_MINOR); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 310 | if (!tty_driver) |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 311 | return -ENOMEM; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 312 | |
| 313 | tty_driver->owner = THIS_MODULE; |
| 314 | tty_driver->driver_name = DRIVER_STRING[i]; |
| 315 | tty_driver->name = DEVICE_STRING[i]; |
| 316 | tty_driver->major = GDM_TTY_MAJOR; |
| 317 | tty_driver->type = TTY_DRIVER_TYPE_SERIAL; |
| 318 | tty_driver->subtype = SERIAL_TYPE_NORMAL; |
Ebru Akagunduz | 208b867 | 2013-10-10 15:08:32 +0300 | [diff] [blame] | 319 | tty_driver->flags = TTY_DRIVER_REAL_RAW | |
| 320 | TTY_DRIVER_DYNAMIC_DEV; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 321 | tty_driver->init_termios = tty_std_termios; |
| 322 | tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL; |
| 323 | tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN; |
| 324 | tty_set_operations(tty_driver, &gdm_tty_ops); |
| 325 | |
| 326 | ret = tty_register_driver(tty_driver); |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 327 | if (ret) { |
| 328 | put_tty_driver(tty_driver); |
| 329 | return ret; |
| 330 | } |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 331 | |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 332 | gdm_driver[i] = tty_driver; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 333 | } |
| 334 | |
| 335 | return ret; |
| 336 | } |
| 337 | |
| 338 | void unregister_lte_tty_driver(void) |
| 339 | { |
| 340 | struct tty_driver *tty_driver; |
| 341 | int i; |
| 342 | |
| 343 | for (i = 0; i < TTY_MAX_COUNT; i++) { |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 344 | tty_driver = gdm_driver[i]; |
Won Kang | 61e1210 | 2013-07-25 03:36:17 +0900 | [diff] [blame] | 345 | if (tty_driver) { |
| 346 | tty_unregister_driver(tty_driver); |
| 347 | put_tty_driver(tty_driver); |
| 348 | } |
| 349 | } |
| 350 | } |
Won Kang | 7ee4c1b | 2013-08-16 13:13:43 +0900 | [diff] [blame] | 351 | |