Commit 236b8756a2b6f90498d45b2c36d43e5372f2d4b8
Committed by
Linus Torvalds
1 parent
b8e3591965
Exists in
master
and in
7 other branches
dsp56k: BKL pushdown
Push the BKL down into the driver ioctl methods Signed-off-by: Alan Cox <alan@redhat.com> Cc: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 14 additions and 6 deletions Inline Diff
drivers/char/dsp56k.c
1 | /* | 1 | /* |
2 | * The DSP56001 Device Driver, saviour of the Free World(tm) | 2 | * The DSP56001 Device Driver, saviour of the Free World(tm) |
3 | * | 3 | * |
4 | * Authors: Fredrik Noring <noring@nocrew.org> | 4 | * Authors: Fredrik Noring <noring@nocrew.org> |
5 | * lars brinkhoff <lars@nocrew.org> | 5 | * lars brinkhoff <lars@nocrew.org> |
6 | * Tomas Berndtsson <tomas@nocrew.org> | 6 | * Tomas Berndtsson <tomas@nocrew.org> |
7 | * | 7 | * |
8 | * First version May 1996 | 8 | * First version May 1996 |
9 | * | 9 | * |
10 | * History: | 10 | * History: |
11 | * 97-01-29 Tomas Berndtsson, | 11 | * 97-01-29 Tomas Berndtsson, |
12 | * Integrated with Linux 2.1.21 kernel sources. | 12 | * Integrated with Linux 2.1.21 kernel sources. |
13 | * 97-02-15 Tomas Berndtsson, | 13 | * 97-02-15 Tomas Berndtsson, |
14 | * Fixed for kernel 2.1.26 | 14 | * Fixed for kernel 2.1.26 |
15 | * | 15 | * |
16 | * BUGS: | 16 | * BUGS: |
17 | * Hmm... there must be something here :) | 17 | * Hmm... there must be something here :) |
18 | * | 18 | * |
19 | * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson | 19 | * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson |
20 | * | 20 | * |
21 | * This file is subject to the terms and conditions of the GNU General Public | 21 | * This file is subject to the terms and conditions of the GNU General Public |
22 | * License. See the file COPYING in the main directory of this archive | 22 | * License. See the file COPYING in the main directory of this archive |
23 | * for more details. | 23 | * for more details. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/slab.h> /* for kmalloc() and kfree() */ | 27 | #include <linux/slab.h> /* for kmalloc() and kfree() */ |
28 | #include <linux/major.h> | 28 | #include <linux/major.h> |
29 | #include <linux/types.h> | 29 | #include <linux/types.h> |
30 | #include <linux/errno.h> | 30 | #include <linux/errno.h> |
31 | #include <linux/delay.h> /* guess what */ | 31 | #include <linux/delay.h> /* guess what */ |
32 | #include <linux/fs.h> | 32 | #include <linux/fs.h> |
33 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/device.h> | 35 | #include <linux/device.h> |
36 | #include <linux/smp_lock.h> | 36 | #include <linux/smp_lock.h> |
37 | #include <linux/firmware.h> | 37 | #include <linux/firmware.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/uaccess.h> /* For put_user and get_user */ | ||
39 | 40 | ||
40 | #include <asm/atarihw.h> | 41 | #include <asm/atarihw.h> |
41 | #include <asm/traps.h> | 42 | #include <asm/traps.h> |
42 | #include <asm/uaccess.h> /* For put_user and get_user */ | ||
43 | 43 | ||
44 | #include <asm/dsp56k.h> | 44 | #include <asm/dsp56k.h> |
45 | 45 | ||
46 | /* minor devices */ | 46 | /* minor devices */ |
47 | #define DSP56K_DEV_56001 0 /* The only device so far */ | 47 | #define DSP56K_DEV_56001 0 /* The only device so far */ |
48 | 48 | ||
49 | #define TIMEOUT 10 /* Host port timeout in number of tries */ | 49 | #define TIMEOUT 10 /* Host port timeout in number of tries */ |
50 | #define MAXIO 2048 /* Maximum number of words before sleep */ | 50 | #define MAXIO 2048 /* Maximum number of words before sleep */ |
51 | #define DSP56K_MAX_BINARY_LENGTH (3*64*1024) | 51 | #define DSP56K_MAX_BINARY_LENGTH (3*64*1024) |
52 | 52 | ||
53 | #define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ | 53 | #define DSP56K_TX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_TREQ |
54 | #define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ | 54 | #define DSP56K_RX_INT_ON dsp56k_host_interface.icr |= DSP56K_ICR_RREQ |
55 | #define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ | 55 | #define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ |
56 | #define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ | 56 | #define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ |
57 | 57 | ||
58 | #define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE) | 58 | #define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE) |
59 | #define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF) | 59 | #define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF) |
60 | 60 | ||
61 | #define handshake(count, maxio, timeout, ENABLE, f) \ | 61 | #define handshake(count, maxio, timeout, ENABLE, f) \ |
62 | { \ | 62 | { \ |
63 | long i, t, m; \ | 63 | long i, t, m; \ |
64 | while (count > 0) { \ | 64 | while (count > 0) { \ |
65 | m = min_t(unsigned long, count, maxio); \ | 65 | m = min_t(unsigned long, count, maxio); \ |
66 | for (i = 0; i < m; i++) { \ | 66 | for (i = 0; i < m; i++) { \ |
67 | for (t = 0; t < timeout && !ENABLE; t++) \ | 67 | for (t = 0; t < timeout && !ENABLE; t++) \ |
68 | msleep(20); \ | 68 | msleep(20); \ |
69 | if(!ENABLE) \ | 69 | if(!ENABLE) \ |
70 | return -EIO; \ | 70 | return -EIO; \ |
71 | f; \ | 71 | f; \ |
72 | } \ | 72 | } \ |
73 | count -= m; \ | 73 | count -= m; \ |
74 | if (m == maxio) msleep(20); \ | 74 | if (m == maxio) msleep(20); \ |
75 | } \ | 75 | } \ |
76 | } | 76 | } |
77 | 77 | ||
78 | #define tx_wait(n) \ | 78 | #define tx_wait(n) \ |
79 | { \ | 79 | { \ |
80 | int t; \ | 80 | int t; \ |
81 | for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \ | 81 | for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \ |
82 | msleep(10); \ | 82 | msleep(10); \ |
83 | if(!DSP56K_TRANSMIT) { \ | 83 | if(!DSP56K_TRANSMIT) { \ |
84 | return -EIO; \ | 84 | return -EIO; \ |
85 | } \ | 85 | } \ |
86 | } | 86 | } |
87 | 87 | ||
88 | #define rx_wait(n) \ | 88 | #define rx_wait(n) \ |
89 | { \ | 89 | { \ |
90 | int t; \ | 90 | int t; \ |
91 | for(t = 0; t < n && !DSP56K_RECEIVE; t++) \ | 91 | for(t = 0; t < n && !DSP56K_RECEIVE; t++) \ |
92 | msleep(10); \ | 92 | msleep(10); \ |
93 | if(!DSP56K_RECEIVE) { \ | 93 | if(!DSP56K_RECEIVE) { \ |
94 | return -EIO; \ | 94 | return -EIO; \ |
95 | } \ | 95 | } \ |
96 | } | 96 | } |
97 | 97 | ||
98 | static struct dsp56k_device { | 98 | static struct dsp56k_device { |
99 | unsigned long in_use; | 99 | unsigned long in_use; |
100 | long maxio, timeout; | 100 | long maxio, timeout; |
101 | int tx_wsize, rx_wsize; | 101 | int tx_wsize, rx_wsize; |
102 | } dsp56k; | 102 | } dsp56k; |
103 | 103 | ||
104 | static struct class *dsp56k_class; | 104 | static struct class *dsp56k_class; |
105 | 105 | ||
106 | static int dsp56k_reset(void) | 106 | static int dsp56k_reset(void) |
107 | { | 107 | { |
108 | u_char status; | 108 | u_char status; |
109 | 109 | ||
110 | /* Power down the DSP */ | 110 | /* Power down the DSP */ |
111 | sound_ym.rd_data_reg_sel = 14; | 111 | sound_ym.rd_data_reg_sel = 14; |
112 | status = sound_ym.rd_data_reg_sel & 0xef; | 112 | status = sound_ym.rd_data_reg_sel & 0xef; |
113 | sound_ym.wd_data = status; | 113 | sound_ym.wd_data = status; |
114 | sound_ym.wd_data = status | 0x10; | 114 | sound_ym.wd_data = status | 0x10; |
115 | 115 | ||
116 | udelay(10); | 116 | udelay(10); |
117 | 117 | ||
118 | /* Power up the DSP */ | 118 | /* Power up the DSP */ |
119 | sound_ym.rd_data_reg_sel = 14; | 119 | sound_ym.rd_data_reg_sel = 14; |
120 | sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef; | 120 | sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef; |
121 | 121 | ||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | static int dsp56k_upload(u_char __user *bin, int len) | 125 | static int dsp56k_upload(u_char __user *bin, int len) |
126 | { | 126 | { |
127 | struct platform_device *pdev; | 127 | struct platform_device *pdev; |
128 | const struct firmware *fw; | 128 | const struct firmware *fw; |
129 | const char fw_name[] = "dsp56k/bootstrap.bin"; | 129 | const char fw_name[] = "dsp56k/bootstrap.bin"; |
130 | int err; | 130 | int err; |
131 | int i; | 131 | int i; |
132 | 132 | ||
133 | dsp56k_reset(); | 133 | dsp56k_reset(); |
134 | 134 | ||
135 | pdev = platform_device_register_simple("dsp56k", 0, NULL, 0); | 135 | pdev = platform_device_register_simple("dsp56k", 0, NULL, 0); |
136 | if (IS_ERR(pdev)) { | 136 | if (IS_ERR(pdev)) { |
137 | printk(KERN_ERR "Failed to register device for \"%s\"\n", | 137 | printk(KERN_ERR "Failed to register device for \"%s\"\n", |
138 | fw_name); | 138 | fw_name); |
139 | return -EINVAL; | 139 | return -EINVAL; |
140 | } | 140 | } |
141 | err = request_firmware(&fw, fw_name, &pdev->dev); | 141 | err = request_firmware(&fw, fw_name, &pdev->dev); |
142 | platform_device_unregister(pdev); | 142 | platform_device_unregister(pdev); |
143 | if (err) { | 143 | if (err) { |
144 | printk(KERN_ERR "Failed to load image \"%s\" err %d\n", | 144 | printk(KERN_ERR "Failed to load image \"%s\" err %d\n", |
145 | fw_name, err); | 145 | fw_name, err); |
146 | return err; | 146 | return err; |
147 | } | 147 | } |
148 | if (fw->size % 3) { | 148 | if (fw->size % 3) { |
149 | printk(KERN_ERR "Bogus length %d in image \"%s\"\n", | 149 | printk(KERN_ERR "Bogus length %d in image \"%s\"\n", |
150 | fw->size, fw_name); | 150 | fw->size, fw_name); |
151 | release_firmware(fw); | 151 | release_firmware(fw); |
152 | return -EINVAL; | 152 | return -EINVAL; |
153 | } | 153 | } |
154 | for (i = 0; i < fw->size; i = i + 3) { | 154 | for (i = 0; i < fw->size; i = i + 3) { |
155 | /* tx_wait(10); */ | 155 | /* tx_wait(10); */ |
156 | dsp56k_host_interface.data.b[1] = fw->data[i]; | 156 | dsp56k_host_interface.data.b[1] = fw->data[i]; |
157 | dsp56k_host_interface.data.b[2] = fw->data[i + 1]; | 157 | dsp56k_host_interface.data.b[2] = fw->data[i + 1]; |
158 | dsp56k_host_interface.data.b[3] = fw->data[i + 2]; | 158 | dsp56k_host_interface.data.b[3] = fw->data[i + 2]; |
159 | } | 159 | } |
160 | release_firmware(fw); | 160 | release_firmware(fw); |
161 | for (; i < 512; i++) { | 161 | for (; i < 512; i++) { |
162 | /* tx_wait(10); */ | 162 | /* tx_wait(10); */ |
163 | dsp56k_host_interface.data.b[1] = 0; | 163 | dsp56k_host_interface.data.b[1] = 0; |
164 | dsp56k_host_interface.data.b[2] = 0; | 164 | dsp56k_host_interface.data.b[2] = 0; |
165 | dsp56k_host_interface.data.b[3] = 0; | 165 | dsp56k_host_interface.data.b[3] = 0; |
166 | } | 166 | } |
167 | 167 | ||
168 | for (i = 0; i < len; i++) { | 168 | for (i = 0; i < len; i++) { |
169 | tx_wait(10); | 169 | tx_wait(10); |
170 | get_user(dsp56k_host_interface.data.b[1], bin++); | 170 | get_user(dsp56k_host_interface.data.b[1], bin++); |
171 | get_user(dsp56k_host_interface.data.b[2], bin++); | 171 | get_user(dsp56k_host_interface.data.b[2], bin++); |
172 | get_user(dsp56k_host_interface.data.b[3], bin++); | 172 | get_user(dsp56k_host_interface.data.b[3], bin++); |
173 | } | 173 | } |
174 | 174 | ||
175 | tx_wait(10); | 175 | tx_wait(10); |
176 | dsp56k_host_interface.data.l = 3; /* Magic execute */ | 176 | dsp56k_host_interface.data.l = 3; /* Magic execute */ |
177 | 177 | ||
178 | return 0; | 178 | return 0; |
179 | } | 179 | } |
180 | 180 | ||
181 | static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count, | 181 | static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count, |
182 | loff_t *ppos) | 182 | loff_t *ppos) |
183 | { | 183 | { |
184 | struct inode *inode = file->f_path.dentry->d_inode; | 184 | struct inode *inode = file->f_path.dentry->d_inode; |
185 | int dev = iminor(inode) & 0x0f; | 185 | int dev = iminor(inode) & 0x0f; |
186 | 186 | ||
187 | switch(dev) | 187 | switch(dev) |
188 | { | 188 | { |
189 | case DSP56K_DEV_56001: | 189 | case DSP56K_DEV_56001: |
190 | { | 190 | { |
191 | 191 | ||
192 | long n; | 192 | long n; |
193 | 193 | ||
194 | /* Don't do anything if nothing is to be done */ | 194 | /* Don't do anything if nothing is to be done */ |
195 | if (!count) return 0; | 195 | if (!count) return 0; |
196 | 196 | ||
197 | n = 0; | 197 | n = 0; |
198 | switch (dsp56k.rx_wsize) { | 198 | switch (dsp56k.rx_wsize) { |
199 | case 1: /* 8 bit */ | 199 | case 1: /* 8 bit */ |
200 | { | 200 | { |
201 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, | 201 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, |
202 | put_user(dsp56k_host_interface.data.b[3], buf+n++)); | 202 | put_user(dsp56k_host_interface.data.b[3], buf+n++)); |
203 | return n; | 203 | return n; |
204 | } | 204 | } |
205 | case 2: /* 16 bit */ | 205 | case 2: /* 16 bit */ |
206 | { | 206 | { |
207 | short __user *data; | 207 | short __user *data; |
208 | 208 | ||
209 | count /= 2; | 209 | count /= 2; |
210 | data = (short __user *) buf; | 210 | data = (short __user *) buf; |
211 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, | 211 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, |
212 | put_user(dsp56k_host_interface.data.w[1], data+n++)); | 212 | put_user(dsp56k_host_interface.data.w[1], data+n++)); |
213 | return 2*n; | 213 | return 2*n; |
214 | } | 214 | } |
215 | case 3: /* 24 bit */ | 215 | case 3: /* 24 bit */ |
216 | { | 216 | { |
217 | count /= 3; | 217 | count /= 3; |
218 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, | 218 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, |
219 | put_user(dsp56k_host_interface.data.b[1], buf+n++); | 219 | put_user(dsp56k_host_interface.data.b[1], buf+n++); |
220 | put_user(dsp56k_host_interface.data.b[2], buf+n++); | 220 | put_user(dsp56k_host_interface.data.b[2], buf+n++); |
221 | put_user(dsp56k_host_interface.data.b[3], buf+n++)); | 221 | put_user(dsp56k_host_interface.data.b[3], buf+n++)); |
222 | return 3*n; | 222 | return 3*n; |
223 | } | 223 | } |
224 | case 4: /* 32 bit */ | 224 | case 4: /* 32 bit */ |
225 | { | 225 | { |
226 | long __user *data; | 226 | long __user *data; |
227 | 227 | ||
228 | count /= 4; | 228 | count /= 4; |
229 | data = (long __user *) buf; | 229 | data = (long __user *) buf; |
230 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, | 230 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE, |
231 | put_user(dsp56k_host_interface.data.l, data+n++)); | 231 | put_user(dsp56k_host_interface.data.l, data+n++)); |
232 | return 4*n; | 232 | return 4*n; |
233 | } | 233 | } |
234 | } | 234 | } |
235 | return -EFAULT; | 235 | return -EFAULT; |
236 | } | 236 | } |
237 | 237 | ||
238 | default: | 238 | default: |
239 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); | 239 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); |
240 | return -ENXIO; | 240 | return -ENXIO; |
241 | } | 241 | } |
242 | } | 242 | } |
243 | 243 | ||
244 | static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count, | 244 | static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count, |
245 | loff_t *ppos) | 245 | loff_t *ppos) |
246 | { | 246 | { |
247 | struct inode *inode = file->f_path.dentry->d_inode; | 247 | struct inode *inode = file->f_path.dentry->d_inode; |
248 | int dev = iminor(inode) & 0x0f; | 248 | int dev = iminor(inode) & 0x0f; |
249 | 249 | ||
250 | switch(dev) | 250 | switch(dev) |
251 | { | 251 | { |
252 | case DSP56K_DEV_56001: | 252 | case DSP56K_DEV_56001: |
253 | { | 253 | { |
254 | long n; | 254 | long n; |
255 | 255 | ||
256 | /* Don't do anything if nothing is to be done */ | 256 | /* Don't do anything if nothing is to be done */ |
257 | if (!count) return 0; | 257 | if (!count) return 0; |
258 | 258 | ||
259 | n = 0; | 259 | n = 0; |
260 | switch (dsp56k.tx_wsize) { | 260 | switch (dsp56k.tx_wsize) { |
261 | case 1: /* 8 bit */ | 261 | case 1: /* 8 bit */ |
262 | { | 262 | { |
263 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, | 263 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, |
264 | get_user(dsp56k_host_interface.data.b[3], buf+n++)); | 264 | get_user(dsp56k_host_interface.data.b[3], buf+n++)); |
265 | return n; | 265 | return n; |
266 | } | 266 | } |
267 | case 2: /* 16 bit */ | 267 | case 2: /* 16 bit */ |
268 | { | 268 | { |
269 | const short __user *data; | 269 | const short __user *data; |
270 | 270 | ||
271 | count /= 2; | 271 | count /= 2; |
272 | data = (const short __user *)buf; | 272 | data = (const short __user *)buf; |
273 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, | 273 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, |
274 | get_user(dsp56k_host_interface.data.w[1], data+n++)); | 274 | get_user(dsp56k_host_interface.data.w[1], data+n++)); |
275 | return 2*n; | 275 | return 2*n; |
276 | } | 276 | } |
277 | case 3: /* 24 bit */ | 277 | case 3: /* 24 bit */ |
278 | { | 278 | { |
279 | count /= 3; | 279 | count /= 3; |
280 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, | 280 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, |
281 | get_user(dsp56k_host_interface.data.b[1], buf+n++); | 281 | get_user(dsp56k_host_interface.data.b[1], buf+n++); |
282 | get_user(dsp56k_host_interface.data.b[2], buf+n++); | 282 | get_user(dsp56k_host_interface.data.b[2], buf+n++); |
283 | get_user(dsp56k_host_interface.data.b[3], buf+n++)); | 283 | get_user(dsp56k_host_interface.data.b[3], buf+n++)); |
284 | return 3*n; | 284 | return 3*n; |
285 | } | 285 | } |
286 | case 4: /* 32 bit */ | 286 | case 4: /* 32 bit */ |
287 | { | 287 | { |
288 | const long __user *data; | 288 | const long __user *data; |
289 | 289 | ||
290 | count /= 4; | 290 | count /= 4; |
291 | data = (const long __user *)buf; | 291 | data = (const long __user *)buf; |
292 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, | 292 | handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT, |
293 | get_user(dsp56k_host_interface.data.l, data+n++)); | 293 | get_user(dsp56k_host_interface.data.l, data+n++)); |
294 | return 4*n; | 294 | return 4*n; |
295 | } | 295 | } |
296 | } | 296 | } |
297 | 297 | ||
298 | return -EFAULT; | 298 | return -EFAULT; |
299 | } | 299 | } |
300 | default: | 300 | default: |
301 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); | 301 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); |
302 | return -ENXIO; | 302 | return -ENXIO; |
303 | } | 303 | } |
304 | } | 304 | } |
305 | 305 | ||
306 | static int dsp56k_ioctl(struct inode *inode, struct file *file, | 306 | static long dsp56k_ioctl(struct file *file, unsigned int cmd, |
307 | unsigned int cmd, unsigned long arg) | 307 | unsigned long arg) |
308 | { | 308 | { |
309 | int dev = iminor(inode) & 0x0f; | 309 | int dev = iminor(inode) & 0x0f; |
310 | void __user *argp = (void __user *)arg; | 310 | void __user *argp = (void __user *)arg; |
311 | 311 | ||
312 | switch(dev) | 312 | switch(dev) |
313 | { | 313 | { |
314 | case DSP56K_DEV_56001: | 314 | case DSP56K_DEV_56001: |
315 | 315 | ||
316 | switch(cmd) { | 316 | switch(cmd) { |
317 | case DSP56K_UPLOAD: | 317 | case DSP56K_UPLOAD: |
318 | { | 318 | { |
319 | char __user *bin; | 319 | char __user *bin; |
320 | int r, len; | 320 | int r, len; |
321 | struct dsp56k_upload __user *binary = argp; | 321 | struct dsp56k_upload __user *binary = argp; |
322 | 322 | ||
323 | if(get_user(len, &binary->len) < 0) | 323 | if(get_user(len, &binary->len) < 0) |
324 | return -EFAULT; | 324 | return -EFAULT; |
325 | if(get_user(bin, &binary->bin) < 0) | 325 | if(get_user(bin, &binary->bin) < 0) |
326 | return -EFAULT; | 326 | return -EFAULT; |
327 | 327 | ||
328 | if (len == 0) { | 328 | if (len == 0) { |
329 | return -EINVAL; /* nothing to upload?!? */ | 329 | return -EINVAL; /* nothing to upload?!? */ |
330 | } | 330 | } |
331 | if (len > DSP56K_MAX_BINARY_LENGTH) { | 331 | if (len > DSP56K_MAX_BINARY_LENGTH) { |
332 | return -EINVAL; | 332 | return -EINVAL; |
333 | } | 333 | } |
334 | 334 | lock_kernel(); | |
335 | r = dsp56k_upload(bin, len); | 335 | r = dsp56k_upload(bin, len); |
336 | unlock_kernel(); | ||
336 | if (r < 0) { | 337 | if (r < 0) { |
337 | return r; | 338 | return r; |
338 | } | 339 | } |
339 | 340 | ||
340 | break; | 341 | break; |
341 | } | 342 | } |
342 | case DSP56K_SET_TX_WSIZE: | 343 | case DSP56K_SET_TX_WSIZE: |
343 | if (arg > 4 || arg < 1) | 344 | if (arg > 4 || arg < 1) |
344 | return -EINVAL; | 345 | return -EINVAL; |
346 | lock_kernel(); | ||
345 | dsp56k.tx_wsize = (int) arg; | 347 | dsp56k.tx_wsize = (int) arg; |
348 | unlock_kernel(); | ||
346 | break; | 349 | break; |
347 | case DSP56K_SET_RX_WSIZE: | 350 | case DSP56K_SET_RX_WSIZE: |
348 | if (arg > 4 || arg < 1) | 351 | if (arg > 4 || arg < 1) |
349 | return -EINVAL; | 352 | return -EINVAL; |
353 | lock_kernel(); | ||
350 | dsp56k.rx_wsize = (int) arg; | 354 | dsp56k.rx_wsize = (int) arg; |
355 | unlock_kernel(); | ||
351 | break; | 356 | break; |
352 | case DSP56K_HOST_FLAGS: | 357 | case DSP56K_HOST_FLAGS: |
353 | { | 358 | { |
354 | int dir, out, status; | 359 | int dir, out, status; |
355 | struct dsp56k_host_flags __user *hf = argp; | 360 | struct dsp56k_host_flags __user *hf = argp; |
356 | 361 | ||
357 | if(get_user(dir, &hf->dir) < 0) | 362 | if(get_user(dir, &hf->dir) < 0) |
358 | return -EFAULT; | 363 | return -EFAULT; |
359 | if(get_user(out, &hf->out) < 0) | 364 | if(get_user(out, &hf->out) < 0) |
360 | return -EFAULT; | 365 | return -EFAULT; |
361 | 366 | ||
367 | lock_kernel(); | ||
362 | if ((dir & 0x1) && (out & 0x1)) | 368 | if ((dir & 0x1) && (out & 0x1)) |
363 | dsp56k_host_interface.icr |= DSP56K_ICR_HF0; | 369 | dsp56k_host_interface.icr |= DSP56K_ICR_HF0; |
364 | else if (dir & 0x1) | 370 | else if (dir & 0x1) |
365 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; | 371 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; |
366 | if ((dir & 0x2) && (out & 0x2)) | 372 | if ((dir & 0x2) && (out & 0x2)) |
367 | dsp56k_host_interface.icr |= DSP56K_ICR_HF1; | 373 | dsp56k_host_interface.icr |= DSP56K_ICR_HF1; |
368 | else if (dir & 0x2) | 374 | else if (dir & 0x2) |
369 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; | 375 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; |
370 | 376 | ||
371 | status = 0; | 377 | status = 0; |
372 | if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1; | 378 | if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1; |
373 | if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2; | 379 | if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2; |
374 | if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4; | 380 | if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4; |
375 | if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8; | 381 | if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8; |
376 | 382 | unlock_kernel(); | |
377 | return put_user(status, &hf->status); | 383 | return put_user(status, &hf->status); |
378 | } | 384 | } |
379 | case DSP56K_HOST_CMD: | 385 | case DSP56K_HOST_CMD: |
380 | if (arg > 31 || arg < 0) | 386 | if (arg > 31 || arg < 0) |
381 | return -EINVAL; | 387 | return -EINVAL; |
388 | lock_kernel(); | ||
382 | dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) | | 389 | dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) | |
383 | DSP56K_CVR_HC); | 390 | DSP56K_CVR_HC); |
391 | unlock_kernel(); | ||
384 | break; | 392 | break; |
385 | default: | 393 | default: |
386 | return -EINVAL; | 394 | return -EINVAL; |
387 | } | 395 | } |
388 | return 0; | 396 | return 0; |
389 | 397 | ||
390 | default: | 398 | default: |
391 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); | 399 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); |
392 | return -ENXIO; | 400 | return -ENXIO; |
393 | } | 401 | } |
394 | } | 402 | } |
395 | 403 | ||
396 | /* As of 2.1.26 this should be dsp56k_poll, | 404 | /* As of 2.1.26 this should be dsp56k_poll, |
397 | * but how do I then check device minor number? | 405 | * but how do I then check device minor number? |
398 | * Do I need this function at all??? | 406 | * Do I need this function at all??? |
399 | */ | 407 | */ |
400 | #if 0 | 408 | #if 0 |
401 | static unsigned int dsp56k_poll(struct file *file, poll_table *wait) | 409 | static unsigned int dsp56k_poll(struct file *file, poll_table *wait) |
402 | { | 410 | { |
403 | int dev = iminor(file->f_path.dentry->d_inode) & 0x0f; | 411 | int dev = iminor(file->f_path.dentry->d_inode) & 0x0f; |
404 | 412 | ||
405 | switch(dev) | 413 | switch(dev) |
406 | { | 414 | { |
407 | case DSP56K_DEV_56001: | 415 | case DSP56K_DEV_56001: |
408 | /* poll_wait(file, ???, wait); */ | 416 | /* poll_wait(file, ???, wait); */ |
409 | return POLLIN | POLLRDNORM | POLLOUT; | 417 | return POLLIN | POLLRDNORM | POLLOUT; |
410 | 418 | ||
411 | default: | 419 | default: |
412 | printk("DSP56k driver: Unknown minor device: %d\n", dev); | 420 | printk("DSP56k driver: Unknown minor device: %d\n", dev); |
413 | return 0; | 421 | return 0; |
414 | } | 422 | } |
415 | } | 423 | } |
416 | #endif | 424 | #endif |
417 | 425 | ||
418 | static int dsp56k_open(struct inode *inode, struct file *file) | 426 | static int dsp56k_open(struct inode *inode, struct file *file) |
419 | { | 427 | { |
420 | int dev = iminor(inode) & 0x0f; | 428 | int dev = iminor(inode) & 0x0f; |
421 | int ret = 0; | 429 | int ret = 0; |
422 | 430 | ||
423 | lock_kernel(); | 431 | lock_kernel(); |
424 | switch(dev) | 432 | switch(dev) |
425 | { | 433 | { |
426 | case DSP56K_DEV_56001: | 434 | case DSP56K_DEV_56001: |
427 | 435 | ||
428 | if (test_and_set_bit(0, &dsp56k.in_use)) { | 436 | if (test_and_set_bit(0, &dsp56k.in_use)) { |
429 | ret = -EBUSY; | 437 | ret = -EBUSY; |
430 | goto out; | 438 | goto out; |
431 | } | 439 | } |
432 | 440 | ||
433 | dsp56k.timeout = TIMEOUT; | 441 | dsp56k.timeout = TIMEOUT; |
434 | dsp56k.maxio = MAXIO; | 442 | dsp56k.maxio = MAXIO; |
435 | dsp56k.rx_wsize = dsp56k.tx_wsize = 4; | 443 | dsp56k.rx_wsize = dsp56k.tx_wsize = 4; |
436 | 444 | ||
437 | DSP56K_TX_INT_OFF; | 445 | DSP56K_TX_INT_OFF; |
438 | DSP56K_RX_INT_OFF; | 446 | DSP56K_RX_INT_OFF; |
439 | 447 | ||
440 | /* Zero host flags */ | 448 | /* Zero host flags */ |
441 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; | 449 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0; |
442 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; | 450 | dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1; |
443 | 451 | ||
444 | break; | 452 | break; |
445 | 453 | ||
446 | default: | 454 | default: |
447 | ret = -ENODEV; | 455 | ret = -ENODEV; |
448 | } | 456 | } |
449 | out: | 457 | out: |
450 | unlock_kernel(); | 458 | unlock_kernel(); |
451 | return ret; | 459 | return ret; |
452 | } | 460 | } |
453 | 461 | ||
454 | static int dsp56k_release(struct inode *inode, struct file *file) | 462 | static int dsp56k_release(struct inode *inode, struct file *file) |
455 | { | 463 | { |
456 | int dev = iminor(inode) & 0x0f; | 464 | int dev = iminor(inode) & 0x0f; |
457 | 465 | ||
458 | switch(dev) | 466 | switch(dev) |
459 | { | 467 | { |
460 | case DSP56K_DEV_56001: | 468 | case DSP56K_DEV_56001: |
461 | clear_bit(0, &dsp56k.in_use); | 469 | clear_bit(0, &dsp56k.in_use); |
462 | break; | 470 | break; |
463 | default: | 471 | default: |
464 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); | 472 | printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev); |
465 | return -ENXIO; | 473 | return -ENXIO; |
466 | } | 474 | } |
467 | 475 | ||
468 | return 0; | 476 | return 0; |
469 | } | 477 | } |
470 | 478 | ||
471 | static const struct file_operations dsp56k_fops = { | 479 | static const struct file_operations dsp56k_fops = { |
472 | .owner = THIS_MODULE, | 480 | .owner = THIS_MODULE, |
473 | .read = dsp56k_read, | 481 | .read = dsp56k_read, |
474 | .write = dsp56k_write, | 482 | .write = dsp56k_write, |
475 | .ioctl = dsp56k_ioctl, | 483 | .unlocked_ioctl = dsp56k_ioctl, |
476 | .open = dsp56k_open, | 484 | .open = dsp56k_open, |
477 | .release = dsp56k_release, | 485 | .release = dsp56k_release, |
478 | }; | 486 | }; |
479 | 487 | ||
480 | 488 | ||
481 | /****** Init and module functions ******/ | 489 | /****** Init and module functions ******/ |
482 | 490 | ||
483 | static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n"; | 491 | static char banner[] __initdata = KERN_INFO "DSP56k driver installed\n"; |
484 | 492 | ||
485 | static int __init dsp56k_init_driver(void) | 493 | static int __init dsp56k_init_driver(void) |
486 | { | 494 | { |
487 | int err = 0; | 495 | int err = 0; |
488 | 496 | ||
489 | if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) { | 497 | if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) { |
490 | printk("DSP56k driver: Hardware not present\n"); | 498 | printk("DSP56k driver: Hardware not present\n"); |
491 | return -ENODEV; | 499 | return -ENODEV; |
492 | } | 500 | } |
493 | 501 | ||
494 | if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) { | 502 | if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) { |
495 | printk("DSP56k driver: Unable to register driver\n"); | 503 | printk("DSP56k driver: Unable to register driver\n"); |
496 | return -ENODEV; | 504 | return -ENODEV; |
497 | } | 505 | } |
498 | dsp56k_class = class_create(THIS_MODULE, "dsp56k"); | 506 | dsp56k_class = class_create(THIS_MODULE, "dsp56k"); |
499 | if (IS_ERR(dsp56k_class)) { | 507 | if (IS_ERR(dsp56k_class)) { |
500 | err = PTR_ERR(dsp56k_class); | 508 | err = PTR_ERR(dsp56k_class); |
501 | goto out_chrdev; | 509 | goto out_chrdev; |
502 | } | 510 | } |
503 | device_create_drvdata(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), | 511 | device_create_drvdata(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), |
504 | NULL, "dsp56k"); | 512 | NULL, "dsp56k"); |
505 | 513 | ||
506 | printk(banner); | 514 | printk(banner); |
507 | goto out; | 515 | goto out; |
508 | 516 | ||
509 | out_chrdev: | 517 | out_chrdev: |
510 | unregister_chrdev(DSP56K_MAJOR, "dsp56k"); | 518 | unregister_chrdev(DSP56K_MAJOR, "dsp56k"); |
511 | out: | 519 | out: |
512 | return err; | 520 | return err; |
513 | } | 521 | } |
514 | module_init(dsp56k_init_driver); | 522 | module_init(dsp56k_init_driver); |
515 | 523 | ||
516 | static void __exit dsp56k_cleanup_driver(void) | 524 | static void __exit dsp56k_cleanup_driver(void) |
517 | { | 525 | { |
518 | device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); | 526 | device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); |
519 | class_destroy(dsp56k_class); | 527 | class_destroy(dsp56k_class); |
520 | unregister_chrdev(DSP56K_MAJOR, "dsp56k"); | 528 | unregister_chrdev(DSP56K_MAJOR, "dsp56k"); |
521 | } | 529 | } |
522 | module_exit(dsp56k_cleanup_driver); | 530 | module_exit(dsp56k_cleanup_driver); |
523 | 531 | ||
524 | MODULE_LICENSE("GPL"); | 532 | MODULE_LICENSE("GPL"); |
525 | MODULE_FIRMWARE("dsp56k/bootstrap.bin"); | 533 | MODULE_FIRMWARE("dsp56k/bootstrap.bin"); |