tty_ldisc.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #include <tty.h>
  2. #include <tty_ldisc.h>
  3. #define DBG_TAG "TTY_LDISC"
  4. #ifdef RT_TTY_DEBUG
  5. #define DBG_LVL DBG_LOG
  6. #else
  7. #define DBG_LVL DBG_INFO
  8. #endif /* RT_TTY_DEBUG */
  9. #include <rtdbg.h>
  10. extern struct tty_ldisc_ops n_tty_ops;
  11. static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS] = {
  12. &n_tty_ops, /* N_TTY = 0 */
  13. };
  14. static struct tty_ldisc_ops *get_ldops(int disc)
  15. {
  16. struct tty_ldisc_ops *ldops = RT_NULL;
  17. int level = 0;
  18. level = rt_hw_interrupt_disable();
  19. ldops = tty_ldiscs[disc];
  20. if (ldops)
  21. {
  22. ldops->refcount++;
  23. }
  24. rt_hw_interrupt_enable(level);
  25. return ldops;
  26. }
  27. static void put_ldops(struct tty_ldisc_ops *ldops)
  28. {
  29. int level = 0;
  30. level = rt_hw_interrupt_disable();
  31. ldops->refcount--;
  32. rt_hw_interrupt_enable(level);
  33. }
  34. static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
  35. {
  36. struct tty_ldisc *ld = RT_NULL;
  37. struct tty_ldisc_ops *ldops = RT_NULL;
  38. if (disc < N_TTY || disc >= NR_LDISCS)
  39. {
  40. return RT_NULL;
  41. }
  42. ldops = get_ldops(disc);
  43. if (ldops == RT_NULL)
  44. {
  45. LOG_E("tty ldisc get error\n");
  46. return RT_NULL;
  47. }
  48. ld = rt_malloc(sizeof(struct tty_ldisc));
  49. if (ld == RT_NULL)
  50. {
  51. ldops->refcount--;
  52. return RT_NULL;
  53. }
  54. ld->ops = ldops;
  55. ld->tty = tty;
  56. return ld;
  57. }
  58. /**
  59. * tty_ldisc_put - release the ldisc
  60. *
  61. * Complement of tty_ldisc_get().
  62. */
  63. static void tty_ldisc_put(struct tty_ldisc *ld)
  64. {
  65. if (ld)
  66. {
  67. put_ldops(ld->ops);
  68. rt_free(ld);
  69. }
  70. }
  71. /**
  72. * tty_ldisc_close - close a line discipline
  73. * @tty: tty we are opening the ldisc on
  74. * @ld: discipline to close
  75. *
  76. * A helper close method. Also a convenient debugging and check
  77. * point.
  78. */
  79. static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
  80. {
  81. if (ld && ld->ops->close)
  82. {
  83. ld->ops->close(tty);
  84. }
  85. }
  86. /**
  87. * tty_ldisc_kill - teardown ldisc
  88. * @tty: tty being released
  89. *
  90. * Perform final close of the ldisc and reset tty->ldisc
  91. */
  92. void tty_ldisc_kill(struct tty_struct *tty)
  93. {
  94. if (tty && tty->ldisc)
  95. {
  96. /*
  97. * Now kill off the ldisc
  98. */
  99. tty_ldisc_close(tty, tty->ldisc);
  100. tty_ldisc_put(tty->ldisc);
  101. /* Force an oops if we mess this up */
  102. tty->ldisc = NULL;
  103. }
  104. }
  105. int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
  106. {
  107. int ret = 0;
  108. int level = 0;
  109. if (disc < N_TTY || disc >= NR_LDISCS)
  110. {
  111. return -EINVAL;
  112. }
  113. level = rt_hw_interrupt_disable();
  114. tty_ldiscs[disc] = new_ldisc;
  115. new_ldisc->num = disc;
  116. new_ldisc->refcount = 0;
  117. rt_hw_interrupt_enable(level);
  118. return ret;
  119. }
  120. /**
  121. * tty_ldisc_release - release line discipline
  122. * @tty: tty being shut down (or one end of pty pair)
  123. *
  124. * Called during the final close of a tty or a pty pair in order to shut
  125. * down the line discpline layer. On exit, each tty's ldisc is NULL.
  126. */
  127. void tty_ldisc_release(struct tty_struct *tty)
  128. {
  129. int level = 0;
  130. struct tty_struct *o_tty = tty->other_struct;
  131. /*
  132. * Shutdown this line discipline. As this is the final close,
  133. * it does not race with the set_ldisc code path.
  134. */
  135. level = rt_hw_interrupt_disable();
  136. tty_ldisc_kill(tty);
  137. if (o_tty)
  138. {
  139. tty_ldisc_kill(o_tty);
  140. }
  141. rt_hw_interrupt_enable(level);
  142. }
  143. /**
  144. * tty_ldisc_init - ldisc setup for new tty
  145. * @tty: tty being allocated
  146. *
  147. * Set up the line discipline objects for a newly allocated tty. Note that
  148. * the tty structure is not completely set up when this call is made.
  149. */
  150. void tty_ldisc_init(struct tty_struct *tty)
  151. {
  152. if (tty)
  153. {
  154. tty->ldisc = tty_ldisc_get(tty, N_TTY);
  155. }
  156. }