2 * Picvue PVC160206 display driver
4 * Brian Murphy <brian.murphy@eicon.com>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/errno.h>
13 #include <linux/proc_fs.h>
14 #include <linux/seq_file.h>
15 #include <linux/interrupt.h>
17 #include <linux/timer.h>
18 #include <linux/mutex.h>
22 static DEFINE_MUTEX(pvc_mutex
);
23 static char pvc_lines
[PVC_NLINES
][PVC_LINELEN
+1];
24 static int pvc_linedata
[PVC_NLINES
];
25 static char *pvc_linename
[PVC_NLINES
] = {"line1", "line2"};
26 #define DISPLAY_DIR_NAME "display"
27 static int scroll_dir
, scroll_interval
;
29 static struct timer_list timer
;
31 static void pvc_display(unsigned long data
)
36 for (i
= 0; i
< PVC_NLINES
; i
++)
37 pvc_write_string(pvc_lines
[i
], 0, i
);
40 static DECLARE_TASKLET(pvc_display_tasklet
, &pvc_display
, 0);
42 static int pvc_line_proc_show(struct seq_file
*m
, void *v
)
44 int lineno
= *(int *)m
->private;
46 if (lineno
< 0 || lineno
> PVC_NLINES
) {
47 printk(KERN_WARNING
"proc_read_line: invalid lineno %d\n", lineno
);
51 mutex_lock(&pvc_mutex
);
52 seq_printf(m
, "%s\n", pvc_lines
[lineno
]);
53 mutex_unlock(&pvc_mutex
);
58 static int pvc_line_proc_open(struct inode
*inode
, struct file
*file
)
60 return single_open(file
, pvc_line_proc_show
, PDE_DATA(inode
));
63 static ssize_t
pvc_line_proc_write(struct file
*file
, const char __user
*buf
,
64 size_t count
, loff_t
*pos
)
66 int lineno
= *(int *)PDE_DATA(file_inode(file
));
67 char kbuf
[PVC_LINELEN
];
70 BUG_ON(lineno
< 0 || lineno
> PVC_NLINES
);
72 len
= min(count
, sizeof(kbuf
) - 1);
73 if (copy_from_user(kbuf
, buf
, len
))
77 if (len
> 0 && kbuf
[len
- 1] == '\n')
80 mutex_lock(&pvc_mutex
);
81 strncpy(pvc_lines
[lineno
], kbuf
, len
);
82 pvc_lines
[lineno
][len
] = '\0';
83 mutex_unlock(&pvc_mutex
);
85 tasklet_schedule(&pvc_display_tasklet
);
90 static const struct file_operations pvc_line_proc_fops
= {
92 .open
= pvc_line_proc_open
,
95 .release
= single_release
,
96 .write
= pvc_line_proc_write
,
99 static ssize_t
pvc_scroll_proc_write(struct file
*file
, const char __user
*buf
,
100 size_t count
, loff_t
*pos
)
106 len
= min(count
, sizeof(kbuf
) - 1);
107 if (copy_from_user(kbuf
, buf
, len
))
111 cmd
= simple_strtol(kbuf
, NULL
, 10);
113 mutex_lock(&pvc_mutex
);
114 if (scroll_interval
!= 0)
123 scroll_interval
= -cmd
;
126 scroll_interval
= cmd
;
130 mutex_unlock(&pvc_mutex
);
135 static int pvc_scroll_proc_show(struct seq_file
*m
, void *v
)
137 mutex_lock(&pvc_mutex
);
138 seq_printf(m
, "%d\n", scroll_dir
* scroll_interval
);
139 mutex_unlock(&pvc_mutex
);
144 static int pvc_scroll_proc_open(struct inode
*inode
, struct file
*file
)
146 return single_open(file
, pvc_scroll_proc_show
, NULL
);
149 static const struct file_operations pvc_scroll_proc_fops
= {
150 .owner
= THIS_MODULE
,
151 .open
= pvc_scroll_proc_open
,
154 .release
= single_release
,
155 .write
= pvc_scroll_proc_write
,
158 void pvc_proc_timerfunc(unsigned long data
)
161 pvc_move(DISPLAY
|RIGHT
);
162 else if (scroll_dir
> 0)
163 pvc_move(DISPLAY
|LEFT
);
165 timer
.expires
= jiffies
+ scroll_interval
;
169 static void pvc_proc_cleanup(void)
171 remove_proc_subtree(DISPLAY_DIR_NAME
, NULL
);
172 del_timer_sync(&timer
);
175 static int __init
pvc_proc_init(void)
177 struct proc_dir_entry
*dir
, *proc_entry
;
180 dir
= proc_mkdir(DISPLAY_DIR_NAME
, NULL
);
184 for (i
= 0; i
< PVC_NLINES
; i
++) {
185 strcpy(pvc_lines
[i
], "");
188 for (i
= 0; i
< PVC_NLINES
; i
++) {
189 proc_entry
= proc_create_data(pvc_linename
[i
], 0644, dir
,
190 &pvc_line_proc_fops
, &pvc_linedata
[i
]);
191 if (proc_entry
== NULL
)
194 proc_entry
= proc_create("scroll", 0644, dir
,
195 &pvc_scroll_proc_fops
);
196 if (proc_entry
== NULL
)
200 timer
.function
= pvc_proc_timerfunc
;
208 module_init(pvc_proc_init
);
209 module_exit(pvc_proc_cleanup
);
210 MODULE_LICENSE("GPL");