linux/drivers/staging/gdm724x/gdm_tty.c
<<
>>
Prefs
   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 const 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) {
  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 = 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                gdm = kmalloc(sizeof(*gdm), GFP_KERNEL);
 229                if (!gdm)
 230                        return -ENOMEM;
 231
 232                mutex_lock(&gdm_table_lock);
 233                for (j = 0; j < GDM_TTY_MINOR; j++) {
 234                        if (!gdm_table[i][j])
 235                                break;
 236                }
 237
 238                if (j == GDM_TTY_MINOR) {
 239                        kfree(gdm);
 240                        mutex_unlock(&gdm_table_lock);
 241                        return -EINVAL;
 242                }
 243
 244                gdm_table[i][j] = gdm;
 245                mutex_unlock(&gdm_table_lock);
 246
 247                tty_dev->gdm[i] = gdm;
 248                tty_port_init(&gdm->port);
 249
 250                gdm->port.ops = &gdm_port_ops;
 251                gdm->index = i;
 252                gdm->minor = j;
 253                gdm->tty_dev = tty_dev;
 254
 255                tty_port_register_device(&gdm->port, gdm_driver[i],
 256                                         gdm->minor, device);
 257        }
 258
 259        for (i = 0; i < MAX_ISSUE_NUM; i++)
 260                gdm_tty_recv(gdm, gdm_tty_recv_complete);
 261
 262        return 0;
 263}
 264
 265void unregister_lte_tty_device(struct tty_dev *tty_dev)
 266{
 267        struct gdm *gdm;
 268        struct tty_struct *tty;
 269        int i;
 270
 271        for (i = 0; i < TTY_MAX_COUNT; i++) {
 272                gdm = tty_dev->gdm[i];
 273                if (!gdm)
 274                        continue;
 275
 276                mutex_lock(&gdm_table_lock);
 277                gdm_table[gdm->index][gdm->minor] = NULL;
 278                mutex_unlock(&gdm_table_lock);
 279
 280                tty = tty_port_tty_get(&gdm->port);
 281                if (tty) {
 282                        tty_vhangup(tty);
 283                        tty_kref_put(tty);
 284                }
 285
 286                tty_unregister_device(gdm_driver[i], gdm->minor);
 287                tty_port_put(&gdm->port);
 288        }
 289}
 290
 291static const struct tty_operations gdm_tty_ops = {
 292        .install =      gdm_tty_install,
 293        .open =         gdm_tty_open,
 294        .close =        gdm_tty_close,
 295        .cleanup =      gdm_tty_cleanup,
 296        .hangup =       gdm_tty_hangup,
 297        .write =        gdm_tty_write,
 298        .write_room =   gdm_tty_write_room,
 299};
 300
 301int register_lte_tty_driver(void)
 302{
 303        struct tty_driver *tty_driver;
 304        int i;
 305        int ret;
 306
 307        for (i = 0; i < TTY_MAX_COUNT; i++) {
 308                tty_driver = alloc_tty_driver(GDM_TTY_MINOR);
 309                if (!tty_driver)
 310                        return -ENOMEM;
 311
 312                tty_driver->owner = THIS_MODULE;
 313                tty_driver->driver_name = DRIVER_STRING[i];
 314                tty_driver->name = DEVICE_STRING[i];
 315                tty_driver->major = GDM_TTY_MAJOR;
 316                tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
 317                tty_driver->subtype = SERIAL_TYPE_NORMAL;
 318                tty_driver->flags = TTY_DRIVER_REAL_RAW |
 319                                        TTY_DRIVER_DYNAMIC_DEV;
 320                tty_driver->init_termios = tty_std_termios;
 321                tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL;
 322                tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN;
 323                tty_set_operations(tty_driver, &gdm_tty_ops);
 324
 325                ret = tty_register_driver(tty_driver);
 326                if (ret) {
 327                        put_tty_driver(tty_driver);
 328                        return ret;
 329                }
 330
 331                gdm_driver[i] = tty_driver;
 332        }
 333
 334        return ret;
 335}
 336
 337void unregister_lte_tty_driver(void)
 338{
 339        struct tty_driver *tty_driver;
 340        int i;
 341
 342        for (i = 0; i < TTY_MAX_COUNT; i++) {
 343                tty_driver = gdm_driver[i];
 344                if (tty_driver) {
 345                        tty_unregister_driver(tty_driver);
 346                        put_tty_driver(tty_driver);
 347                }
 348        }
 349}
 350
 351