Merge branch 'we21-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
[linux-2.6] / arch / mips / lasat / picvue_proc.c
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
19 static char pvc_lines[PVC_NLINES][PVC_LINELEN+1];
20 static int pvc_linedata[PVC_NLINES];
21 static struct proc_dir_entry *pvc_display_dir;
22 static char *pvc_linename[PVC_NLINES] = {"line1", "line2"};
23 #define DISPLAY_DIR_NAME "display"
24 static int scroll_dir = 0, scroll_interval = 0;
25
26 static struct timer_list timer;
27
28 static 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
36 static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0);
37
38 static 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
57 static 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
84 static 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
112 static 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
126 void 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
137 static 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
148 static 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;
179 error:
180         pvc_proc_cleanup();
181         return -ENOMEM;
182 }
183
184 module_init(pvc_proc_init);
185 module_exit(pvc_proc_cleanup);
186 MODULE_LICENSE("GPL");