mm: replace access_process_vm() write parameter with gup_flags
[cascardo/linux.git] / 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/bug.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/init.h>
11 #include <linux/errno.h>
12
13 #include <linux/proc_fs.h>
14 #include <linux/seq_file.h>
15 #include <linux/interrupt.h>
16
17 #include <linux/timer.h>
18 #include <linux/mutex.h>
19
20 #include "picvue.h"
21
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;
28
29 static struct timer_list timer;
30
31 static void pvc_display(unsigned long data)
32 {
33         int i;
34
35         pvc_clear();
36         for (i = 0; i < PVC_NLINES; i++)
37                 pvc_write_string(pvc_lines[i], 0, i);
38 }
39
40 static DECLARE_TASKLET(pvc_display_tasklet, &pvc_display, 0);
41
42 static int pvc_line_proc_show(struct seq_file *m, void *v)
43 {
44         int lineno = *(int *)m->private;
45
46         if (lineno < 0 || lineno >= PVC_NLINES) {
47                 printk(KERN_WARNING "proc_read_line: invalid lineno %d\n", lineno);
48                 return 0;
49         }
50
51         mutex_lock(&pvc_mutex);
52         seq_printf(m, "%s\n", pvc_lines[lineno]);
53         mutex_unlock(&pvc_mutex);
54
55         return 0;
56 }
57
58 static int pvc_line_proc_open(struct inode *inode, struct file *file)
59 {
60         return single_open(file, pvc_line_proc_show, PDE_DATA(inode));
61 }
62
63 static ssize_t pvc_line_proc_write(struct file *file, const char __user *buf,
64                                    size_t count, loff_t *pos)
65 {
66         int lineno = *(int *)PDE_DATA(file_inode(file));
67         char kbuf[PVC_LINELEN];
68         size_t len;
69
70         BUG_ON(lineno < 0 || lineno >= PVC_NLINES);
71
72         len = min(count, sizeof(kbuf) - 1);
73         if (copy_from_user(kbuf, buf, len))
74                 return -EFAULT;
75         kbuf[len] = '\0';
76
77         if (len > 0 && kbuf[len - 1] == '\n')
78                 len--;
79
80         mutex_lock(&pvc_mutex);
81         strncpy(pvc_lines[lineno], kbuf, len);
82         pvc_lines[lineno][len] = '\0';
83         mutex_unlock(&pvc_mutex);
84
85         tasklet_schedule(&pvc_display_tasklet);
86
87         return count;
88 }
89
90 static const struct file_operations pvc_line_proc_fops = {
91         .owner          = THIS_MODULE,
92         .open           = pvc_line_proc_open,
93         .read           = seq_read,
94         .llseek         = seq_lseek,
95         .release        = single_release,
96         .write          = pvc_line_proc_write,
97 };
98
99 static ssize_t pvc_scroll_proc_write(struct file *file, const char __user *buf,
100                                      size_t count, loff_t *pos)
101 {
102         char kbuf[42];
103         size_t len;
104         int cmd;
105
106         len = min(count, sizeof(kbuf) - 1);
107         if (copy_from_user(kbuf, buf, len))
108                 return -EFAULT;
109         kbuf[len] = '\0';
110
111         cmd = simple_strtol(kbuf, NULL, 10);
112
113         mutex_lock(&pvc_mutex);
114         if (scroll_interval != 0)
115                 del_timer(&timer);
116
117         if (cmd == 0) {
118                 scroll_dir = 0;
119                 scroll_interval = 0;
120         } else {
121                 if (cmd < 0) {
122                         scroll_dir = -1;
123                         scroll_interval = -cmd;
124                 } else {
125                         scroll_dir = 1;
126                         scroll_interval = cmd;
127                 }
128                 add_timer(&timer);
129         }
130         mutex_unlock(&pvc_mutex);
131
132         return count;
133 }
134
135 static int pvc_scroll_proc_show(struct seq_file *m, void *v)
136 {
137         mutex_lock(&pvc_mutex);
138         seq_printf(m, "%d\n", scroll_dir * scroll_interval);
139         mutex_unlock(&pvc_mutex);
140
141         return 0;
142 }
143
144 static int pvc_scroll_proc_open(struct inode *inode, struct file *file)
145 {
146         return single_open(file, pvc_scroll_proc_show, NULL);
147 }
148
149 static const struct file_operations pvc_scroll_proc_fops = {
150         .owner          = THIS_MODULE,
151         .open           = pvc_scroll_proc_open,
152         .read           = seq_read,
153         .llseek         = seq_lseek,
154         .release        = single_release,
155         .write          = pvc_scroll_proc_write,
156 };
157
158 void pvc_proc_timerfunc(unsigned long data)
159 {
160         if (scroll_dir < 0)
161                 pvc_move(DISPLAY|RIGHT);
162         else if (scroll_dir > 0)
163                 pvc_move(DISPLAY|LEFT);
164
165         timer.expires = jiffies + scroll_interval;
166         add_timer(&timer);
167 }
168
169 static void pvc_proc_cleanup(void)
170 {
171         remove_proc_subtree(DISPLAY_DIR_NAME, NULL);
172         del_timer_sync(&timer);
173 }
174
175 static int __init pvc_proc_init(void)
176 {
177         struct proc_dir_entry *dir, *proc_entry;
178         int i;
179
180         dir = proc_mkdir(DISPLAY_DIR_NAME, NULL);
181         if (dir == NULL)
182                 goto error;
183
184         for (i = 0; i < PVC_NLINES; i++) {
185                 strcpy(pvc_lines[i], "");
186                 pvc_linedata[i] = i;
187         }
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)
192                         goto error;
193         }
194         proc_entry = proc_create("scroll", 0644, dir,
195                                  &pvc_scroll_proc_fops);
196         if (proc_entry == NULL)
197                 goto error;
198
199         init_timer(&timer);
200         timer.function = pvc_proc_timerfunc;
201
202         return 0;
203 error:
204         pvc_proc_cleanup();
205         return -ENOMEM;
206 }
207
208 module_init(pvc_proc_init);
209 module_exit(pvc_proc_cleanup);
210 MODULE_LICENSE("GPL");