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 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 16#include <linux/kernel.h> 17#include <linux/errno.h> 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 47#define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count) 48 49static struct tty_driver *gdm_driver[TTY_MAX_COUNT]; 50static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR]; 51static DEFINE_MUTEX(gdm_table_lock); 52 53static char *DRIVER_STRING[TTY_MAX_COUNT] = {"GCTATC", "GCTDM"}; 54static char *DEVICE_STRING[TTY_MAX_COUNT] = {"GCT-ATC", "GCT-DM"}; 55 56static void gdm_port_destruct(struct tty_port *port) 57{ 58 struct gdm *gdm = container_of(port, struct gdm, port); 59 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 67static struct tty_port_operations gdm_port_ops = { 68 .destruct = gdm_port_destruct, 69}; 70 71static int gdm_tty_install(struct tty_driver *driver, struct tty_struct *tty) 72{ 73 struct gdm *gdm = NULL; 74 int ret; 75 int i; 76 int j; 77 78 j = GDM_TTY_MINOR; 79 for (i = 0; i < TTY_MAX_COUNT; i++) { 80 if (!strcmp(tty->driver->driver_name, DRIVER_STRING[i])) { 81 j = tty->index; 82 break; 83 } 84 } 85 86 if (j == GDM_TTY_MINOR) 87 return -ENODEV; 88 89 mutex_lock(&gdm_table_lock); 90 gdm = gdm_table[i][j]; 91 if (gdm == NULL) { 92 mutex_unlock(&gdm_table_lock); 93 return -ENODEV; 94 } 95 96 tty_port_get(&gdm->port); 97 98 ret = tty_standard_install(driver, tty); 99 if (ret) { 100 tty_port_put(&gdm->port); 101 mutex_unlock(&gdm_table_lock); 102 return ret; 103 } 104 105 tty->driver_data = gdm; 106 mutex_unlock(&gdm_table_lock); 107 108 return 0; 109} 110 111static int gdm_tty_open(struct tty_struct *tty, struct file *filp) 112{ 113 struct gdm *gdm = tty->driver_data; 114 115 return tty_port_open(&gdm->port, tty, filp); 116} 117 118static void gdm_tty_cleanup(struct tty_struct *tty) 119{ 120 struct gdm *gdm = tty->driver_data; 121 122 tty_port_put(&gdm->port); 123} 124 125static void gdm_tty_hangup(struct tty_struct *tty) 126{ 127 struct gdm *gdm = tty->driver_data; 128 129 tty_port_hangup(&gdm->port); 130} 131 132static void gdm_tty_close(struct tty_struct *tty, struct file *filp) 133{ 134 struct gdm *gdm = tty->driver_data; 135 136 tty_port_close(&gdm->port, tty, filp); 137} 138 139static int gdm_tty_recv_complete(void *data, 140 int len, 141 int index, 142 struct tty_dev *tty_dev, 143 int complete) 144{ 145 struct gdm *gdm = tty_dev->gdm[index]; 146 147 if (!GDM_TTY_READY(gdm)) { 148 if (complete == RECV_PACKET_PROCESS_COMPLETE) 149 gdm_tty_recv(gdm, gdm_tty_recv_complete); 150 return TO_HOST_PORT_CLOSE; 151 } 152 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 } 160 } 161 162 if (complete == RECV_PACKET_PROCESS_COMPLETE) 163 gdm_tty_recv(gdm, gdm_tty_recv_complete); 164 165 return 0; 166} 167 168static void gdm_tty_send_complete(void *arg) 169{ 170 struct gdm *gdm = (struct gdm *)arg; 171 172 if (!GDM_TTY_READY(gdm)) 173 return; 174 175 tty_port_tty_wakeup(&gdm->port); 176} 177 178static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, 179 int len) 180{ 181 struct gdm *gdm = tty->driver_data; 182 int remain = len; 183 int sent_len = 0; 184 int sending_len = 0; 185 186 if (!GDM_TTY_READY(gdm)) 187 return -ENODEV; 188 189 if (!len) 190 return 0; 191 192 while (1) { 193 sending_len = remain > MUX_TX_MAX_SIZE ? MUX_TX_MAX_SIZE : 194 remain; 195 gdm_tty_send(gdm, 196 (void *)(buf+sent_len), 197 sending_len, 198 gdm->index, 199 gdm_tty_send_complete, 200 gdm 201 ); 202 sent_len += sending_len; 203 remain -= sending_len; 204 if (remain <= 0) 205 break; 206 } 207 208 return len; 209} 210 211static int gdm_tty_write_room(struct tty_struct *tty) 212{ 213 struct gdm *gdm = tty->driver_data; 214 215 if (!GDM_TTY_READY(gdm)) 216 return -ENODEV; 217 218 return WRITE_SIZE; 219} 220 221int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device) 222{ 223 struct gdm *gdm; 224 int i; 225 int j; 226 227 for (i = 0; i < TTY_MAX_COUNT; i++) { 228 229 gdm = kmalloc(sizeof(struct gdm), GFP_KERNEL); 230 if (!gdm) 231 return -ENOMEM; 232 233 mutex_lock(&gdm_table_lock); 234 for (j = 0; j < GDM_TTY_MINOR; j++) { 235 if (!gdm_table[i][j]) 236 break; 237 } 238 239 if (j == GDM_TTY_MINOR) { 240 kfree(gdm); 241 mutex_unlock(&gdm_table_lock); 242 return -EINVAL; 243 } 244 245 gdm_table[i][j] = gdm; 246 mutex_unlock(&gdm_table_lock); 247 248 tty_dev->gdm[i] = gdm; 249 tty_port_init(&gdm->port); 250 251 gdm->port.ops = &gdm_port_ops; 252 gdm->index = i; 253 gdm->minor = j; 254 gdm->tty_dev = tty_dev; 255 256 tty_port_register_device(&gdm->port, gdm_driver[i], 257 gdm->minor, device); 258 } 259 260 for (i = 0; i < MAX_ISSUE_NUM; i++) 261 gdm_tty_recv(gdm, gdm_tty_recv_complete); 262 263 return 0; 264} 265 266void unregister_lte_tty_device(struct tty_dev *tty_dev) 267{ 268 struct gdm *gdm; 269 struct tty_struct *tty; 270 int i; 271 272 for (i = 0; i < TTY_MAX_COUNT; i++) { 273 gdm = tty_dev->gdm[i]; 274 if (!gdm) 275 continue; 276 277 mutex_lock(&gdm_table_lock); 278 gdm_table[gdm->index][gdm->minor] = NULL; 279 mutex_unlock(&gdm_table_lock); 280 281 tty = tty_port_tty_get(&gdm->port); 282 if (tty) { 283 tty_vhangup(tty); 284 tty_kref_put(tty); 285 } 286 287 tty_unregister_device(gdm_driver[i], gdm->minor); 288 tty_port_put(&gdm->port); 289 } 290} 291 292static const struct tty_operations gdm_tty_ops = { 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, 300}; 301 302int register_lte_tty_driver(void) 303{ 304 struct tty_driver *tty_driver; 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); 310 if (!tty_driver) 311 return -ENOMEM; 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; 319 tty_driver->flags = TTY_DRIVER_REAL_RAW | 320 TTY_DRIVER_DYNAMIC_DEV; 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); 327 if (ret) { 328 put_tty_driver(tty_driver); 329 return ret; 330 } 331 332 gdm_driver[i] = tty_driver; 333 } 334 335 return ret; 336} 337 338void 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++) { 344 tty_driver = gdm_driver[i]; 345 if (tty_driver) { 346 tty_unregister_driver(tty_driver); 347 put_tty_driver(tty_driver); 348 } 349 } 350} 351 352