2 * linux/arch/arm/mach-omap/dsp/dsp_ctl.c
4 * OMAP DSP control device driver
6 * Copyright (C) 2002-2005 Nokia Corporation
8 * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * 2005/06/09: DSP Gateway version 3.3
27 #include <linux/module.h>
28 #include <linux/slab.h>
29 #include <linux/major.h>
31 #include <linux/device.h>
32 #include <linux/proc_fs.h>
33 #include <linux/init.h>
34 #include <linux/sched.h>
35 #include <linux/delay.h>
36 #include <linux/platform_device.h>
37 #include <asm/uaccess.h>
39 #include <asm/ioctls.h>
40 #include <asm/hardware/clock.h>
41 #include <asm/arch/dsp.h>
42 #include "hardware_dsp.h"
46 static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
48 static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
49 extern struct device_attribute dev_attr_ipbuf;
57 static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q);
58 static unsigned short ioctl_wait_cmd;
59 static DECLARE_MUTEX(ioctl_sem);
61 static unsigned char n_stask;
66 static short varread_val[5]; /* maximum */
68 static int dsp_regread(unsigned short cmd_l, unsigned short adr,
74 if (down_interruptible(&ioctl_sem))
77 ioctl_wait_cmd = MBCMD(REGRW);
78 mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
79 dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
81 if (ioctl_wait_cmd != 0) {
82 printk(KERN_ERR "omapdsp: register read error!\n");
87 *val = varread_val[0];
94 static int dsp_regwrite(unsigned short cmd_l, unsigned short adr,
98 struct mb_exarg arg = {
99 .tid = OMAP_DSP_TID_ANON,
104 mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
105 dsp_mbcmd_send_exarg(&mb, &arg);
109 static int dsp_getvar(unsigned char varid, unsigned short *val, int sz)
114 if (down_interruptible(&ioctl_sem))
117 ioctl_wait_cmd = MBCMD(GETVAR);
118 mbcmd_set(mb, MBCMD(GETVAR), varid, 0);
119 dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
121 if (ioctl_wait_cmd != 0) {
122 printk(KERN_ERR "omapdsp: variable read error!\n");
127 memcpy(val, varread_val, sz * sizeof(short));
134 static int dsp_setvar(unsigned char varid, unsigned short val)
136 dsp_mbsend(MBCMD(SETVAR), varid, val);
140 static int dspcfg(void)
145 if (down_interruptible(&ioctl_sem))
148 if (cfgstat != CFG_ERR) {
150 "omapdsp: DSP has been already configured. "
157 dsp_mem_usecount_clear();
160 * DSPCFG command and dsp_mem_start() must be called
161 * while internal mem is on.
163 dsp_mem_enable((void *)dspmem_base);
171 ioctl_wait_cmd = MBCMD(DSPCFG);
172 mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0);
173 dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
175 if (ioctl_wait_cmd != 0) {
176 printk(KERN_ERR "omapdsp: configuration error!\n");
182 #ifdef OLD_BINARY_SUPPORT
184 * MBREV 3.2 or earlier doesn't assume DMA domain is on
185 * when DSPCFG command is sent
187 if ((mbx_revision == MBREV_3_0) ||
188 (mbx_revision == MBREV_3_2)) {
189 ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
190 DSPREG_ICR_DMA_IDLE_DOMAIN);
194 if ((ret = dsp_task_config_all(n_stask)) < 0) {
197 dsp_mem_disable((void *)dspmem_base);
204 if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK,
205 dsp_cpustat_get_icrmask())) < 0)
208 /* create runtime sysfs entries */
209 device_create_file(&dsp_device.dev, &dev_attr_loadinfo);
210 device_create_file(&dsp_device.dev, &dev_attr_ipbuf);
213 dsp_mem_disable((void *)dspmem_base);
220 if (dsp_taskmod_busy()) {
221 printk(KERN_WARNING "omapdsp: tasks are busy.\n");
225 if (down_interruptible(&ioctl_sem))
228 /* FIXME: lock task module */
230 /* remove runtime sysfs entries */
231 device_remove_file(&dsp_device.dev, &dev_attr_loadinfo);
232 device_remove_file(&dsp_device.dev, &dev_attr_ipbuf);
239 dsp_task_unconfig_all();
247 int dsp_is_ready(void)
249 return (cfgstat == CFG_READY) ? 1 : 0;
260 if (down_interruptible(&ioctl_sem))
263 ioctl_wait_cmd = MBCMD(POLL);
264 mbcmd_set(mb, MBCMD(POLL), 0, 0);
265 dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
267 if (ioctl_wait_cmd != 0) {
268 printk(KERN_ERR "omapdsp: poll error!\n");
278 void dsp_runlevel(unsigned char level)
280 if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY)
281 dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0);
283 dsp_mbsend(MBCMD(RUNLEVEL), level, 0);
286 static enum cfgstat cfgstat_save_suspend;
289 * suspend / resume callbacks
290 * DSP is not reset within this code, but done in omap_pm_suspend.
291 * so if these functions are called as OMAP_DSP_IOCTL_SUSPEND,
292 * DSP should be reset / unreset out of these functions.
294 int dsp_suspend(void)
299 if (cfgstat == CFG_SUSPEND) {
300 printk(KERN_ERR "omapdsp: DSP is already in suspend state.\n");
304 if (down_interruptible(&ioctl_sem))
307 cfgstat_save_suspend = cfgstat;
308 if (!dsp_is_ready()) {
309 if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
311 "omapdsp: illegal operation: trying suspend DSP "
312 "while it is running but has not configured "
314 " Resetting DSP...\n");
319 ioctl_wait_cmd = MBCMD(SUSPEND);
320 mbcmd_set(mb, MBCMD(SUSPEND), 0, 0);
321 dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
323 if (ioctl_wait_cmd != 0) {
324 printk(KERN_ERR "omapdsp: DSP suspend error!\n");
331 cfgstat = CFG_SUSPEND;
339 if (cfgstat != CFG_SUSPEND) {
340 printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n");
344 cfgstat = cfgstat_save_suspend;
348 static void dsp_fbctl_enable(void)
350 dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
351 OMAP_DSP_MBCMD_FBCTL_ENABLE);
354 static int dsp_fbctl_disable(void)
359 if (down_interruptible(&ioctl_sem))
362 ioctl_wait_cmd = MBCMD(KFUNC);
363 mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
364 OMAP_DSP_MBCMD_FBCTL_DISABLE);
365 dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
366 if (ioctl_wait_cmd != 0) {
367 printk(KERN_ERR "omapdsp: fb disable error!\n");
376 * DSP control device file operations
378 static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
379 unsigned int cmd, unsigned long arg)
385 * command level 1: commands which don't need lock
387 case OMAP_DSP_IOCTL_RUN:
388 dsp_cpustat_request(CPUSTAT_RUN);
391 case OMAP_DSP_IOCTL_RESET:
392 dsp_cpustat_request(CPUSTAT_RESET);
395 case OMAP_DSP_IOCTL_SETRSTVECT:
396 ret = dsp_set_rstvect((unsigned long)arg);
399 case OMAP_DSP_IOCTL_CPU_IDLE:
400 dsp_cpustat_request(CPUSTAT_CPU_IDLE);
403 case OMAP_DSP_IOCTL_GBL_IDLE:
404 dsp_cpustat_request(CPUSTAT_GBL_IDLE);
407 case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON:
411 case OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF:
415 case OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON:
419 case OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF:
423 case OMAP_DSP_IOCTL_MBSEND:
425 struct omap_dsp_mailbox_cmd u_cmd;
427 if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
430 mb.data = u_cmd.data;
431 ret = dsp_mbcmd_send((struct mbcmd *)&mb);
435 case OMAP_DSP_IOCTL_SETVAR:
437 struct omap_dsp_varinfo var;
438 if (copy_from_user(&var, (void *)arg, sizeof(var)))
440 ret = dsp_setvar(var.varid, var.val[0]);
444 case OMAP_DSP_IOCTL_RUNLEVEL:
448 case OMAP_DSP_IOCTL_FBEN:
453 * command level 2: commands which need lock
455 case OMAP_DSP_IOCTL_DSPCFG:
459 case OMAP_DSP_IOCTL_DSPUNCFG:
463 case OMAP_DSP_IOCTL_TASKCNT:
464 ret = dsp_task_count();
467 case OMAP_DSP_IOCTL_POLL:
471 case OMAP_DSP_IOCTL_FBDIS:
472 ret = dsp_fbctl_disable();
476 * FIXME: cpu status control for suspend - resume
478 case OMAP_DSP_IOCTL_SUSPEND:
479 if ((ret = dsp_suspend()) < 0)
481 dsp_cpustat_request(CPUSTAT_RESET);
484 case OMAP_DSP_IOCTL_RESUME:
485 if ((ret = dsp_resume()) < 0)
487 dsp_cpustat_request(CPUSTAT_RUN);
490 case OMAP_DSP_IOCTL_REGMEMR:
492 struct omap_dsp_reginfo *u_reg = (void *)arg;
493 unsigned short adr, val;
495 if (copy_from_user(&adr, &u_reg->adr, sizeof(short)))
497 if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_MEMR,
500 if (copy_to_user(&u_reg->val, &val, sizeof(short)))
505 case OMAP_DSP_IOCTL_REGMEMW:
507 struct omap_dsp_reginfo reg;
509 if (copy_from_user(®, (void *)arg, sizeof(reg)))
511 ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_MEMW,
516 case OMAP_DSP_IOCTL_REGIOR:
518 struct omap_dsp_reginfo *u_reg = (void *)arg;
519 unsigned short adr, val;
521 if (copy_from_user(&adr, &u_reg->adr, sizeof(short)))
523 if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_IOR,
526 if (copy_to_user(&u_reg->val, &val, sizeof(short)))
531 case OMAP_DSP_IOCTL_REGIOW:
533 struct omap_dsp_reginfo reg;
535 if (copy_from_user(®, (void *)arg, sizeof(reg)))
537 ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_IOW,
542 case OMAP_DSP_IOCTL_GETVAR:
544 struct omap_dsp_varinfo *u_var = (void *)arg;
546 unsigned short val[5]; /* maximum */
549 if (copy_from_user(&varid, &u_var->varid, sizeof(char)))
552 case OMAP_DSP_MBCMD_VARID_ICRMASK:
555 case OMAP_DSP_MBCMD_VARID_LOADINFO:
561 if ((ret = dsp_getvar(varid, val, argc)) < 0)
563 if (copy_to_user(&u_var->val, val, sizeof(short) * argc))
576 * functions called from mailbox1 interrupt routine
578 void mbx1_suspend(struct mbcmd *mb)
580 if (!waitqueue_active(&ioctl_wait_q) ||
581 (ioctl_wait_cmd != MBCMD(SUSPEND))) {
583 "mbx: SUSPEND command received, "
584 "but nobody is waiting for it...\n");
589 wake_up_interruptible(&ioctl_wait_q);
592 void mbx1_dspcfg(struct mbcmd *mb)
594 unsigned char last = mb->cmd_l & 0x80;
595 unsigned char cfgcmd = mb->cmd_l & 0x7f;
596 static unsigned long tmp_ipb_adr;
598 /* mailbox protocol check */
599 if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) {
600 if (!waitqueue_active(&ioctl_wait_q) ||
601 (ioctl_wait_cmd != MBCMD(DSPCFG))) {
603 "mbx: DSPCFG command received, "
604 "but nobody is waiting for it...\n");
608 mbx_revision = mb->data;
609 if (mbx_revision == OMAP_DSP_MBPROT_REVISION)
611 #ifdef OLD_BINARY_SUPPORT
612 else if ((mbx_revision == MBREV_3_0) ||
613 (mbx_revision == MBREV_3_2)) {
615 "mbx: ***** old DSP binary *****\n"
616 " Please update your DSP application.\n");
622 "mbx: protocol revision check error!\n"
623 " expected=0x%04x, received=0x%04x\n",
624 OMAP_DSP_MBPROT_REVISION, mb->data);
631 * following commands are accepted only after
632 * revision check has been passed.
634 if (!mbx_revision < 0) {
636 "mbx: DSPCFG command received, "
637 "but revision check has not been passed.\n");
641 if (!waitqueue_active(&ioctl_wait_q) ||
642 (ioctl_wait_cmd != MBCMD(DSPCFG))) {
644 "mbx: DSPCFG command received, "
645 "but nobody is waiting for it...\n");
650 case OMAP_DSP_MBCMD_DSPCFG_SYSADRH:
651 tmp_ipb_adr = (unsigned long)mb->data << 16;
654 case OMAP_DSP_MBCMD_DSPCFG_SYSADRL:
655 tmp_ipb_adr |= mb->data;
658 case OMAP_DSP_MBCMD_DSPCFG_ABORT:
663 "mbx: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
664 mb->cmd_l, mb->data);
672 volatile unsigned short *buf;
673 void *ipb_sys_da, *ipb_sys_ad;
676 unsigned short dbg_buf_sz, dbg_line_sz;
677 struct mem_sync_struct mem_sync, *mem_syncp;
679 ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
680 if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
683 if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
684 printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n");
688 * read configuration data on system IPBUF
689 * we must read with 16bit-access
691 #ifdef OLD_BINARY_SUPPORT
692 if (mbx_revision == OMAP_DSP_MBPROT_REVISION) {
694 buf = ipbuf_sys_da->d;
698 badr = MKVIRT(buf[3], buf[4]);
699 /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
700 ipb_sys_ad = MKVIRT(buf[7], buf[8]);
701 mbseq = MKVIRT(buf[9], buf[10]);
702 dbg_buf = MKVIRT(buf[11], buf[12]);
703 dbg_buf_sz = buf[13];
704 dbg_line_sz = buf[14];
705 mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
706 mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
707 mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
708 mem_syncp = &mem_sync;
709 #ifdef OLD_BINARY_SUPPORT
710 } else if (mbx_revision == MBREV_3_2) {
711 buf = ipbuf_sys_da->d;
715 badr = MKVIRT(buf[3], buf[4]);
716 /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
717 ipb_sys_ad = MKVIRT(buf[7], buf[8]);
718 mbseq = MKVIRT(buf[9], buf[10]);
723 } else if (mbx_revision == MBREV_3_0) {
724 buf = ipbuf_sys_da->d;
728 badr = MKVIRT(buf[3], buf[4]);
729 /* bkeep = buf[5]; */
730 /* ipb_sys_da = MKVIRT(buf[6], buf[7]); */
731 ipb_sys_ad = MKVIRT(buf[8], buf[9]);
732 mbseq = MKVIRT(buf[10], buf[11]);
737 } else /* should not occur */
739 #endif /* OLD_BINARY_SUPPORT */
741 release_ipbuf_pvt(ipbuf_sys_da);
744 * following configurations need to be done before
745 * waking up the dspcfg initiator process.
747 if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
749 if (ipbuf_config(bln, bsz, badr) < 0)
751 if (dsp_mb_config(mbseq) < 0)
753 if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
755 if (dsp_mem_sync_config(mem_syncp) < 0)
759 wake_up_interruptible(&ioctl_wait_q);
766 wake_up_interruptible(&ioctl_wait_q);
770 void mbx1_poll(struct mbcmd *mb)
772 if (!waitqueue_active(&ioctl_wait_q) ||
773 (ioctl_wait_cmd != MBCMD(POLL))) {
775 "mbx: POLL command received, "
776 "but nobody is waiting for it...\n");
781 wake_up_interruptible(&ioctl_wait_q);
784 void mbx1_regrw(struct mbcmd *mb)
786 if (!waitqueue_active(&ioctl_wait_q) ||
787 (ioctl_wait_cmd != MBCMD(REGRW))) {
789 "mbx: REGRW command received, "
790 "but nobody is waiting for it...\n");
795 case OMAP_DSP_MBCMD_REGRW_DATA:
797 varread_val[0] = mb->data;
798 wake_up_interruptible(&ioctl_wait_q);
803 "mbx: Illegal REGRW command: "
804 "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
809 void mbx1_getvar(struct mbcmd *mb)
811 unsigned char varid = mb->cmd_l;
813 volatile unsigned short *buf;
815 if (!waitqueue_active(&ioctl_wait_q) ||
816 (ioctl_wait_cmd != MBCMD(GETVAR))) {
818 "mbx: GETVAR command received, "
819 "but nobody is waiting for it...\n");
825 case OMAP_DSP_MBCMD_VARID_ICRMASK:
826 varread_val[0] = mb->data;
828 case OMAP_DSP_MBCMD_VARID_LOADINFO:
830 if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
832 "mbx: GETVAR - IPBUF sync failed!\n");
835 /* need word access. do not use memcpy. */
836 buf = ipbuf_sys_da->d;
837 for (i = 0; i < 5; i++) {
838 varread_val[i] = buf[i];
840 release_ipbuf_pvt(ipbuf_sys_da);
844 wake_up_interruptible(&ioctl_wait_q);
852 static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
858 * I/F VERSION descriptions:
860 * 3.2: sysfs / udev support
861 * KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
862 * 3.3: added following ioctls
863 * OMAP_DSP_IOCTL_GBL_IDLE
864 * OMAP_DSP_IOCTL_CPU_IDLE (instead of OMAP_DSP_IOCTL_IDLE)
865 * OMAP_DSP_IOCTL_POLL
869 * print all supporting I/F VERSIONs, like followings.
871 * len += sprintf(buf, "3.2\n");
872 * len += sprintf(buf, "3.3\n");
874 len += sprintf(buf + len, "3.2\n");
875 len += sprintf(buf + len, "3.3\n");
880 static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
882 static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
885 return sprintf(buf, "%s\n", cpustat_name(dsp_cpustat_get_stat()));
888 static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
890 static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
893 return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
896 static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
897 const char *buf, size_t count)
902 if (!capable(CAP_SYS_ADMIN))
905 mask = simple_strtol(buf, NULL, 16);
906 dsp_cpustat_set_icrmask(mask);
908 if (dsp_is_ready()) {
909 ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, mask);
917 static struct device_attribute dev_attr_icrmask =
918 __ATTR(icrmask, S_IWUSR | S_IRUGO, icrmask_show, icrmask_store);
920 static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
925 static unsigned short val[5];
927 if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_LOADINFO, val, 5)) < 0)
930 /* load info value range is 0(free) - 10000(busy) */
933 " 10ms average = %3d.%02d%%\n"
934 " 1sec average = %3d.%02d%% busiest 10ms = %3d.%02d%%\n"
935 " 1min average = %3d.%02d%% busiest 1s = %3d.%02d%%\n",
936 val[0]/100, val[0]%100,
937 val[1]/100, val[1]%100, val[2]/100, val[2]%100,
938 val[3]/100, val[3]%100, val[4]/100, val[4]%100);
943 * This is declared at the top of this file.
945 * static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
948 void mbx1_fbctl_disable(void)
950 if (!waitqueue_active(&ioctl_wait_q) ||
951 (ioctl_wait_cmd != MBCMD(KFUNC))) {
953 "mbx: KFUNC:FBCTL command received, "
954 "but nobody is waiting for it...\n");
958 wake_up_interruptible(&ioctl_wait_q);
961 #ifdef CONFIG_PROC_FS
962 /* for backward compatibility */
963 static int version_read_proc(char *page, char **start, off_t off, int count,
964 int *eof, void *data)
967 * This entry is read by 3.1 tools only, so leave it as is.
968 * 3.2 and later will read from sysfs file.
970 return sprintf(page, "3.1\n");
973 static void __init dsp_ctl_create_proc(void)
975 struct proc_dir_entry *ent;
978 ent = create_proc_read_entry("version", 0, procdir_dsp,
979 version_read_proc, NULL);
982 "omapdsp: failed to register proc device: version\n");
986 static void dsp_ctl_remove_proc(void)
988 remove_proc_entry("version", procdir_dsp);
990 #endif /* CONFIG_PROC_FS */
992 struct file_operations dsp_ctl_fops = {
993 .owner = THIS_MODULE,
994 .ioctl = dsp_ctl_ioctl,
997 void __init dsp_ctl_init(void)
999 device_create_file(&dsp_device.dev, &dev_attr_ifver);
1000 device_create_file(&dsp_device.dev, &dev_attr_cpustat);
1001 device_create_file(&dsp_device.dev, &dev_attr_icrmask);
1002 #ifdef CONFIG_PROC_FS
1003 dsp_ctl_create_proc();
1007 void dsp_ctl_exit(void)
1009 device_remove_file(&dsp_device.dev, &dev_attr_ifver);
1010 device_remove_file(&dsp_device.dev, &dev_attr_cpustat);
1011 device_remove_file(&dsp_device.dev, &dev_attr_icrmask);
1012 #ifdef CONFIG_PROC_FS
1013 dsp_ctl_remove_proc();