tty/module.c
changeset 1800 5bfbb7be5400
parent 1796 3bb9ca8b58f2
child 1797 5bf740cd1599
equal deleted inserted replaced
1799:f228415225b7 1800:5bfbb7be5400
    39 #include <linux/tty_driver.h>
    39 #include <linux/tty_driver.h>
    40 #include <linux/tty_flip.h>
    40 #include <linux/tty_flip.h>
    41 #include <linux/termios.h>
    41 #include <linux/termios.h>
    42 #include <linux/timer.h>
    42 #include <linux/timer.h>
    43 #include <linux/version.h>
    43 #include <linux/version.h>
       
    44 #include <linux/serial.h>
       
    45 #include <linux/uaccess.h>
    44 
    46 
    45 #include "../master/globals.h"
    47 #include "../master/globals.h"
    46 #include "../include/ectty.h"
    48 #include "../include/ectty.h"
    47 
    49 
    48 /*****************************************************************************/
    50 /*****************************************************************************/
    49 
    51 
    50 #define PFX "ec_tty: "
    52 #define PFX "ec_tty: "
    51 
    53 
    52 #define EC_TTY_MAX_DEVICES 10
    54 #define EC_TTY_MAX_DEVICES 32
    53 #define EC_TTY_TX_BUFFER_SIZE 100
    55 #define EC_TTY_TX_BUFFER_SIZE 100
    54 #define EC_TTY_RX_BUFFER_SIZE 100
    56 #define EC_TTY_RX_BUFFER_SIZE 100
    55 
    57 
    56 #define EC_TTY_DEBUG 0
    58 #define EC_TTY_DEBUG 0
    57 
    59 
    61 unsigned int debug_level = 0;
    63 unsigned int debug_level = 0;
    62 
    64 
    63 static struct tty_driver *tty_driver = NULL;
    65 static struct tty_driver *tty_driver = NULL;
    64 ec_tty_t *ttys[EC_TTY_MAX_DEVICES];
    66 ec_tty_t *ttys[EC_TTY_MAX_DEVICES];
    65 struct semaphore tty_sem;
    67 struct semaphore tty_sem;
       
    68 
       
    69 void ec_tty_wakeup(unsigned long);
    66 
    70 
    67 /*****************************************************************************/
    71 /*****************************************************************************/
    68 
    72 
    69 /** \cond */
    73 /** \cond */
    70 
    74 
    76 module_param_named(debug_level, debug_level, uint, S_IRUGO);
    80 module_param_named(debug_level, debug_level, uint, S_IRUGO);
    77 MODULE_PARM_DESC(debug_level, "Debug level");
    81 MODULE_PARM_DESC(debug_level, "Debug level");
    78 
    82 
    79 /** \endcond */
    83 /** \endcond */
    80 
    84 
       
    85 /** Standard termios for ec_tty devices.
       
    86  *
       
    87  * Simplest possible configuration, as you would expect.
       
    88  */
    81 static struct ktermios ec_tty_std_termios = {
    89 static struct ktermios ec_tty_std_termios = {
    82     .c_iflag = ICRNL | IXON,
    90     .c_iflag = 0,
    83     .c_oflag = OPOST,
    91     .c_oflag = 0,
    84     .c_cflag = B38400 | CS8 | CREAD | HUPCL,
    92     .c_cflag = B9600 | CS8 | CREAD,
    85     .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN,
    93     .c_lflag = 0,
    86     .c_cc = INIT_C_CC,
    94     .c_cc = INIT_C_CC,
    87 };
    95 };
    88 
    96 
    89 struct ec_tty {
    97 struct ec_tty {
    90     int minor;
    98     int minor;
    99     unsigned int rx_read_idx;
   107     unsigned int rx_read_idx;
   100     unsigned int rx_write_idx;
   108     unsigned int rx_write_idx;
   101 
   109 
   102     struct timer_list timer;
   110     struct timer_list timer;
   103     struct tty_struct *tty;
   111     struct tty_struct *tty;
       
   112 
       
   113     ec_tty_operations_t ops;
       
   114     void *cb_data;
   104 };
   115 };
   105 
   116 
   106 static const struct tty_operations ec_tty_ops; // see below
   117 static const struct tty_operations ec_tty_ops; // see below
   107 
   118 
   108 /*****************************************************************************/
   119 /*****************************************************************************/
   137     tty_driver->minor_start = 0;
   148     tty_driver->minor_start = 0;
   138     tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
   149     tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
   139     tty_driver->subtype = SERIAL_TYPE_NORMAL;
   150     tty_driver->subtype = SERIAL_TYPE_NORMAL;
   140     tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
   151     tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
   141     tty_driver->init_termios = ec_tty_std_termios;
   152     tty_driver->init_termios = ec_tty_std_termios;
   142     tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
       
   143     tty_set_operations(tty_driver, &ec_tty_ops);
   153     tty_set_operations(tty_driver, &ec_tty_ops);
   144 
   154 
   145     ret = tty_register_driver(tty_driver);
   155     ret = tty_register_driver(tty_driver);
   146     if (ret) {
   156     if (ret) {
   147         printk(KERN_ERR PFX "Failed to register tty driver.\n");
   157         printk(KERN_ERR PFX "Failed to register tty driver.\n");
   167     tty_unregister_driver(tty_driver);
   177     tty_unregister_driver(tty_driver);
   168     put_tty_driver(tty_driver);
   178     put_tty_driver(tty_driver);
   169     printk(KERN_INFO PFX "Module unloading.\n");
   179     printk(KERN_INFO PFX "Module unloading.\n");
   170 }
   180 }
   171 
   181 
       
   182 /******************************************************************************
       
   183  * ec_tty_t methods.
       
   184  *****************************************************************************/
       
   185 
       
   186 int ec_tty_init(ec_tty_t *t, int minor,
       
   187         const ec_tty_operations_t *ops, void *cb_data)
       
   188 {
       
   189     int ret;
       
   190     tcflag_t cflag;
       
   191     struct tty_struct *tty;
       
   192 
       
   193     t->minor = minor;
       
   194     t->tx_read_idx = 0;
       
   195     t->tx_write_idx = 0;
       
   196     t->wakeup = 0;
       
   197     t->rx_read_idx = 0;
       
   198     t->rx_write_idx = 0;
       
   199     init_timer(&t->timer);
       
   200     t->tty = NULL;
       
   201     t->ops = *ops;
       
   202     t->cb_data = cb_data;
       
   203 
       
   204     t->dev = tty_register_device(tty_driver, t->minor, NULL);
       
   205     if (IS_ERR(t->dev)) {
       
   206         printk(KERN_ERR PFX "Failed to register tty device.\n");
       
   207         return PTR_ERR(t->dev);
       
   208     }
       
   209 
       
   210     // Tell the device-specific implementation about the initial cflags
       
   211     tty = tty_driver->ttys[minor];
       
   212 
       
   213     if (tty && tty->termios) { // already opened before
       
   214         cflag = tty->termios->c_cflag;
       
   215     } else {
       
   216         cflag = tty_driver->init_termios.c_cflag;
       
   217     }
       
   218     ret = t->ops.cflag_changed(t->cb_data, cflag);
       
   219     if (ret) {
       
   220         printk(KERN_ERR PFX "ERROR: Initial cflag 0x%x not accepted.\n",
       
   221                 cflag);
       
   222         tty_unregister_device(tty_driver, t->minor);
       
   223         return ret;
       
   224     }
       
   225 
       
   226     t->timer.function = ec_tty_wakeup;
       
   227     t->timer.data = (unsigned long) t;
       
   228     t->timer.expires = jiffies + 10;
       
   229     add_timer(&t->timer);
       
   230     return 0;
       
   231 }
       
   232 
       
   233 /*****************************************************************************/
       
   234 
       
   235 void ec_tty_clear(ec_tty_t *tty)
       
   236 {
       
   237     del_timer_sync(&tty->timer);
       
   238     tty_unregister_device(tty_driver, tty->minor);
       
   239 }
       
   240 
   172 /*****************************************************************************/
   241 /*****************************************************************************/
   173 
   242 
   174 unsigned int ec_tty_tx_size(ec_tty_t *tty)
   243 unsigned int ec_tty_tx_size(ec_tty_t *tty)
   175 {
   244 {
   176     unsigned int ret;
   245     unsigned int ret;
   213     return EC_TTY_RX_BUFFER_SIZE - 1 - ec_tty_rx_size(tty);
   282     return EC_TTY_RX_BUFFER_SIZE - 1 - ec_tty_rx_size(tty);
   214 }
   283 }
   215 
   284 
   216 /*****************************************************************************/
   285 /*****************************************************************************/
   217 
   286 
       
   287 int ec_tty_get_serial_info(ec_tty_t *tty, struct serial_struct *data)
       
   288 {
       
   289     struct serial_struct tmp;
       
   290 
       
   291     if (!data)
       
   292         return -EFAULT;
       
   293 
       
   294     memset(&tmp, 0, sizeof(tmp));
       
   295 
       
   296     if (copy_to_user(data, &tmp, sizeof(*data))) {
       
   297         return -EFAULT;
       
   298     }
       
   299     return 0;
       
   300 }
       
   301 
       
   302 /*****************************************************************************/
       
   303 
       
   304 /** Timer function.
       
   305  */
   218 void ec_tty_wakeup(unsigned long data)
   306 void ec_tty_wakeup(unsigned long data)
   219 {
   307 {
   220     ec_tty_t *tty = (ec_tty_t *) data;
   308     ec_tty_t *tty = (ec_tty_t *) data;
   221     size_t to_recv;
   309     size_t to_recv;
   222 
   310 
   235     to_recv = ec_tty_rx_size(tty);
   323     to_recv = ec_tty_rx_size(tty);
   236     if (to_recv && tty->tty) {
   324     if (to_recv && tty->tty) {
   237         unsigned char *cbuf;
   325         unsigned char *cbuf;
   238         int space = tty_prepare_flip_string(tty->tty, &cbuf, to_recv);
   326         int space = tty_prepare_flip_string(tty->tty, &cbuf, to_recv);
   239 
   327 
   240 		if (space < to_recv) {
   328         if (space < to_recv) {
   241 			printk(KERN_WARNING PFX "Insufficient space to_recv=%d space=%d\n",
   329             printk(KERN_WARNING PFX "Insufficient space to_recv=%d space=%d\n",
   242                     to_recv, space);
   330                     to_recv, space);
   243 		}
   331         }
   244 
   332 
   245         if (space < 0) {
   333         if (space < 0) {
   246             to_recv = 0;
   334             to_recv = 0;
   247         } else {
   335         } else {
   248             to_recv = space;
   336             to_recv = space;
   255             printk(KERN_INFO PFX "Pushing %u bytes to TTY core.\n", to_recv);
   343             printk(KERN_INFO PFX "Pushing %u bytes to TTY core.\n", to_recv);
   256 #endif
   344 #endif
   257 
   345 
   258             for (i = 0; i < to_recv; i++) {
   346             for (i = 0; i < to_recv; i++) {
   259                 cbuf[i] = tty->rx_buffer[tty->rx_read_idx];
   347                 cbuf[i] = tty->rx_buffer[tty->rx_read_idx];
   260                 tty->rx_read_idx = (tty->rx_read_idx + 1) % EC_TTY_RX_BUFFER_SIZE;
   348                 tty->rx_read_idx =
       
   349                     (tty->rx_read_idx + 1) % EC_TTY_RX_BUFFER_SIZE;
   261             }
   350             }
   262             tty_flip_buffer_push(tty->tty);
   351             tty_flip_buffer_push(tty->tty);
   263         }
   352         }
   264 	}
   353     }
   265     
   354     
   266     tty->timer.expires += 1;
   355     tty->timer.expires += 1;
   267     add_timer(&tty->timer);
   356     add_timer(&tty->timer);
   268 }
   357 }
   269 
   358 
   270 /*****************************************************************************/
       
   271 
       
   272 int ec_tty_init(ec_tty_t *tty, int minor)
       
   273 {
       
   274     tty->minor = minor;
       
   275     tty->tx_read_idx = 0;
       
   276     tty->tx_write_idx = 0;
       
   277     tty->wakeup = 0;
       
   278     tty->rx_read_idx = 0;
       
   279     tty->rx_write_idx = 0;
       
   280     init_timer(&tty->timer);
       
   281     tty->tty = NULL;
       
   282 
       
   283     tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
       
   284     if (IS_ERR(tty->dev)) {
       
   285         printk(KERN_ERR PFX "Failed to register tty device.\n");
       
   286         return PTR_ERR(tty->dev);
       
   287     }
       
   288 
       
   289     tty->timer.function = ec_tty_wakeup;
       
   290     tty->timer.data = (unsigned long) tty;
       
   291     tty->timer.expires = jiffies + 10;
       
   292     add_timer(&tty->timer);
       
   293     return 0;
       
   294 }
       
   295 
       
   296 /*****************************************************************************/
       
   297 
       
   298 void ec_tty_clear(ec_tty_t *tty)
       
   299 {
       
   300     del_timer_sync(&tty->timer);
       
   301     tty_unregister_device(tty_driver, tty->minor);
       
   302 }
       
   303 
       
   304 /******************************************************************************
   359 /******************************************************************************
   305  * Device callbacks
   360  * Device callbacks
   306  *****************************************************************************/
   361  *****************************************************************************/
   307 
   362 
   308 static int ec_tty_open(struct tty_struct *tty, struct file *file)
   363 static int ec_tty_open(struct tty_struct *tty, struct file *file)
   312 
   367 
   313 #if EC_TTY_DEBUG >= 1
   368 #if EC_TTY_DEBUG >= 1
   314     printk(KERN_INFO PFX "Opening line %i.\n", line);
   369     printk(KERN_INFO PFX "Opening line %i.\n", line);
   315 #endif
   370 #endif
   316 
   371 
   317 	if (line < 0 || line >= EC_TTY_MAX_DEVICES) {
   372     if (line < 0 || line >= EC_TTY_MAX_DEVICES) {
   318 		return -ENXIO;
   373         return -ENXIO;
   319     }
   374     }
   320 
   375 
   321     t = ttys[line];
   376     t = ttys[line];
   322     if (!t) {
   377     if (!t) {
   323         return -ENXIO;
   378         return -ENXIO;
   445 static void ec_tty_flush_buffer(struct tty_struct *tty)
   500 static void ec_tty_flush_buffer(struct tty_struct *tty)
   446 {
   501 {
   447 #if EC_TTY_DEBUG >= 2
   502 #if EC_TTY_DEBUG >= 2
   448     printk(KERN_INFO PFX "%s().\n", __func__);
   503     printk(KERN_INFO PFX "%s().\n", __func__);
   449 #endif
   504 #endif
       
   505 
       
   506     // FIXME empty ring buffer
   450 }
   507 }
   451 
   508 
   452 /*****************************************************************************/
   509 /*****************************************************************************/
   453 
   510 
   454 static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
   511 static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
   455 		    unsigned int cmd, unsigned long arg)
   512         unsigned int cmd, unsigned long arg)
   456 {
   513 {
       
   514     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
       
   515     int ret = -ENOTTY;
       
   516     
       
   517 #if EC_TTY_DEBUG >= 2
       
   518     printk(KERN_INFO PFX "%s(tty=%p, file=%p, cmd=%08x, arg=%08lx).\n",
       
   519             __func__, tty, file, cmd, arg);
       
   520     printk(KERN_INFO PFX "decoded: type=%02x nr=%u\n",
       
   521             _IOC_TYPE(cmd), _IOC_NR(cmd));
       
   522 #endif
       
   523 
       
   524     switch (cmd) {
       
   525         case TIOCGSERIAL:
       
   526             if (access_ok(VERIFY_WRITE,
       
   527                         (void *) arg, sizeof(struct serial_struct))) {
       
   528                 ret = ec_tty_get_serial_info(t, (struct serial_struct *) arg);
       
   529             } else {
       
   530                 ret = -EFAULT;
       
   531             }
       
   532             break;
       
   533 
       
   534         case TIOCSSERIAL: // TODO
       
   535             break;
       
   536 
       
   537         default:
       
   538 #if EC_TTY_DEBUG >= 2
       
   539             printk(KERN_INFO PFX "no ioctl() -> handled by tty core!\n");
       
   540 #endif
       
   541             ret = -ENOIOCTLCMD;
       
   542             break;
       
   543     }
       
   544 
       
   545     return ret;
       
   546 }
       
   547 
       
   548 /*****************************************************************************/
       
   549 
       
   550 static void ec_tty_set_termios(struct tty_struct *tty,
       
   551         struct ktermios *old_termios)
       
   552 {
       
   553     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
       
   554     int ret;
       
   555 
   457 #if EC_TTY_DEBUG >= 2
   556 #if EC_TTY_DEBUG >= 2
   458     printk(KERN_INFO PFX "%s().\n", __func__);
   557     printk(KERN_INFO PFX "%s().\n", __func__);
   459 #endif
   558 #endif
   460     return -ENOTTY;
   559 
   461 }
   560     if (tty->termios->c_cflag == old_termios->c_cflag)
   462 
   561         return;
   463 /*****************************************************************************/
   562 
   464 
   563 #if EC_TTY_DEBUG >= 2
   465 static void ec_tty_throttle(struct tty_struct *tty)
   564     printk(KERN_INFO "cflag changed from %x to %x.\n",
   466 {
   565             old_termios->c_cflag, tty->termios->c_cflag);
   467 #if EC_TTY_DEBUG >= 2
   566 #endif
   468     printk(KERN_INFO PFX "%s().\n", __func__);
   567 
   469 #endif
   568     ret = t->ops.cflag_changed(t->cb_data, tty->termios->c_cflag);
   470 }
   569     if (ret) {
   471 
   570         printk(KERN_ERR PFX "ERROR: cflag 0x%x not accepted.\n",
   472 /*****************************************************************************/
   571                 tty->termios->c_cflag);
   473 
   572         tty->termios->c_cflag = old_termios->c_cflag;
   474 static void ec_tty_unthrottle(struct tty_struct *tty)
   573     }
   475 {
       
   476 #if EC_TTY_DEBUG >= 2
       
   477     printk(KERN_INFO PFX "%s().\n", __func__);
       
   478 #endif
       
   479 }
       
   480 
       
   481 /*****************************************************************************/
       
   482 
       
   483 static void ec_tty_set_termios(struct tty_struct *tty,
       
   484 			   struct ktermios *old_termios)
       
   485 {
       
   486 #if EC_TTY_DEBUG >= 2
       
   487     printk(KERN_INFO PFX "%s().\n", __func__);
       
   488 #endif
       
   489 }
   574 }
   490 
   575 
   491 /*****************************************************************************/
   576 /*****************************************************************************/
   492 
   577 
   493 static void ec_tty_stop(struct tty_struct *tty)
   578 static void ec_tty_stop(struct tty_struct *tty)
   550 #endif
   635 #endif
   551 }
   636 }
   552 
   637 
   553 /*****************************************************************************/
   638 /*****************************************************************************/
   554 
   639 
   555 static int ec_tty_tiocmget(struct tty_struct *tty, struct file *file)
       
   556 {
       
   557 #if EC_TTY_DEBUG >= 2
       
   558     printk(KERN_INFO PFX "%s().\n", __func__);
       
   559 #endif
       
   560     return -EBUSY;
       
   561 }
       
   562 
       
   563 /*****************************************************************************/
       
   564 
       
   565 static int ec_tty_tiocmset(struct tty_struct *tty, struct file *file,
       
   566 		    unsigned int set, unsigned int clear)
       
   567 {
       
   568 #if EC_TTY_DEBUG >= 2
       
   569     printk(KERN_INFO PFX "%s(set=%u, clear=%u).\n", __func__, set, clear);
       
   570 #endif
       
   571     return -EBUSY;
       
   572 }
       
   573 
       
   574 /*****************************************************************************/
       
   575 
       
   576 static const struct tty_operations ec_tty_ops = {
   640 static const struct tty_operations ec_tty_ops = {
   577     .open = ec_tty_open,
   641     .open = ec_tty_open,
   578     .close = ec_tty_close,
   642     .close = ec_tty_close,
   579     .write = ec_tty_write,
   643     .write = ec_tty_write,
   580 	.put_char = ec_tty_put_char,
   644     .put_char = ec_tty_put_char,
   581 	.write_room = ec_tty_write_room,
   645     .write_room = ec_tty_write_room,
   582 	.chars_in_buffer = ec_tty_chars_in_buffer,
   646     .chars_in_buffer = ec_tty_chars_in_buffer,
   583 	.flush_buffer = ec_tty_flush_buffer,
   647     .flush_buffer = ec_tty_flush_buffer,
   584 	.ioctl = ec_tty_ioctl,
   648     .ioctl = ec_tty_ioctl,
   585 	.throttle = ec_tty_throttle,
   649     .set_termios = ec_tty_set_termios,
   586 	.unthrottle = ec_tty_unthrottle,
   650     .stop = ec_tty_stop,
   587 	.set_termios = ec_tty_set_termios,
   651     .start = ec_tty_start,
   588 	.stop = ec_tty_stop,
   652     .hangup = ec_tty_hangup,
   589 	.start = ec_tty_start,
   653     .break_ctl = ec_tty_break,
   590 	.hangup = ec_tty_hangup,
   654     .send_xchar = ec_tty_send_xchar,
   591 	.break_ctl = ec_tty_break,
   655     .wait_until_sent = ec_tty_wait_until_sent,
   592 	.send_xchar = ec_tty_send_xchar,
       
   593 	.wait_until_sent = ec_tty_wait_until_sent,
       
   594 	.tiocmget = ec_tty_tiocmget,
       
   595 	.tiocmset = ec_tty_tiocmset,
       
   596 };
   656 };
   597 
   657 
   598 /******************************************************************************
   658 /******************************************************************************
   599  * Public functions and methods
   659  * Public functions and methods
   600  *****************************************************************************/
   660  *****************************************************************************/
   601 
   661 
   602 ec_tty_t *ectty_create(void)
   662 ec_tty_t *ectty_create(const ec_tty_operations_t *ops, void *cb_data)
   603 {
   663 {
   604     ec_tty_t *tty;
   664     ec_tty_t *tty;
   605     int minor, ret;
   665     int minor, ret;
   606 
   666 
   607     if (down_interruptible(&tty_sem)) {
   667     if (down_interruptible(&tty_sem)) {
   617                 up(&tty_sem);
   677                 up(&tty_sem);
   618                 printk(KERN_ERR PFX "Failed to allocate memory.\n");
   678                 printk(KERN_ERR PFX "Failed to allocate memory.\n");
   619                 return ERR_PTR(-ENOMEM);
   679                 return ERR_PTR(-ENOMEM);
   620             }
   680             }
   621 
   681 
   622             ret = ec_tty_init(tty, minor);
   682             ret = ec_tty_init(tty, minor, ops, cb_data);
   623             if (ret) {
   683             if (ret) {
   624                 up(&tty_sem);
   684                 up(&tty_sem);
   625                 kfree(tty);
   685                 kfree(tty);
   626                 return ERR_PTR(ret);
   686                 return ERR_PTR(ret);
   627             }
   687             }
   691             printk(KERN_WARNING PFX "Dropping %u bytes.\n", size - to_recv);
   751             printk(KERN_WARNING PFX "Dropping %u bytes.\n", size - to_recv);
   692         }
   752         }
   693 
   753 
   694         for (i = 0; i < size; i++) {
   754         for (i = 0; i < size; i++) {
   695             tty->rx_buffer[tty->rx_write_idx] = buffer[i];
   755             tty->rx_buffer[tty->rx_write_idx] = buffer[i];
   696             tty->rx_write_idx = (tty->rx_write_idx + 1) % EC_TTY_RX_BUFFER_SIZE;
   756             tty->rx_write_idx =
       
   757                 (tty->rx_write_idx + 1) % EC_TTY_RX_BUFFER_SIZE;
   697         }
   758         }
   698     }
   759     }
   699 }
   760 }
   700 
   761 
   701 /*****************************************************************************/
   762 /*****************************************************************************/