dsp56k.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:13k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * The DSP56001 Device Driver, saviour of the Free World(tm)
  3.  *
  4.  * Authors: Fredrik Noring   <noring@nocrew.org>
  5.  *          lars brinkhoff   <lars@nocrew.org>
  6.  *          Tomas Berndtsson <tomas@nocrew.org>
  7.  *
  8.  * First version May 1996
  9.  *
  10.  * History:
  11.  *  97-01-29   Tomas Berndtsson,
  12.  *               Integrated with Linux 2.1.21 kernel sources.
  13.  *  97-02-15   Tomas Berndtsson,
  14.  *               Fixed for kernel 2.1.26
  15.  *
  16.  * BUGS:
  17.  *  Hmm... there must be something here :)
  18.  *
  19.  * Copyright (C) 1996,1997 Fredrik Noring, lars brinkhoff & Tomas Berndtsson
  20.  *
  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
  23.  * for more details.
  24.  */
  25. #include <linux/module.h>
  26. #include <linux/version.h>
  27. #include <linux/slab.h> /* for kmalloc() and kfree() */
  28. #include <linux/sched.h> /* for struct wait_queue etc */
  29. #include <linux/major.h>
  30. #include <linux/types.h>
  31. #include <linux/errno.h>
  32. #include <linux/delay.h> /* guess what */
  33. #include <linux/fs.h>
  34. #include <linux/mm.h>
  35. #include <linux/init.h>
  36. #include <linux/devfs_fs_kernel.h>
  37. #include <linux/smp_lock.h>
  38. #include <asm/segment.h>
  39. #include <asm/atarihw.h>
  40. #include <asm/traps.h>
  41. #include <asm/uaccess.h> /* For put_user and get_user */
  42. #include <asm/dsp56k.h>
  43. /* minor devices */
  44. #define DSP56K_DEV_56001        0    /* The only device so far */
  45. #define TIMEOUT    10   /* Host port timeout in number of tries */
  46. #define MAXIO    2048   /* Maximum number of words before sleep */
  47. #define DSP56K_MAX_BINARY_LENGTH (3*64*1024)
  48. #define DSP56K_TX_INT_ON dsp56k_host_interface.icr |=  DSP56K_ICR_TREQ
  49. #define DSP56K_RX_INT_ON dsp56k_host_interface.icr |=  DSP56K_ICR_RREQ
  50. #define DSP56K_TX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_TREQ
  51. #define DSP56K_RX_INT_OFF dsp56k_host_interface.icr &= ~DSP56K_ICR_RREQ
  52. #define DSP56K_TRANSMIT (dsp56k_host_interface.isr & DSP56K_ISR_TXDE)
  53. #define DSP56K_RECEIVE (dsp56k_host_interface.isr & DSP56K_ISR_RXDF)
  54. #define wait_some(n) 
  55. set_current_state(TASK_INTERRUPTIBLE); 
  56. schedule_timeout(n); 
  57. }
  58. #define handshake(count, maxio, timeout, ENABLE, f) 
  59. long i, t, m; 
  60. while (count > 0) { 
  61. m = min_t(unsigned long, count, maxio); 
  62. for (i = 0; i < m; i++) { 
  63. for (t = 0; t < timeout && !ENABLE; t++) 
  64. wait_some(HZ/50); 
  65. if(!ENABLE) 
  66. return -EIO; 
  67. f; 
  68. count -= m; 
  69. if (m == maxio) wait_some(HZ/50); 
  70. }
  71. #define tx_wait(n) 
  72. int t; 
  73. for(t = 0; t < n && !DSP56K_TRANSMIT; t++) 
  74. wait_some(HZ/100); 
  75. if(!DSP56K_TRANSMIT) { 
  76. return -EIO; 
  77. }
  78. #define rx_wait(n) 
  79. int t; 
  80. for(t = 0; t < n && !DSP56K_RECEIVE; t++) 
  81. wait_some(HZ/100); 
  82. if(!DSP56K_RECEIVE) { 
  83. return -EIO; 
  84. }
  85. /* DSP56001 bootstrap code */
  86. static char bootstrap[] = {
  87. 0x0c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  88. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  89. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  90. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  91. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  92. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  93. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  94. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  95. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  96. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  97. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  98. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  99. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  100. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  101. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  102. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  103. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  104. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  105. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  106. 0x00, 0x00, 0x60, 0xf4, 0x00, 0x00, 0x00, 0x4f, 0x61, 0xf4,
  107. 0x00, 0x00, 0x7e, 0xa9, 0x06, 0x2e, 0x80, 0x00, 0x00, 0x47,
  108. 0x07, 0xd8, 0x84, 0x07, 0x59, 0x84, 0x08, 0xf4, 0xa8, 0x00,
  109. 0x00, 0x04, 0x08, 0xf4, 0xbf, 0x00, 0x0c, 0x00, 0x00, 0xfe,
  110. 0xb8, 0x0a, 0xf0, 0x80, 0x00, 0x7e, 0xa9, 0x08, 0xf4, 0xa0,
  111. 0x00, 0x00, 0x01, 0x08, 0xf4, 0xbe, 0x00, 0x00, 0x00, 0x0a,
  112. 0xa9, 0x80, 0x00, 0x7e, 0xad, 0x08, 0x4e, 0x2b, 0x44, 0xf4,
  113. 0x00, 0x00, 0x00, 0x03, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x01,
  114. 0x0e, 0xa0, 0x00, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb5, 0x08,
  115. 0x50, 0x2b, 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xb8, 0x08, 0x46,
  116. 0x2b, 0x44, 0xf4, 0x45, 0x00, 0x00, 0x02, 0x0a, 0xf0, 0xaa,
  117. 0x00, 0x7e, 0xc9, 0x20, 0x00, 0x45, 0x0a, 0xf0, 0xaa, 0x00,
  118. 0x7e, 0xd0, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xc6, 0x0a, 0xa9,
  119. 0x80, 0x00, 0x7e, 0xc4, 0x08, 0x58, 0x6b, 0x0a, 0xf0, 0x80,
  120. 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xcd, 0x0a,
  121. 0xa9, 0x80, 0x00, 0x7e, 0xcb, 0x08, 0x58, 0xab, 0x0a, 0xf0,
  122. 0x80, 0x00, 0x7e, 0xad, 0x06, 0xc6, 0x00, 0x00, 0x7e, 0xd4,
  123. 0x0a, 0xa9, 0x80, 0x00, 0x7e, 0xd2, 0x08, 0x58, 0xeb, 0x0a,
  124. 0xf0, 0x80, 0x00, 0x7e, 0xad};
  125. static int sizeof_bootstrap = 375;
  126. static struct dsp56k_device {
  127. long in_use;
  128. long maxio, timeout;
  129. int tx_wsize, rx_wsize;
  130. } dsp56k;
  131. static int dsp56k_reset(void)
  132. {
  133. u_char status;
  134. /* Power down the DSP */
  135. sound_ym.rd_data_reg_sel = 14;
  136. status = sound_ym.rd_data_reg_sel & 0xef;
  137. sound_ym.wd_data = status;
  138. sound_ym.wd_data = status | 0x10;
  139.   
  140. udelay(10);
  141.   
  142. /* Power up the DSP */
  143. sound_ym.rd_data_reg_sel = 14;
  144. sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xef;
  145. return 0;
  146. }
  147. static int dsp56k_upload(u_char *bin, int len)
  148. {
  149. int i;
  150. u_char *p;
  151. dsp56k_reset();
  152.   
  153. p = bootstrap;
  154. for (i = 0; i < sizeof_bootstrap/3; i++) {
  155. /* tx_wait(10); */
  156. dsp56k_host_interface.data.b[1] = *p++;
  157. dsp56k_host_interface.data.b[2] = *p++;
  158. dsp56k_host_interface.data.b[3] = *p++;
  159. }
  160. for (; i < 512; i++) {
  161. /* tx_wait(10); */
  162. dsp56k_host_interface.data.b[1] = 0;
  163. dsp56k_host_interface.data.b[2] = 0;
  164. dsp56k_host_interface.data.b[3] = 0;
  165. }
  166.   
  167. for (i = 0; i < len; i++) {
  168. tx_wait(10);
  169. get_user(dsp56k_host_interface.data.b[1], bin++);
  170. get_user(dsp56k_host_interface.data.b[2], bin++);
  171. get_user(dsp56k_host_interface.data.b[3], bin++);
  172. }
  173. tx_wait(10);
  174. dsp56k_host_interface.data.l = 3;    /* Magic execute */
  175. return 0;
  176. }
  177. static ssize_t dsp56k_read(struct file *file, char *buf, size_t count,
  178.    loff_t *ppos)
  179. {
  180. struct inode *inode = file->f_dentry->d_inode;
  181. int dev = MINOR(inode->i_rdev) & 0x0f;
  182. switch(dev)
  183. {
  184. case DSP56K_DEV_56001:
  185. {
  186. long n;
  187. /* Don't do anything if nothing is to be done */
  188. if (!count) return 0;
  189. n = 0;
  190. switch (dsp56k.rx_wsize) {
  191. case 1:  /* 8 bit */
  192. {
  193. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  194.   put_user(dsp56k_host_interface.data.b[3], buf+n++));
  195. return n;
  196. }
  197. case 2:  /* 16 bit */
  198. {
  199. short *data;
  200. count /= 2;
  201. data = (short*) buf;
  202. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  203.   put_user(dsp56k_host_interface.data.w[1], data+n++));
  204. return 2*n;
  205. }
  206. case 3:  /* 24 bit */
  207. {
  208. count /= 3;
  209. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  210.   put_user(dsp56k_host_interface.data.b[1], buf+n++);
  211.   put_user(dsp56k_host_interface.data.b[2], buf+n++);
  212.   put_user(dsp56k_host_interface.data.b[3], buf+n++));
  213. return 3*n;
  214. }
  215. case 4:  /* 32 bit */
  216. {
  217. long *data;
  218. count /= 4;
  219. data = (long*) buf;
  220. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_RECEIVE,
  221.   put_user(dsp56k_host_interface.data.l, data+n++));
  222. return 4*n;
  223. }
  224. }
  225. return -EFAULT;
  226. }
  227. default:
  228. printk(KERN_ERR "DSP56k driver: Unknown minor device: %dn", dev);
  229. return -ENXIO;
  230. }
  231. }
  232. static ssize_t dsp56k_write(struct file *file, const char *buf, size_t count,
  233.     loff_t *ppos)
  234. {
  235. struct inode *inode = file->f_dentry->d_inode;
  236. int dev = MINOR(inode->i_rdev) & 0x0f;
  237. switch(dev)
  238. {
  239. case DSP56K_DEV_56001:
  240. {
  241. long n;
  242. /* Don't do anything if nothing is to be done */
  243. if (!count) return 0;
  244. n = 0;
  245. switch (dsp56k.tx_wsize) {
  246. case 1:  /* 8 bit */
  247. {
  248. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  249.   get_user(dsp56k_host_interface.data.b[3], buf+n++));
  250. return n;
  251. }
  252. case 2:  /* 16 bit */
  253. {
  254. short *data;
  255. count /= 2;
  256. data = (short*) buf;
  257. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  258.   get_user(dsp56k_host_interface.data.w[1], data+n++));
  259. return 2*n;
  260. }
  261. case 3:  /* 24 bit */
  262. {
  263. count /= 3;
  264. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  265.   get_user(dsp56k_host_interface.data.b[1], buf+n++);
  266.   get_user(dsp56k_host_interface.data.b[2], buf+n++);
  267.   get_user(dsp56k_host_interface.data.b[3], buf+n++));
  268. return 3*n;
  269. }
  270. case 4:  /* 32 bit */
  271. {
  272. long *data;
  273. count /= 4;
  274. data = (long*) buf;
  275. handshake(count, dsp56k.maxio, dsp56k.timeout, DSP56K_TRANSMIT,
  276.   get_user(dsp56k_host_interface.data.l, data+n++));
  277. return 4*n;
  278. }
  279. }
  280. return -EFAULT;
  281. }
  282. default:
  283. printk(KERN_ERR "DSP56k driver: Unknown minor device: %dn", dev);
  284. return -ENXIO;
  285. }
  286. }
  287. static int dsp56k_ioctl(struct inode *inode, struct file *file,
  288. unsigned int cmd, unsigned long arg)
  289. {
  290. int dev = MINOR(inode->i_rdev) & 0x0f;
  291. switch(dev)
  292. {
  293. case DSP56K_DEV_56001:
  294. switch(cmd) {
  295. case DSP56K_UPLOAD:
  296. {
  297. char *bin;
  298. int r, len;
  299. struct dsp56k_upload *binary = (struct dsp56k_upload *) arg;
  300.     
  301. if(get_user(len, &binary->len) < 0)
  302. return -EFAULT;
  303. if(get_user(bin, &binary->bin) < 0)
  304. return -EFAULT;
  305. if (len == 0) {
  306. return -EINVAL;      /* nothing to upload?!? */
  307. }
  308. if (len > DSP56K_MAX_BINARY_LENGTH) {
  309. return -EINVAL;
  310. }
  311.     
  312. r = dsp56k_upload(bin, len);
  313. if (r < 0) {
  314. return r;
  315. }
  316.     
  317. break;
  318. }
  319. case DSP56K_SET_TX_WSIZE:
  320. if (arg > 4 || arg < 1)
  321. return -EINVAL;
  322. dsp56k.tx_wsize = (int) arg;
  323. break;
  324. case DSP56K_SET_RX_WSIZE:
  325. if (arg > 4 || arg < 1)
  326. return -EINVAL;
  327. dsp56k.rx_wsize = (int) arg;
  328. break;
  329. case DSP56K_HOST_FLAGS:
  330. {
  331. int dir, out, status;
  332. struct dsp56k_host_flags *hf = (struct dsp56k_host_flags*) arg;
  333.     
  334. if(get_user(dir, &hf->dir) < 0)
  335. return -EFAULT;
  336. if(get_user(out, &hf->out) < 0)
  337. return -EFAULT;
  338. if ((dir & 0x1) && (out & 0x1))
  339. dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
  340. else if (dir & 0x1)
  341. dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
  342. if ((dir & 0x2) && (out & 0x2))
  343. dsp56k_host_interface.icr |= DSP56K_ICR_HF1;
  344. else if (dir & 0x2)
  345. dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
  346. status = 0;
  347. if (dsp56k_host_interface.icr & DSP56K_ICR_HF0) status |= 0x1;
  348. if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
  349. if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
  350. if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
  351. return put_user(status, &hf->status);
  352. }
  353. case DSP56K_HOST_CMD:
  354. if (arg > 31 || arg < 0)
  355. return -EINVAL;
  356. dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
  357.      DSP56K_CVR_HC);
  358. break;
  359. default:
  360. return -EINVAL;
  361. }
  362. return 0;
  363. default:
  364. printk(KERN_ERR "DSP56k driver: Unknown minor device: %dn", dev);
  365. return -ENXIO;
  366. }
  367. }
  368. /* As of 2.1.26 this should be dsp56k_poll,
  369.  * but how do I then check device minor number?
  370.  * Do I need this function at all???
  371.  */
  372. #if 0
  373. static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
  374. {
  375. int dev = MINOR(file->f_dentry->d_inode->i_rdev) & 0x0f;
  376. switch(dev)
  377. {
  378. case DSP56K_DEV_56001:
  379. /* poll_wait(file, ???, wait); */
  380. return POLLIN | POLLRDNORM | POLLOUT;
  381. default:
  382. printk("DSP56k driver: Unknown minor device: %dn", dev);
  383. return 0;
  384. }
  385. }
  386. #endif
  387. static int dsp56k_open(struct inode *inode, struct file *file)
  388. {
  389. int dev = MINOR(inode->i_rdev) & 0x0f;
  390. switch(dev)
  391. {
  392. case DSP56K_DEV_56001:
  393. if (test_and_set_bit(0, &dsp56k.in_use))
  394. return -EBUSY;
  395. dsp56k.timeout = TIMEOUT;
  396. dsp56k.maxio = MAXIO;
  397. dsp56k.rx_wsize = dsp56k.tx_wsize = 4; 
  398. DSP56K_TX_INT_OFF;
  399. DSP56K_RX_INT_OFF;
  400. /* Zero host flags */
  401. dsp56k_host_interface.icr &= ~DSP56K_ICR_HF0;
  402. dsp56k_host_interface.icr &= ~DSP56K_ICR_HF1;
  403. break;
  404. default:
  405. return -ENODEV;
  406. }
  407. return 0;
  408. }
  409. static int dsp56k_release(struct inode *inode, struct file *file)
  410. {
  411. int dev = MINOR(inode->i_rdev) & 0x0f;
  412. switch(dev)
  413. {
  414. case DSP56K_DEV_56001:
  415. clear_bit(0, &dsp56k.in_use);
  416. break;
  417. default:
  418. printk(KERN_ERR "DSP56k driver: Unknown minor device: %dn", dev);
  419. return -ENXIO;
  420. }
  421. return 0;
  422. }
  423. static struct file_operations dsp56k_fops = {
  424. owner: THIS_MODULE,
  425. read: dsp56k_read,
  426. write: dsp56k_write,
  427. ioctl: dsp56k_ioctl,
  428. open: dsp56k_open,
  429. release: dsp56k_release,
  430. };
  431. /****** Init and module functions ******/
  432. static devfs_handle_t devfs_handle;
  433. static char banner[] __initdata = KERN_INFO "DSP56k driver installedn";
  434. static int __init dsp56k_init_driver(void)
  435. {
  436. if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
  437. printk("DSP56k driver: Hardware not presentn");
  438. return -ENODEV;
  439. }
  440. if(devfs_register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
  441. printk("DSP56k driver: Unable to register drivern");
  442. return -ENODEV;
  443. }
  444. devfs_handle = devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT,
  445.       DSP56K_MAJOR, 0,
  446.       S_IFCHR | S_IRUSR | S_IWUSR,
  447.       &dsp56k_fops, NULL);
  448. printk(banner);
  449. return 0;
  450. }
  451. module_init(dsp56k_init_driver);
  452. static void __exit dsp56k_cleanup_driver(void)
  453. {
  454. devfs_unregister_chrdev(DSP56K_MAJOR, "dsp56k");
  455. devfs_unregister(devfs_handle);
  456. }
  457. module_exit(dsp56k_cleanup_driver);
  458. MODULE_LICENSE("GPL");