63 char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */ |
63 char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */ |
64 unsigned int debug_level = 0; |
64 unsigned int debug_level = 0; |
65 |
65 |
66 static struct tty_driver *tty_driver = NULL; |
66 static struct tty_driver *tty_driver = NULL; |
67 ec_tty_t *ttys[EC_TTY_MAX_DEVICES]; |
67 ec_tty_t *ttys[EC_TTY_MAX_DEVICES]; |
68 struct ec_mutex_t tty_sem; |
68 struct semaphore tty_sem; |
69 |
69 |
70 void ec_tty_wakeup(unsigned long); |
70 void ec_tty_wakeup(unsigned long); |
71 |
71 |
72 /*****************************************************************************/ |
72 /*****************************************************************************/ |
73 |
73 |
109 unsigned int rx_write_idx; |
109 unsigned int rx_write_idx; |
110 |
110 |
111 struct timer_list timer; |
111 struct timer_list timer; |
112 struct tty_struct *tty; |
112 struct tty_struct *tty; |
113 unsigned int open_count; |
113 unsigned int open_count; |
114 struct ec_mutex_t sem; |
114 struct semaphore sem; |
115 |
115 |
116 ec_tty_operations_t ops; |
116 ec_tty_operations_t ops; |
117 void *cb_data; |
117 void *cb_data; |
118 }; |
118 }; |
119 |
119 |
190 const ec_tty_operations_t *ops, void *cb_data) |
190 const ec_tty_operations_t *ops, void *cb_data) |
191 { |
191 { |
192 int ret; |
192 int ret; |
193 tcflag_t cflag; |
193 tcflag_t cflag; |
194 struct tty_struct *tty; |
194 struct tty_struct *tty; |
|
195 struct ktermios *termios; |
195 |
196 |
196 t->minor = minor; |
197 t->minor = minor; |
197 t->tx_read_idx = 0; |
198 t->tx_read_idx = 0; |
198 t->tx_write_idx = 0; |
199 t->tx_write_idx = 0; |
199 t->wakeup = 0; |
200 t->wakeup = 0; |
200 t->rx_read_idx = 0; |
201 t->rx_read_idx = 0; |
201 t->rx_write_idx = 0; |
202 t->rx_write_idx = 0; |
202 init_timer(&t->timer); |
203 init_timer(&t->timer); |
203 t->tty = NULL; |
204 t->tty = NULL; |
204 t->open_count = 0; |
205 t->open_count = 0; |
205 ec_mutex_init(&t->sem); |
206 sema_init(&t->sem, 1); |
206 t->ops = *ops; |
207 t->ops = *ops; |
207 t->cb_data = cb_data; |
208 t->cb_data = cb_data; |
208 |
209 |
209 t->dev = tty_register_device(tty_driver, t->minor, NULL); |
210 t->dev = tty_register_device(tty_driver, t->minor, NULL); |
210 if (IS_ERR(t->dev)) { |
211 if (IS_ERR(t->dev)) { |
213 } |
214 } |
214 |
215 |
215 // Tell the device-specific implementation about the initial cflags |
216 // Tell the device-specific implementation about the initial cflags |
216 tty = tty_driver->ttys[minor]; |
217 tty = tty_driver->ttys[minor]; |
217 |
218 |
218 if (tty && tty->termios) { // already opened before |
219 termios = |
219 cflag = tty->termios->c_cflag; |
220 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) |
|
221 &tty->termios |
|
222 #else |
|
223 tty->termios |
|
224 #endif |
|
225 ; |
|
226 |
|
227 if (tty && termios) { // already opened before |
|
228 cflag = termios->c_cflag; |
220 } else { |
229 } else { |
221 cflag = tty_driver->init_termios.c_cflag; |
230 cflag = tty_driver->init_termios.c_cflag; |
222 } |
231 } |
223 ret = t->ops.cflag_changed(t->cb_data, cflag); |
232 ret = t->ops.cflag_changed(t->cb_data, cflag); |
224 if (ret) { |
233 if (ret) { |
407 printk(KERN_INFO PFX "%s(tty=%p, file=%p): Closing line %i.\n", |
416 printk(KERN_INFO PFX "%s(tty=%p, file=%p): Closing line %i.\n", |
408 __func__, tty, file, tty->index); |
417 __func__, tty, file, tty->index); |
409 #endif |
418 #endif |
410 |
419 |
411 if (t) { |
420 if (t) { |
412 ec_mutex_lock(&t->sem); |
421 down(&t->sem); |
413 if (--t->open_count == 0) { |
422 if (--t->open_count == 0) { |
414 t->tty = NULL; |
423 t->tty = NULL; |
415 } |
424 } |
416 ec_mutex_unlock(&t->sem); |
425 up(&t->sem); |
417 } |
426 } |
418 } |
427 } |
419 |
428 |
420 /*****************************************************************************/ |
429 /*****************************************************************************/ |
421 |
430 |
480 |
489 |
481 static int ec_tty_write_room(struct tty_struct *tty) |
490 static int ec_tty_write_room(struct tty_struct *tty) |
482 { |
491 { |
483 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
492 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
484 int ret = ec_tty_tx_space(t); |
493 int ret = ec_tty_tx_space(t); |
485 |
494 |
486 #if EC_TTY_DEBUG >= 2 |
495 #if EC_TTY_DEBUG >= 2 |
487 printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret); |
496 printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret); |
488 #endif |
497 #endif |
489 |
498 |
490 return ret; |
499 return ret; |
494 |
503 |
495 static int ec_tty_chars_in_buffer(struct tty_struct *tty) |
504 static int ec_tty_chars_in_buffer(struct tty_struct *tty) |
496 { |
505 { |
497 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
506 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
498 int ret; |
507 int ret; |
499 |
508 |
500 #if EC_TTY_DEBUG >= 2 |
509 #if EC_TTY_DEBUG >= 2 |
501 printk(KERN_INFO PFX "%s().\n", __func__); |
510 printk(KERN_INFO PFX "%s().\n", __func__); |
502 #endif |
511 #endif |
503 |
512 |
504 ret = ec_tty_tx_size(t); |
513 ret = ec_tty_tx_size(t); |
505 |
514 |
506 #if EC_TTY_DEBUG >= 2 |
515 #if EC_TTY_DEBUG >= 2 |
507 printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret); |
516 printk(KERN_INFO PFX "%s() = %i.\n", __func__, ret); |
508 #endif |
517 #endif |
509 |
518 |
510 return ret; |
519 return ret; |
511 } |
520 } |
512 |
521 |
513 /*****************************************************************************/ |
522 /*****************************************************************************/ |
514 |
523 |
521 // FIXME empty ring buffer |
530 // FIXME empty ring buffer |
522 } |
531 } |
523 |
532 |
524 /*****************************************************************************/ |
533 /*****************************************************************************/ |
525 |
534 |
526 static int ec_tty_ioctl(struct tty_struct *tty, struct file *file, |
535 static int ec_tty_ioctl(struct tty_struct *tty, |
|
536 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) |
|
537 struct file *file, |
|
538 #endif |
527 unsigned int cmd, unsigned long arg) |
539 unsigned int cmd, unsigned long arg) |
528 { |
540 { |
529 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
541 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
530 int ret = -ENOTTY; |
542 int ret = -ENOTTY; |
531 |
543 |
532 #if EC_TTY_DEBUG >= 2 |
544 #if EC_TTY_DEBUG >= 2 |
533 printk(KERN_INFO PFX "%s(tty=%p, file=%p, cmd=%08x, arg=%08lx).\n", |
545 printk(KERN_INFO PFX "%s(tty=%p, " |
534 __func__, tty, file, cmd, arg); |
546 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) |
|
547 "file=%p, " |
|
548 #endif |
|
549 "cmd=%08x, arg=%08lx).\n", |
|
550 __func__, tty, |
|
551 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) |
|
552 file, |
|
553 #endif |
|
554 cmd, arg); |
535 printk(KERN_INFO PFX "decoded: type=%02x nr=%u\n", |
555 printk(KERN_INFO PFX "decoded: type=%02x nr=%u\n", |
536 _IOC_TYPE(cmd), _IOC_NR(cmd)); |
556 _IOC_TYPE(cmd), _IOC_NR(cmd)); |
537 #endif |
557 #endif |
538 |
558 |
539 switch (cmd) { |
559 switch (cmd) { |
562 static void ec_tty_set_termios(struct tty_struct *tty, |
582 static void ec_tty_set_termios(struct tty_struct *tty, |
563 struct ktermios *old_termios) |
583 struct ktermios *old_termios) |
564 { |
584 { |
565 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
585 ec_tty_t *t = (ec_tty_t *) tty->driver_data; |
566 int ret; |
586 int ret; |
|
587 struct ktermios *termios; |
567 |
588 |
568 #if EC_TTY_DEBUG >= 2 |
589 #if EC_TTY_DEBUG >= 2 |
569 printk(KERN_INFO PFX "%s().\n", __func__); |
590 printk(KERN_INFO PFX "%s().\n", __func__); |
570 #endif |
591 #endif |
571 |
592 |
572 if (tty->termios->c_cflag == old_termios->c_cflag) |
593 termios = |
|
594 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) |
|
595 &tty->termios |
|
596 #else |
|
597 tty->termios |
|
598 #endif |
|
599 ; |
|
600 |
|
601 if (termios->c_cflag == old_termios->c_cflag) |
573 return; |
602 return; |
574 |
603 |
575 #if EC_TTY_DEBUG >= 2 |
604 #if EC_TTY_DEBUG >= 2 |
576 printk(KERN_INFO "cflag changed from %x to %x.\n", |
605 printk(KERN_INFO "cflag changed from %x to %x.\n", |
577 old_termios->c_cflag, tty->termios->c_cflag); |
606 old_termios->c_cflag, termios->c_cflag); |
578 #endif |
607 #endif |
579 |
608 |
580 ret = t->ops.cflag_changed(t->cb_data, tty->termios->c_cflag); |
609 ret = t->ops.cflag_changed(t->cb_data, termios->c_cflag); |
581 if (ret) { |
610 if (ret) { |
582 printk(KERN_ERR PFX "ERROR: cflag 0x%x not accepted.\n", |
611 printk(KERN_ERR PFX "ERROR: cflag 0x%x not accepted.\n", |
583 tty->termios->c_cflag); |
612 termios->c_cflag); |
584 tty->termios->c_cflag = old_termios->c_cflag; |
613 termios->c_cflag = old_termios->c_cflag; |
585 } |
614 } |
586 } |
615 } |
587 |
616 |
588 /*****************************************************************************/ |
617 /*****************************************************************************/ |
589 |
618 |
674 ec_tty_t *ectty_create(const ec_tty_operations_t *ops, void *cb_data) |
703 ec_tty_t *ectty_create(const ec_tty_operations_t *ops, void *cb_data) |
675 { |
704 { |
676 ec_tty_t *tty; |
705 ec_tty_t *tty; |
677 int minor, ret; |
706 int minor, ret; |
678 |
707 |
679 if (ec_mutex_lock_interruptible(&tty_sem)) { |
708 if (down_interruptible(&tty_sem)) { |
680 return ERR_PTR(-EINTR); |
709 return ERR_PTR(-EINTR); |
681 } |
710 } |
682 |
711 |
683 for (minor = 0; minor < EC_TTY_MAX_DEVICES; minor++) { |
712 for (minor = 0; minor < EC_TTY_MAX_DEVICES; minor++) { |
684 if (!ttys[minor]) { |
713 if (!ttys[minor]) { |
685 printk(KERN_INFO PFX "Creating TTY interface %i.\n", minor); |
714 printk(KERN_INFO PFX "Creating TTY interface %i.\n", minor); |
686 |
715 |
687 tty = kmalloc(sizeof(ec_tty_t), GFP_KERNEL); |
716 tty = kmalloc(sizeof(ec_tty_t), GFP_KERNEL); |
688 if (!tty) { |
717 if (!tty) { |
689 ec_mutex_unlock(&tty_sem); |
718 up(&tty_sem); |
690 printk(KERN_ERR PFX "Failed to allocate memory.\n"); |
719 printk(KERN_ERR PFX "Failed to allocate memory.\n"); |
691 return ERR_PTR(-ENOMEM); |
720 return ERR_PTR(-ENOMEM); |
692 } |
721 } |
693 |
722 |
694 ret = ec_tty_init(tty, minor, ops, cb_data); |
723 ret = ec_tty_init(tty, minor, ops, cb_data); |
695 if (ret) { |
724 if (ret) { |
696 ec_mutex_unlock(&tty_sem); |
725 up(&tty_sem); |
697 kfree(tty); |
726 kfree(tty); |
698 return ERR_PTR(ret); |
727 return ERR_PTR(ret); |
699 } |
728 } |
700 |
729 |
701 ttys[minor] = tty; |
730 ttys[minor] = tty; |
702 ec_mutex_unlock(&tty_sem); |
731 up(&tty_sem); |
703 return tty; |
732 return tty; |
704 } |
733 } |
705 } |
734 } |
706 |
735 |
707 ec_mutex_unlock(&tty_sem); |
736 up(&tty_sem); |
708 printk(KERN_ERR PFX "No free interfaces avaliable.\n"); |
737 printk(KERN_ERR PFX "No free interfaces avaliable.\n"); |
709 return ERR_PTR(-EBUSY); |
738 return ERR_PTR(-EBUSY); |
710 } |
739 } |
711 |
740 |
712 /*****************************************************************************/ |
741 /*****************************************************************************/ |