Blame view

drivers/char/dsp56k.c 12.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * The DSP56001 Device Driver, saviour of the Free World(tm)
   *
   * Authors: Fredrik Noring   <noring@nocrew.org>
   *          lars brinkhoff   <lars@nocrew.org>
   *          Tomas Berndtsson <tomas@nocrew.org>
   *
   * First version May 1996
   *
   * History:
   *  97-01-29   Tomas Berndtsson,
   *               Integrated with Linux 2.1.21 kernel sources.
   *  97-02-15   Tomas Berndtsson,
   *               Fixed for kernel 2.1.26
   *
   * BUGS:
   *  Hmm... there must be something here :)
   *
   * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file COPYING in the main directory of this archive
   * for more details.
   */
  
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
  #include <linux/major.h>
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/delay.h>	/* guess what */
  #include <linux/fs.h>
  #include <linux/mm.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/device.h>
613655fa3   Arnd Bergmann   drivers: autoconv...
35
  #include <linux/mutex.h>
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
36
37
  #include <linux/firmware.h>
  #include <linux/platform_device.h>
236b8756a   Alan Cox   dsp56k: BKL pushdown
38
  #include <linux/uaccess.h>	/* For put_user and get_user */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  
  #include <asm/atarihw.h>
  #include <asm/traps.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  
  #include <asm/dsp56k.h>
  
  /* minor devices */
  #define DSP56K_DEV_56001        0    /* The only device so far */
  
  #define TIMEOUT    10   /* Host port timeout in number of tries */
  #define MAXIO    2048   /* Maximum number of words before sleep */
  #define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
  
  #define DSP56K_TX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
  #define DSP56K_RX_INT_ON	dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
  #define DSP56K_TX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
  #define DSP56K_RX_INT_OFF	dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
  
  #define DSP56K_TRANSMIT		(dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
  #define DSP56K_RECEIVE		(dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
  
  #define handshake(count, maxio, timeout, ENABLE, f) \
  { \
  	long i, t, m; \
  	while (count > 0) { \
  		m = min_t(unsigned long, count, maxio); \
  		for (i = 0; i < m; i++) { \
  			for (t = 0; t < timeout && !ENABLE; t++) \
  				msleep(20); \
  			if(!ENABLE) \
  				return -EIO; \
  			f; \
  		} \
  		count -= m; \
  		if (m == maxio) msleep(20); \
  	} \
  }
  
  #define tx_wait(n) \
  { \
  	int t; \
  	for(t = 0; t < n && !DSP56K_TRANSMIT; t++) \
  		msleep(10); \
  	if(!DSP56K_TRANSMIT) { \
  		return -EIO; \
  	} \
  }
  
  #define rx_wait(n) \
  { \
  	int t; \
  	for(t = 0; t < n && !DSP56K_RECEIVE; t++) \
  		msleep(10); \
  	if(!DSP56K_RECEIVE) { \
  		return -EIO; \
  	} \
  }
613655fa3   Arnd Bergmann   drivers: autoconv...
96
  static DEFINE_MUTEX(dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  static struct dsp56k_device {
64b33619a   Al Viro   long vs. unsigned...
98
  	unsigned long in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
  	long maxio, timeout;
  	int tx_wsize, rx_wsize;
  } dsp56k;
ca8eca688   Greg Kroah-Hartman   [PATCH] class: co...
102
  static struct class *dsp56k_class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  
  static int dsp56k_reset(void)
  {
  	u_char status;
  	
  	/* Power down the DSP */
  	sound_ym.rd_data_reg_sel = 14;
  	status = sound_ym.rd_data_reg_sel & 0xef;
  	sound_ym.wd_data = status;
  	sound_ym.wd_data = status | 0x10;
    
  	udelay(10);
    
  	/* Power up the DSP */
  	sound_ym.rd_data_reg_sel = 14;
  	sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
  
  	return 0;
  }
d85f6891a   Al Viro   [PATCH] m68k: dsp...
122
  static int dsp56k_upload(u_char __user *bin, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  {
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
124
125
126
127
  	struct platform_device *pdev;
  	const struct firmware *fw;
  	const char fw_name[] = "dsp56k/bootstrap.bin";
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  	int i;
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
129

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	dsp56k_reset();
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  
  	pdev = platform_device_register_simple("dsp56k", 0, NULL, 0);
  	if (IS_ERR(pdev)) {
  		printk(KERN_ERR "Failed to register device for \"%s\"
  ",
  		       fw_name);
  		return -EINVAL;
  	}
  	err = request_firmware(&fw, fw_name, &pdev->dev);
  	platform_device_unregister(pdev);
  	if (err) {
  		printk(KERN_ERR "Failed to load image \"%s\" err %d
  ",
  		       fw_name, err);
  		return err;
  	}
  	if (fw->size % 3) {
  		printk(KERN_ERR "Bogus length %d in image \"%s\"
  ",
  		       fw->size, fw_name);
  		release_firmware(fw);
  		return -EINVAL;
  	}
  	for (i = 0; i < fw->size; i = i + 3) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  		/* tx_wait(10); */
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
156
157
158
  		dsp56k_host_interface.data.b[1] = fw->data[i];
  		dsp56k_host_interface.data.b[2] = fw->data[i + 1];
  		dsp56k_host_interface.data.b[3] = fw->data[i + 2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	}
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
160
  	release_firmware(fw);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  	for (; i < 512; i++) {
  		/* tx_wait(10); */
  		dsp56k_host_interface.data.b[1] = 0;
  		dsp56k_host_interface.data.b[2] = 0;
  		dsp56k_host_interface.data.b[3] = 0;
  	}
    
  	for (i = 0; i < len; i++) {
  		tx_wait(10);
  		get_user(dsp56k_host_interface.data.b[1], bin++);
  		get_user(dsp56k_host_interface.data.b[2], bin++);
  		get_user(dsp56k_host_interface.data.b[3], bin++);
  	}
  
  	tx_wait(10);
  	dsp56k_host_interface.data.l = 3;    /* Magic execute */
  
  	return 0;
  }
d85f6891a   Al Viro   [PATCH] m68k: dsp...
180
  static ssize_t dsp56k_read(struct file *file, char __user *buf, size_t count,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
  			   loff_t *ppos)
  {
a7113a966   Josef Sipek   [PATCH] struct pa...
183
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
  	int dev = iminor(inode) & 0x0f;
  
  	switch(dev)
  	{
  	case DSP56K_DEV_56001:
  	{
  
  		long n;
  
  		/* Don't do anything if nothing is to be done */
  		if (!count) return 0;
  
  		n = 0;
  		switch (dsp56k.rx_wsize) {
  		case 1:  /* 8 bit */
  		{
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
  			return n;
  		}
  		case 2:  /* 16 bit */
  		{
d85f6891a   Al Viro   [PATCH] m68k: dsp...
206
  			short __user *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  
  			count /= 2;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
209
  			data = (short __user *) buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  				  put_user(dsp56k_host_interface.data.w[1], data+n++));
  			return 2*n;
  		}
  		case 3:  /* 24 bit */
  		{
  			count /= 3;
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  				  put_user(dsp56k_host_interface.data.b[1], buf+n++);
  				  put_user(dsp56k_host_interface.data.b[2], buf+n++);
  				  put_user(dsp56k_host_interface.data.b[3], buf+n++));
  			return 3*n;
  		}
  		case 4:  /* 32 bit */
  		{
d85f6891a   Al Viro   [PATCH] m68k: dsp...
225
  			long __user *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
  
  			count /= 4;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
228
  			data = (long __user *) buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  				  put_user(dsp56k_host_interface.data.l, data+n++));
  			return 4*n;
  		}
  		}
  		return -EFAULT;
  	}
  
  	default:
  		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d
  ", dev);
  		return -ENXIO;
  	}
  }
d85f6891a   Al Viro   [PATCH] m68k: dsp...
243
  static ssize_t dsp56k_write(struct file *file, const char __user *buf, size_t count,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  			    loff_t *ppos)
  {
a7113a966   Josef Sipek   [PATCH] struct pa...
246
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	int dev = iminor(inode) & 0x0f;
  
  	switch(dev)
  	{
  	case DSP56K_DEV_56001:
  	{
  		long n;
  
  		/* Don't do anything if nothing is to be done */
  		if (!count) return 0;
  
  		n = 0;
  		switch (dsp56k.tx_wsize) {
  		case 1:  /* 8 bit */
  		{
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
  			return n;
  		}
  		case 2:  /* 16 bit */
  		{
d85f6891a   Al Viro   [PATCH] m68k: dsp...
268
  			const short __user *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
  
  			count /= 2;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
271
  			data = (const short __user *)buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  				  get_user(dsp56k_host_interface.data.w[1], data+n++));
  			return 2*n;
  		}
  		case 3:  /* 24 bit */
  		{
  			count /= 3;
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  				  get_user(dsp56k_host_interface.data.b[1], buf+n++);
  				  get_user(dsp56k_host_interface.data.b[2], buf+n++);
  				  get_user(dsp56k_host_interface.data.b[3], buf+n++));
  			return 3*n;
  		}
  		case 4:  /* 32 bit */
  		{
d85f6891a   Al Viro   [PATCH] m68k: dsp...
287
  			const long __user *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  
  			count /= 4;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
290
  			data = (const long __user *)buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  			handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  				  get_user(dsp56k_host_interface.data.l, data+n++));
  			return 4*n;
  		}
  		}
  
  		return -EFAULT;
  	}
  	default:
  		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d
  ", dev);
  		return -ENXIO;
  	}
  }
236b8756a   Alan Cox   dsp56k: BKL pushdown
305
  static long dsp56k_ioctl(struct file *file, unsigned int cmd,
689796a14   Geert Uytterhoeven   dsp56k: Fix BKL p...
306
  			 unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
689796a14   Geert Uytterhoeven   dsp56k: Fix BKL p...
308
  	int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
309
  	void __user *argp = (void __user *)arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
316
317
  
  	switch(dev)
  	{
  	case DSP56K_DEV_56001:
  
  		switch(cmd) {
  		case DSP56K_UPLOAD:
  		{
d85f6891a   Al Viro   [PATCH] m68k: dsp...
318
  			char __user *bin;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  			int r, len;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
320
  			struct dsp56k_upload __user *binary = argp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
325
326
327
328
329
330
331
332
      
  			if(get_user(len, &binary->len) < 0)
  				return -EFAULT;
  			if(get_user(bin, &binary->bin) < 0)
  				return -EFAULT;
  		
  			if (len == 0) {
  				return -EINVAL;      /* nothing to upload?!? */
  			}
  			if (len > DSP56K_MAX_BINARY_LENGTH) {
  				return -EINVAL;
  			}
613655fa3   Arnd Bergmann   drivers: autoconv...
333
  			mutex_lock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  			r = dsp56k_upload(bin, len);
613655fa3   Arnd Bergmann   drivers: autoconv...
335
  			mutex_unlock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
  			if (r < 0) {
  				return r;
  			}
      
  			break;
  		}
  		case DSP56K_SET_TX_WSIZE:
  			if (arg > 4 || arg < 1)
  				return -EINVAL;
613655fa3   Arnd Bergmann   drivers: autoconv...
345
  			mutex_lock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  			dsp56k.tx_wsize = (int) arg;
613655fa3   Arnd Bergmann   drivers: autoconv...
347
  			mutex_unlock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
  			break;
  		case DSP56K_SET_RX_WSIZE:
  			if (arg > 4 || arg < 1)
  				return -EINVAL;
613655fa3   Arnd Bergmann   drivers: autoconv...
352
  			mutex_lock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  			dsp56k.rx_wsize = (int) arg;
613655fa3   Arnd Bergmann   drivers: autoconv...
354
  			mutex_unlock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
  			break;
  		case DSP56K_HOST_FLAGS:
  		{
  			int dir, out, status;
d85f6891a   Al Viro   [PATCH] m68k: dsp...
359
  			struct dsp56k_host_flags __user *hf = argp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
364
      
  			if(get_user(dir, &hf->dir) < 0)
  				return -EFAULT;
  			if(get_user(out, &hf->out) < 0)
  				return -EFAULT;
613655fa3   Arnd Bergmann   drivers: autoconv...
365
  			mutex_lock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  			if ((dir & 0x1) && (out & 0x1))
  				dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
  			else if (dir & 0x1)
  				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
  			if ((dir & 0x2) && (out & 0x2))
  				dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
  			else if (dir & 0x2)
  				dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
  
  			status = 0;
  			if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
  			if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
  			if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
  			if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
613655fa3   Arnd Bergmann   drivers: autoconv...
380
  			mutex_unlock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
  			return put_user(status, &hf->status);
  		}
  		case DSP56K_HOST_CMD:
  			if (arg > 31 || arg < 0)
  				return -EINVAL;
613655fa3   Arnd Bergmann   drivers: autoconv...
386
  			mutex_lock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  			dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
  							     DSP56K_CVR_HC);
613655fa3   Arnd Bergmann   drivers: autoconv...
389
  			mutex_unlock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  			break;
  		default:
  			return -EINVAL;
  		}
  		return 0;
  
  	default:
  		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d
  ", dev);
  		return -ENXIO;
  	}
  }
  
  /* As of 2.1.26 this should be dsp56k_poll,
   * but how do I then check device minor number?
   * Do I need this function at all???
   */
  #if 0
  static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
  {
a7113a966   Josef Sipek   [PATCH] struct pa...
410
  	int dev = iminor(file->f_path.dentry->d_inode) & 0x0f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  
  	switch(dev)
  	{
  	case DSP56K_DEV_56001:
  		/* poll_wait(file, ???, wait); */
  		return POLLIN | POLLRDNORM | POLLOUT;
  
  	default:
  		printk("DSP56k driver: Unknown minor device: %d
  ", dev);
  		return 0;
  	}
  }
  #endif
  
  static int dsp56k_open(struct inode *inode, struct file *file)
  {
  	int dev = iminor(inode) & 0x0f;
65f37b790   Jonathan Corbet   dsp56k: BKL pushdown
429
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430

613655fa3   Arnd Bergmann   drivers: autoconv...
431
  	mutex_lock(&dsp56k_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
  	switch(dev)
  	{
  	case DSP56K_DEV_56001:
65f37b790   Jonathan Corbet   dsp56k: BKL pushdown
435
436
437
438
  		if (test_and_set_bit(0, &dsp56k.in_use)) {
  			ret = -EBUSY;
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
  
  		dsp56k.timeout = TIMEOUT;
  		dsp56k.maxio = MAXIO;
  		dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
  
  		DSP56K_TX_INT_OFF;
  		DSP56K_RX_INT_OFF;
  
  		/* Zero host flags */
  		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
  		dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
  
  		break;
  
  	default:
65f37b790   Jonathan Corbet   dsp56k: BKL pushdown
454
  		ret = -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
  	}
65f37b790   Jonathan Corbet   dsp56k: BKL pushdown
456
  out:
613655fa3   Arnd Bergmann   drivers: autoconv...
457
  	mutex_unlock(&dsp56k_mutex);
65f37b790   Jonathan Corbet   dsp56k: BKL pushdown
458
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  }
  
  static int dsp56k_release(struct inode *inode, struct file *file)
  {
  	int dev = iminor(inode) & 0x0f;
  
  	switch(dev)
  	{
  	case DSP56K_DEV_56001:
  		clear_bit(0, &dsp56k.in_use);
  		break;
  	default:
  		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d
  ", dev);
  		return -ENXIO;
  	}
  
  	return 0;
  }
62322d255   Arjan van de Ven   [PATCH] make more...
478
  static const struct file_operations dsp56k_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
  	.owner		= THIS_MODULE,
  	.read		= dsp56k_read,
  	.write		= dsp56k_write,
236b8756a   Alan Cox   dsp56k: BKL pushdown
482
  	.unlocked_ioctl	= dsp56k_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
  	.open		= dsp56k_open,
  	.release	= dsp56k_release,
6038f373a   Arnd Bergmann   llseek: automatic...
485
  	.llseek		= noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
  };
  
  
  /****** Init and module functions ******/
  
  static char banner[] __initdata = KERN_INFO "DSP56k driver installed
  ";
  
  static int __init dsp56k_init_driver(void)
  {
  	int err = 0;
  
  	if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
  		printk("DSP56k driver: Hardware not present
  ");
  		return -ENODEV;
  	}
  
  	if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
  		printk("DSP56k driver: Unable to register driver
  ");
  		return -ENODEV;
  	}
ca8eca688   Greg Kroah-Hartman   [PATCH] class: co...
509
  	dsp56k_class = class_create(THIS_MODULE, "dsp56k");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
  	if (IS_ERR(dsp56k_class)) {
  		err = PTR_ERR(dsp56k_class);
  		goto out_chrdev;
  	}
03457cd45   Greg Kroah-Hartman   device create: ch...
514
515
  	device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL,
  		      "dsp56k");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  	printk(banner);
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
523
524
525
526
527
  out_chrdev:
  	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
  out:
  	return err;
  }
  module_init(dsp56k_init_driver);
  
  static void __exit dsp56k_cleanup_driver(void)
  {
07c015e76   tonyj@suse.de   Convert from clas...
528
  	device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
ca8eca688   Greg Kroah-Hartman   [PATCH] class: co...
529
  	class_destroy(dsp56k_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
533
534
  }
  module_exit(dsp56k_cleanup_driver);
  
  MODULE_LICENSE("GPL");
7f127d5ed   Jaswinder Singh   dsp56k: use reque...
535
  MODULE_FIRMWARE("dsp56k/bootstrap.bin");