tty/module.c
changeset 1575 17598f2332b6
parent 1572 b306e6976682
child 1577 fa3f66b783c1
equal deleted inserted replaced
1574:be344b8ca0e8 1575:17598f2332b6
    36 #include <linux/module.h>
    36 #include <linux/module.h>
    37 #include <linux/err.h>
    37 #include <linux/err.h>
    38 #include <linux/tty.h>
    38 #include <linux/tty.h>
    39 #include <linux/tty_driver.h>
    39 #include <linux/tty_driver.h>
    40 #include <linux/termios.h>
    40 #include <linux/termios.h>
       
    41 #include <linux/timer.h>
    41 
    42 
    42 #include "../master/globals.h"
    43 #include "../master/globals.h"
    43 #include "../include/ectty.h"
    44 #include "../include/ectty.h"
    44 
    45 
    45 /*****************************************************************************/
    46 /*****************************************************************************/
    46 
    47 
    47 #define PFX "ec_tty: "
    48 #define PFX "ec_tty: "
    48 
    49 
    49 #define EC_TTY_MAX_DEVICES 10
    50 #define EC_TTY_MAX_DEVICES 10
       
    51 #define EC_TTY_TX_BUFFER_SIZE 100
    50 
    52 
    51 /*****************************************************************************/
    53 /*****************************************************************************/
    52 
    54 
    53 char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */
    55 char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */
    54 unsigned int debug_level = 0;
    56 unsigned int debug_level = 0;
    68 
    70 
    69 module_param_named(debug_level, debug_level, uint, S_IRUGO);
    71 module_param_named(debug_level, debug_level, uint, S_IRUGO);
    70 MODULE_PARM_DESC(debug_level, "Debug level");
    72 MODULE_PARM_DESC(debug_level, "Debug level");
    71 
    73 
    72 /** \endcond */
    74 /** \endcond */
    73 
       
    74 static int ec_tty_open(struct tty_struct *, struct file *);
       
    75 static void ec_tty_close(struct tty_struct *, struct file *);
       
    76 static int ec_tty_write(struct tty_struct *, const unsigned char *, int);
       
    77 
       
    78 static const struct tty_operations ec_tty_ops = {
       
    79     .open = ec_tty_open,
       
    80     .close = ec_tty_close,
       
    81     .write = ec_tty_write,
       
    82 };
       
    83 
    75 
    84 static struct ktermios ec_tty_std_termios = {
    76 static struct ktermios ec_tty_std_termios = {
    85     .c_iflag = ICRNL | IXON,
    77     .c_iflag = ICRNL | IXON,
    86     .c_oflag = OPOST | ONLCR,
    78     .c_oflag = OPOST | ONLCR,
    87     .c_cflag = B38400 | CS8 | CREAD | HUPCL,
    79     .c_cflag = B38400 | CS8 | CREAD | HUPCL,
    90 };
    82 };
    91 
    83 
    92 struct ec_tty {
    84 struct ec_tty {
    93     int minor;
    85     int minor;
    94     struct device *dev;
    86     struct device *dev;
       
    87     uint8_t tx_buffer[EC_TTY_TX_BUFFER_SIZE];
       
    88     unsigned int tx_read_idx;
       
    89     unsigned int tx_write_idx;
       
    90     unsigned int wakeup;
       
    91     struct timer_list timer;
       
    92     struct tty_struct *tty;
    95 };
    93 };
       
    94 
       
    95 static const struct tty_operations ec_tty_ops; // see below
    96 
    96 
    97 /*****************************************************************************/
    97 /*****************************************************************************/
    98 
    98 
    99 /** Module initialization.
    99 /** Module initialization.
   100  *
   100  *
   158     printk(KERN_INFO PFX "Module unloading.\n");
   158     printk(KERN_INFO PFX "Module unloading.\n");
   159 }
   159 }
   160 
   160 
   161 /*****************************************************************************/
   161 /*****************************************************************************/
   162 
   162 
       
   163 void ec_tty_wakeup(unsigned long data)
       
   164 {
       
   165     ec_tty_t *tty = (ec_tty_t *) data;
       
   166 
       
   167     if (tty->wakeup) {
       
   168         if (tty->tty) {
       
   169             printk("Waking up.\n");
       
   170             tty_wakeup(tty->tty);
       
   171         }
       
   172         tty->wakeup = 0;
       
   173     }
       
   174 
       
   175     tty->timer.expires += 1;
       
   176     add_timer(&tty->timer);
       
   177 }
       
   178 
       
   179 /*****************************************************************************/
       
   180 
   163 int ec_tty_init(ec_tty_t *tty, int minor)
   181 int ec_tty_init(ec_tty_t *tty, int minor)
   164 {
   182 {
   165     tty->minor = minor;
   183     tty->minor = minor;
       
   184     tty->tx_read_idx = 0;
       
   185     tty->tx_write_idx = 0;
       
   186     tty->wakeup = 0;
       
   187     init_timer(&tty->timer);
       
   188     tty->tty = NULL;
   166 
   189 
   167     tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
   190     tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
   168     if (IS_ERR(tty->dev)) {
   191     if (IS_ERR(tty->dev)) {
   169         printk(KERN_ERR PFX "Failed to register tty device.\n");
   192         printk(KERN_ERR PFX "Failed to register tty device.\n");
   170         return PTR_ERR(tty->dev);
   193         return PTR_ERR(tty->dev);
   171     }
   194     }
   172 
   195 
       
   196     tty->timer.function = ec_tty_wakeup;
       
   197     tty->timer.data = (unsigned long) tty;
       
   198     tty->timer.expires = jiffies + 10;
       
   199     add_timer(&tty->timer);
   173     return 0;
   200     return 0;
   174 }
   201 }
   175 
   202 
   176 /*****************************************************************************/
   203 /*****************************************************************************/
   177 
   204 
   178 void ec_tty_clear(ec_tty_t *tty)
   205 void ec_tty_clear(ec_tty_t *tty)
   179 {
   206 {
       
   207     del_timer_sync(&tty->timer);
   180     tty_unregister_device(tty_driver, tty->minor);
   208     tty_unregister_device(tty_driver, tty->minor);
       
   209 }
       
   210 
       
   211 /*****************************************************************************/
       
   212 
       
   213 unsigned int ec_tty_tx_size(ec_tty_t *tty)
       
   214 {
       
   215     unsigned int ret;
       
   216     
       
   217     if (tty->tx_write_idx >= tty->tx_read_idx) {
       
   218         ret = tty->tx_write_idx - tty->tx_read_idx;
       
   219     } else {
       
   220         ret = EC_TTY_TX_BUFFER_SIZE + tty->tx_write_idx - tty->tx_read_idx;
       
   221     }
       
   222 
       
   223     return ret;
       
   224 }
       
   225 
       
   226 /*****************************************************************************/
       
   227 
       
   228 unsigned int ec_tty_tx_space(ec_tty_t *tty)
       
   229 {
       
   230     return EC_TTY_TX_BUFFER_SIZE - 1 - ec_tty_tx_size(tty);
   181 }
   231 }
   182 
   232 
   183 /******************************************************************************
   233 /******************************************************************************
   184  * Device callbacks
   234  * Device callbacks
   185  *****************************************************************************/
   235  *****************************************************************************/
   198     t = ttys[line];
   248     t = ttys[line];
   199     if (!t) {
   249     if (!t) {
   200         return -ENXIO;
   250         return -ENXIO;
   201     }
   251     }
   202 
   252 
       
   253     if (t->tty) {
       
   254         return -EBUSY;
       
   255     }
       
   256 
       
   257     t->tty = tty;
   203     tty->driver_data = t;
   258     tty->driver_data = t;
   204     return 0;
   259     return 0;
   205 }
   260 }
   206 
   261 
   207 /*****************************************************************************/
   262 /*****************************************************************************/
   208 
   263 
   209 static void ec_tty_close(struct tty_struct *tty, struct file *file)
   264 static void ec_tty_close(struct tty_struct *tty, struct file *file)
   210 {
   265 {
       
   266     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
       
   267 
   211     printk(KERN_INFO PFX "Closing line %i.\n", tty->index);
   268     printk(KERN_INFO PFX "Closing line %i.\n", tty->index);
       
   269 
       
   270     if (t->tty == tty) {
       
   271         t->tty = NULL;
       
   272     }
   212 }
   273 }
   213 
   274 
   214 /*****************************************************************************/
   275 /*****************************************************************************/
   215 
   276 
   216 static int ec_tty_write(
   277 static int ec_tty_write(
   217         struct tty_struct *tty,
   278         struct tty_struct *tty,
   218         const unsigned char *buffer,
   279         const unsigned char *buffer,
   219         int count
   280         int count
   220         )
   281         )
   221 {
   282 {
   222     return -EIO;
   283     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
   223 }
   284     unsigned int data_size, i;
       
   285     
       
   286     printk(KERN_INFO PFX "%s(count=%i)\n", __func__, count);
       
   287 
       
   288     if (count <= 0) {
       
   289         return 0;
       
   290     }
       
   291 
       
   292     data_size = min(ec_tty_tx_space(t), (unsigned int) count);
       
   293     for (i = 0; i < data_size; i++) {
       
   294         t->tx_buffer[t->tx_write_idx] = buffer[i];
       
   295         t->tx_write_idx = (t->tx_write_idx + 1) % EC_TTY_TX_BUFFER_SIZE;
       
   296     }
       
   297 
       
   298     printk(KERN_INFO PFX "%s(): %u bytes written.\n", __func__, data_size);
       
   299     return data_size;
       
   300 }
       
   301 
       
   302 /*****************************************************************************/
       
   303 
       
   304 static void ec_tty_put_char(struct tty_struct *tty, unsigned char ch)
       
   305 {
       
   306     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
       
   307 
       
   308     printk(KERN_INFO PFX "%s(): c=%02x.\n", __func__, (unsigned int) ch);
       
   309 
       
   310     if (ec_tty_tx_space(t)) {
       
   311         t->tx_buffer[t->tx_write_idx] = ch;
       
   312         t->tx_write_idx = (t->tx_write_idx + 1) % EC_TTY_TX_BUFFER_SIZE;
       
   313     } else {
       
   314         printk(KERN_WARNING PFX "%s(): Dropped a byte!\n", __func__);
       
   315     }
       
   316 }
       
   317 
       
   318 /*****************************************************************************/
       
   319 
       
   320 static int ec_tty_write_room(struct tty_struct *tty)
       
   321 {
       
   322     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
       
   323     int ret = ec_tty_tx_space(t);
       
   324     
       
   325     printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret);
       
   326 
       
   327     return ret;
       
   328 }
       
   329 
       
   330 /*****************************************************************************/
       
   331 
       
   332 static int ec_tty_chars_in_buffer(struct tty_struct *tty)
       
   333 {
       
   334     ec_tty_t *t = (ec_tty_t *) tty->driver_data;
       
   335     int ret;
       
   336     
       
   337     printk(KERN_INFO PFX "%s().\n", __func__);
       
   338 
       
   339     ret = ec_tty_tx_size(t);
       
   340 
       
   341     printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret);
       
   342     
       
   343     return ret;
       
   344 }
       
   345 
       
   346 /*****************************************************************************/
       
   347 
       
   348 static void ec_tty_flush_buffer(struct tty_struct *tty)
       
   349 {
       
   350     printk(KERN_INFO PFX "%s().\n", __func__);
       
   351 }
       
   352 
       
   353 /*****************************************************************************/
       
   354 
       
   355 static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
       
   356 		    unsigned int cmd, unsigned long arg)
       
   357 {
       
   358     printk(KERN_INFO PFX "%s().\n", __func__);
       
   359     return -ENOTTY;
       
   360 }
       
   361 
       
   362 /*****************************************************************************/
       
   363 
       
   364 static void ec_tty_throttle(struct tty_struct *tty)
       
   365 {
       
   366     printk(KERN_INFO PFX "%s().\n", __func__);
       
   367 }
       
   368 
       
   369 /*****************************************************************************/
       
   370 
       
   371 static void ec_tty_unthrottle(struct tty_struct *tty)
       
   372 {
       
   373     printk(KERN_INFO PFX "%s().\n", __func__);
       
   374 }
       
   375 
       
   376 /*****************************************************************************/
       
   377 
       
   378 static void ec_tty_set_termios(struct tty_struct *tty,
       
   379 			   struct ktermios *old_termios)
       
   380 {
       
   381     printk(KERN_INFO PFX "%s().\n", __func__);
       
   382 }
       
   383 
       
   384 /*****************************************************************************/
       
   385 
       
   386 static void ec_tty_stop(struct tty_struct *tty)
       
   387 {
       
   388     printk(KERN_INFO PFX "%s().\n", __func__);
       
   389 }
       
   390 
       
   391 /*****************************************************************************/
       
   392 
       
   393 static void ec_tty_start(struct tty_struct *tty)
       
   394 {
       
   395     printk(KERN_INFO PFX "%s().\n", __func__);
       
   396 }
       
   397 
       
   398 /*****************************************************************************/
       
   399 
       
   400 static void ec_tty_hangup(struct tty_struct *tty)
       
   401 {
       
   402     printk(KERN_INFO PFX "%s().\n", __func__);
       
   403 }
       
   404 
       
   405 /*****************************************************************************/
       
   406 
       
   407 static void ec_tty_break(struct tty_struct *tty, int break_state)
       
   408 {
       
   409     printk(KERN_INFO PFX "%s(break_state = %i).\n", __func__, break_state);
       
   410 }
       
   411 
       
   412 /*****************************************************************************/
       
   413 
       
   414 static void ec_tty_send_xchar(struct tty_struct *tty, char ch)
       
   415 {
       
   416     printk(KERN_INFO PFX "%s(ch=%02x).\n", __func__, (unsigned int) ch);
       
   417 }
       
   418 
       
   419 /*****************************************************************************/
       
   420 
       
   421 static void ec_tty_wait_until_sent(struct tty_struct *tty, int timeout)
       
   422 {
       
   423     printk(KERN_INFO PFX "%s(timeout=%i).\n", __func__, timeout);
       
   424 }
       
   425 
       
   426 /*****************************************************************************/
       
   427 
       
   428 static int ec_tty_tiocmget(struct tty_struct *tty, struct file *file)
       
   429 {
       
   430     printk(KERN_INFO PFX "%s().\n", __func__);
       
   431     return -EBUSY;
       
   432 }
       
   433 
       
   434 /*****************************************************************************/
       
   435 
       
   436 static int ec_tty_tiocmset(struct tty_struct *tty, struct file *file,
       
   437 		    unsigned int set, unsigned int clear)
       
   438 {
       
   439     printk(KERN_INFO PFX "%s(set=%u, clear=%u).\n", __func__, set, clear);
       
   440     return -EBUSY;
       
   441 }
       
   442 
       
   443 /*****************************************************************************/
       
   444 
       
   445 static const struct tty_operations ec_tty_ops = {
       
   446     .open = ec_tty_open,
       
   447     .close = ec_tty_close,
       
   448     .write = ec_tty_write,
       
   449 	.put_char = ec_tty_put_char,
       
   450 	.write_room = ec_tty_write_room,
       
   451 	.chars_in_buffer = ec_tty_chars_in_buffer,
       
   452 	.flush_buffer = ec_tty_flush_buffer,
       
   453 	.ioctl = ec_tty_ioctl,
       
   454 	.throttle = ec_tty_throttle,
       
   455 	.unthrottle = ec_tty_unthrottle,
       
   456 	.set_termios = ec_tty_set_termios,
       
   457 	.stop = ec_tty_stop,
       
   458 	.start = ec_tty_start,
       
   459 	.hangup = ec_tty_hangup,
       
   460 	.break_ctl = ec_tty_break,
       
   461 	.send_xchar = ec_tty_send_xchar,
       
   462 	.wait_until_sent = ec_tty_wait_until_sent,
       
   463 	.tiocmget = ec_tty_tiocmget,
       
   464 	.tiocmset = ec_tty_tiocmset,
       
   465 };
   224 
   466 
   225 /******************************************************************************
   467 /******************************************************************************
   226  * Public functions and methods
   468  * Public functions and methods
   227  *****************************************************************************/
   469  *****************************************************************************/
   228 
   470 
   235         return ERR_PTR(-EINTR);
   477         return ERR_PTR(-EINTR);
   236     }
   478     }
   237 
   479 
   238     for (minor = 0; minor < EC_TTY_MAX_DEVICES; minor++) {
   480     for (minor = 0; minor < EC_TTY_MAX_DEVICES; minor++) {
   239         if (!ttys[minor]) {
   481         if (!ttys[minor]) {
       
   482             printk(KERN_INFO PFX "Creating TTY interface %i.\n", minor);
       
   483 
   240             tty = kmalloc(sizeof(ec_tty_t), GFP_KERNEL);
   484             tty = kmalloc(sizeof(ec_tty_t), GFP_KERNEL);
   241             if (!tty) {
   485             if (!tty) {
   242                 up(&tty_sem);
   486                 up(&tty_sem);
   243                 printk(KERN_ERR PFX "Failed to allocate memory.\n");
   487                 printk(KERN_ERR PFX "Failed to allocate memory.\n");
   244                 return ERR_PTR(-ENOMEM);
   488                 return ERR_PTR(-ENOMEM);
   264 
   508 
   265 /*****************************************************************************/
   509 /*****************************************************************************/
   266 
   510 
   267 void ectty_free(ec_tty_t *tty)
   511 void ectty_free(ec_tty_t *tty)
   268 {
   512 {
       
   513     printk(KERN_INFO PFX "Freeing TTY interface %i.\n", tty->minor);
       
   514 
   269     ec_tty_clear(tty);
   515     ec_tty_clear(tty);
   270     ttys[tty->minor] = NULL;
   516     ttys[tty->minor] = NULL;
   271     kfree(tty);
   517     kfree(tty);
   272 }
   518 }
   273 
   519 
   274 /*****************************************************************************/
   520 /*****************************************************************************/
   275 
   521 
       
   522 unsigned int ectty_tx_data(ec_tty_t *tty, uint8_t *buffer, size_t size)
       
   523 {
       
   524     unsigned int data_size = min(ec_tty_tx_size(tty), size), i;
       
   525 
       
   526     if (data_size)  {
       
   527         printk(KERN_INFO PFX "Fetching %u bytes to send.\n", data_size);
       
   528     }
       
   529 
       
   530     for (i = 0; i < data_size; i++) {
       
   531         buffer[i] = tty->tx_buffer[tty->tx_read_idx];
       
   532         tty->tx_read_idx = (tty->tx_read_idx + 1) % EC_TTY_TX_BUFFER_SIZE;
       
   533     }
       
   534 
       
   535     if (data_size) {
       
   536         tty->wakeup = 1;
       
   537     }
       
   538 
       
   539     return data_size;
       
   540 }
       
   541 
       
   542 /*****************************************************************************/
       
   543 
   276 /** \cond */
   544 /** \cond */
   277 
   545 
   278 module_init(ec_tty_init_module);
   546 module_init(ec_tty_init_module);
   279 module_exit(ec_tty_cleanup_module);
   547 module_exit(ec_tty_cleanup_module);
   280 
   548 
   281 EXPORT_SYMBOL(ectty_create);
   549 EXPORT_SYMBOL(ectty_create);
   282 EXPORT_SYMBOL(ectty_free);
   550 EXPORT_SYMBOL(ectty_free);
       
   551 EXPORT_SYMBOL(ectty_tx_data);
   283 
   552 
   284 /** \endcond */
   553 /** \endcond */
   285 
   554 
   286 /*****************************************************************************/
   555 /*****************************************************************************/