picvue_proc.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Picvue PVC160206 display driver
  3. *
  4. * Brian Murphy <brian.murphy@eicon.com>
  5. *
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/module.h>
  9. #include <linux/init.h>
  10. #include <linux/errno.h>
  11. #include <linux/proc_fs.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/timer.h>
  14. #include "picvue.h"
  15. static char pvc_lines[PVC_NLINES][PVC_LINELEN+1];
  16. static int pvc_linedata[PVC_NLINES];
  17. static struct proc_dir_entry *pvc_display_dir;
  18. static char *pvc_linename[PVC_NLINES] = {"line1", "line2"};
  19. #define DISPLAY_DIR_NAME "display"
  20. static int scroll_dir = 0, scroll_interval = 0;
  21. static struct timer_list timer;
  22. static void pvc_display(unsigned long data) {
  23. int i;
  24. pvc_clear();
  25. for (i=0; i<PVC_NLINES; i++)
  26. pvc_write_string(pvc_lines[i], 0, i);
  27. }
  28. static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0);
  29. static int pvc_proc_read_line(char *page, char **start,
  30. off_t off, int count,
  31. int *eof, void *data)
  32. {
  33. char *origpage = page;
  34. int lineno = *(int *)data;
  35. if (lineno < 0 || lineno > PVC_NLINES) {
  36. printk("proc_read_line: invalid lineno %d\n", lineno);
  37. return 0;
  38. }
  39. down(&pvc_sem);
  40. page += sprintf(page, "%s\n", pvc_lines[lineno]);
  41. up(&pvc_sem);
  42. return page - origpage;
  43. }
  44. static int pvc_proc_write_line(struct file *file, const char *buffer,
  45. unsigned long count, void *data)
  46. {
  47. int origcount = count;
  48. int lineno = *(int *)data;
  49. if (lineno < 0 || lineno > PVC_NLINES) {
  50. printk("proc_write_line: invalid lineno %d\n", lineno);
  51. return origcount;
  52. }
  53. if (count > PVC_LINELEN)
  54. count = PVC_LINELEN;
  55. if (buffer[count-1] == '\n')
  56. count--;
  57. down(&pvc_sem);
  58. strncpy(pvc_lines[lineno], buffer, count);
  59. pvc_lines[lineno][count] = '\0';
  60. up(&pvc_sem);
  61. tasklet_schedule(&pvc_display_tasklet);
  62. return origcount;
  63. }
  64. static int pvc_proc_write_scroll(struct file *file, const char *buffer,
  65. unsigned long count, void *data)
  66. {
  67. int origcount = count;
  68. int cmd = simple_strtol(buffer, NULL, 10);
  69. down(&pvc_sem);
  70. if (scroll_interval != 0)
  71. del_timer(&timer);
  72. if (cmd == 0) {
  73. scroll_dir = 0;
  74. scroll_interval = 0;
  75. } else {
  76. if (cmd < 0) {
  77. scroll_dir = -1;
  78. scroll_interval = -cmd;
  79. } else {
  80. scroll_dir = 1;
  81. scroll_interval = cmd;
  82. }
  83. add_timer(&timer);
  84. }
  85. up(&pvc_sem);
  86. return origcount;
  87. }
  88. static int pvc_proc_read_scroll(char *page, char **start,
  89. off_t off, int count,
  90. int *eof, void *data)
  91. {
  92. char *origpage = page;
  93. down(&pvc_sem);
  94. page += sprintf(page, "%d\n", scroll_dir * scroll_interval);
  95. up(&pvc_sem);
  96. return page - origpage;
  97. }
  98. void pvc_proc_timerfunc(unsigned long data)
  99. {
  100. if (scroll_dir < 0)
  101. pvc_move(DISPLAY|RIGHT);
  102. else if (scroll_dir > 0)
  103. pvc_move(DISPLAY|LEFT);
  104. timer.expires = jiffies + scroll_interval;
  105. add_timer(&timer);
  106. }
  107. static void pvc_proc_cleanup(void)
  108. {
  109. int i;
  110. for (i=0; i<PVC_NLINES; i++)
  111. remove_proc_entry(pvc_linename[i], pvc_display_dir);
  112. remove_proc_entry("scroll", pvc_display_dir);
  113. remove_proc_entry(DISPLAY_DIR_NAME, NULL);
  114. del_timer(&timer);
  115. }
  116. static int __init pvc_proc_init(void)
  117. {
  118. struct proc_dir_entry *proc_entry;
  119. int i;
  120. pvc_display_dir = proc_mkdir(DISPLAY_DIR_NAME, NULL);
  121. if (pvc_display_dir == NULL)
  122. goto error;
  123. for (i=0; i<PVC_NLINES; i++) {
  124. strcpy(pvc_lines[i], "");
  125. pvc_linedata[i] = i;
  126. }
  127. for (i=0; i<PVC_NLINES; i++) {
  128. proc_entry = create_proc_entry(pvc_linename[i], 0644, pvc_display_dir);
  129. if (proc_entry == NULL)
  130. goto error;
  131. proc_entry->read_proc = pvc_proc_read_line;
  132. proc_entry->write_proc = pvc_proc_write_line;
  133. proc_entry->data = &pvc_linedata[i];
  134. }
  135. proc_entry = create_proc_entry("scroll", 0644, pvc_display_dir);
  136. if (proc_entry == NULL)
  137. goto error;
  138. proc_entry->write_proc = pvc_proc_write_scroll;
  139. proc_entry->read_proc = pvc_proc_read_scroll;
  140. init_timer(&timer);
  141. timer.function = pvc_proc_timerfunc;
  142. return 0;
  143. error:
  144. pvc_proc_cleanup();
  145. return -ENOMEM;
  146. }
  147. module_init(pvc_proc_init);
  148. module_exit(pvc_proc_cleanup);
  149. MODULE_LICENSE("GPL");