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