📄 device.c
字号:
#include <linux/types.h>#include <linux/module.h>#include <linux/init.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/vmalloc.h>#include <asm/errno.h>#include <asm/signal.h>#ifdef ARM2410#include <asm/irq.h>#else#include <linux/irq.h>#include <linux/tqueue.h>#include <linux/wrapper.h>#endif#include <linux/interrupt.h>//#include <linux/kallsyms.h>#include <linux/keyboard.h>#include <asm/bitops.h>#include <asm/io.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/version.h>#include <asm/uaccess.h>#include <asm/delay.h>#include "sh_global.h"#include "sh_tools.h"#include "sh_device.h"MODULE_AUTHOR ("");MODULE_DESCRIPTION ("");MODULE_LICENSE("GPL");static int device_open(struct inode *inode,struct file *file){ printk("device %d.%d open\n", inode->i_rdev >> 8, inode->i_rdev & 0xff); if(0 != device_busy) { return -EBUSY; } device_busy ++;// MOD_INC_USE_COUNT; return SUCCESS;}static int device_release(struct inode *inode,struct file *file){ clientdestroy(); device_busy --;// MOD_DEC_USE_COUNT; printk("device %d.%d close\n", inode->i_rdev >> 8, inode->i_rdev & 0xff); return SUCCESS;}static ssize_t device_read(struct file *file,char *buff,size_t length,loff_t *offset){ int bytes_read = 0;#ifdef _DEBUG struct timeval tv1; struct timeval tv2; int sec; int usec; do_gettimeofday(&tv1);#endif if(length%2 == 0) { bytes_read = RW_TOUSER(*offset,buff,length); } else { bytes_read = RB_TOUSER(*offset,buff,length); }#ifdef _DEBUG do_gettimeofday(&tv2); sec=tv2.tv_sec - tv1.tv_sec; usec=tv2.tv_usec - tv1.tv_usec; if(usec < 0) { usec += 1000000; sec --; } rwtimes=sec * 1000 + usec/1000;// printk("device_read length=%d,offset=0x%x,ret=%d\n",// length,*((unsigned int *)offset),bytes_read);#endif if(bytes_read >=0) { *offset = *offset + bytes_read; return bytes_read; } return bytes_read;}static ssize_t device_write(struct file *file,const char *buff,size_t length,loff_t *offset){ int bytes_write = 0; if(length%2 == 0) { bytes_write = WW_FROMUSER(*offset,(char *)buff,length); } else { bytes_write = WB_FROMUSER(*offset,(char *)buff,length); }// printk("device_write length=%d,offset=0x%x:%u,ret=%d\n",// length,*((unsigned int *)offset),*((unsigned int *)offset),bytes_write); if(bytes_write >=0) { *offset = *offset + bytes_write; return bytes_write; } else { return -EPERM; }}static int device_mmap(struct file * file, struct vm_area_struct * vma){ int ret; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;// printk("start %x,end %x,pgoff %x,offset %x\n",vma->vm_start,vma->vm_end,// vma->vm_pgoff,offset); /* * Accessing memory above the top the kernel knows about or * through a file pointer that was marked O_SYNC will be * done non-cached. */// if (noncached_address(offset) || (file->f_flags & O_SYNC))// vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Don't try to swap out physical pages.. */ vma->vm_flags |= VM_RESERVED; /* * Don't dump addresses that are not real memory to a core file. */ if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) vma->vm_flags |= VM_IO;#ifdef VER2_6 ret=remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end-vma->vm_start, vma->vm_page_prot);#else ret=remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot);#endif if(ret) return -EAGAIN; return 0;}static int device_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg){ switch(cmd) { case ICW_INIT: return clientinit(arg); case ICW_REIRQENABLE: enableirq(DISABLE_IRQ); enableirq(devpriv.curirqenable); return 0; case ICW_RESETBOARD: return resetboard(arg); case ICW_SETINT_COMMAND_DOWN: return (arg,DNINT_COMMAND_DOWN); case ICW_SETINT_DATA_OK: return setdspdownint(arg,DNINT_DATA_OK); case ICW_SETINT_DOWN_RES1: return setdspdownint(arg,DNINT_RES1); case ICW_SETINT_DOWN_RES2: return setdspdownint(arg,DNINT_RES2); case ICW_CLEARINT_DATA_READ: return cleardspupint(arg,UPINT_DATA_READ); case ICW_APPREADFAULTEND: cleardspupint(arg,UPINT_DATA_READ); //下发中断 setdspdownint(arg,DNINT_DATA_OK); return 0;//清除山川中断 //DSP板回复通知MONITOR命令返回中断位 case ICW_CLEARINT_COMMAND_RETURN: return cleardspupint(arg,UPINT_COMMAND_RETURN); //DSP板通知MONITOR复位结束中断位 case ICW_CLEARINT_RESET: return cleardspupint(arg,UPINT_RESET); //DSP板告警中断位 case ICW_CLEARINT_ERROR: return cleardspupint(arg,UPINT_ERROR);//设置旗语 case ICW_SETDSPFLAG0: return setdspflag(arg,DSPFLAG_0); case ICW_SETDSPFLAG1: return setdspflag(arg,DSPFLAG_1); case ICW_SETDSPFLAG2: return setdspflag(arg,DSPFLAG_2); case ICW_SETDSPFLAG3: return setdspflag(arg,DSPFLAG_3); case ICW_SETDSPFLAG4: return setdspflag(arg,DSPFLAG_4); case ICW_SETDSPFLAG5: return setdspflag(arg,DSPFLAG_5); case ICW_SETDSPFLAG6: return setdspflag(arg,DSPFLAG_6); case ICW_SETDSPFLAG7: return setdspflag(arg,DSPFLAG_7);//放弃旗语 case ICW_CLEARDSPFLAG0: return cleardspflag(arg,DSPFLAG_0); case ICW_CLEARDSPFLAG1: return cleardspflag(arg,DSPFLAG_1); case ICW_CLEARDSPFLAG2: return cleardspflag(arg,DSPFLAG_2); case ICW_CLEARDSPFLAG3: return cleardspflag(arg,DSPFLAG_3); case ICW_CLEARDSPFLAG4: return cleardspflag(arg,DSPFLAG_4); case ICW_CLEARDSPFLAG5: return cleardspflag(arg,DSPFLAG_5); case ICW_CLEARDSPFLAG6: return cleardspflag(arg,DSPFLAG_6); case ICW_CLEARDSPFLAG7: return cleardspflag(arg,DSPFLAG_7); //设置输出量 case ICW_SETOUT: return setout(arg); //清除输出量 case ICW_CLEAROUT: return clearout(arg); //开灯 case ICW_SETLED: return setled(arg); //关灯 case ICW_CLEARLED: return clearled(arg); //允许中断 case ICW_SETENABLEIRQ: return setenableirq(arg); //禁止中断 case ICW_CLEARENABLEIRQ: return clearenableirq(arg);//设置同步信号 case ICW_SETSYN_AB_INT: return setsyn_ab_int(); case ICW_SETSYN_QD_INT: return setsyn_qd_int(); case ICW_SETSYN_SYN_WK1: return setsyn_syn_wk1(); case ICW_SETSYN_SYN_WK2: return setsyn_syn_wk2();//清除同步信号 case ICW_CLEARSYN_QD_INT: return clearsyn_qd_int(); case ICW_CLEARSYN_AB_INT: return clearsyn_ab_int(); case ICW_CLEARSYN_SYN_WK1: return clearsyn_syn_wk1(); case ICW_CLEARSYN_SYN_WK2: return clearsyn_syn_wk2(); //设定定时时间 case ICW_ADDTIMEEVENT: { stimeevent timeevent; if( 0 != copy_from_user(&timeevent,(char *)arg,sizeof(stimeevent))) { printk("copy stimeevent struct error\n"); return -1; } return addtimeevent(&timeevent); } //清除定时时间 case ICW_DELTIMEEVENT: return deltimeevent(arg); //清除中断信号源 case ICW_CLEARIRQFLAG: return clearirqflag(arg); //给DSP板发送命令 case ICW_SENDCMD: { sdspcmd dspcmd; if( 0 != copy_from_user(&dspcmd,(char *)arg,sizeof(sdspcmd))) { printk("copy sdspcmd struct error\n"); return -1; } return senddspcmdfromuser(dspcmd.boardno,dspcmd.cmd,dspcmd.cmdlen); } //允许硬件中断 case ICW_HWIRQENALBE: return hwirqenable(); //禁止硬件中断 case ICW_HWIRQDISABLE: return hwirqdisable(); case ICW_KERTIMER: return kertimer(); //清除下发中断 case ICW_CLEARINT_DATA_OK: return cleardspdownint(arg,DNINT_DATA_OK); case ICW_CLEARINT_COMMAND_DOWN: return cleardspdownint(arg,DNINT_COMMAND_DOWN); case ICW_CLEARINT_RES1: return cleardspdownint(arg,DNINT_RES1); case ICW_CLEARINT_RES2: return cleardspdownint(arg,DNINT_RES2); //设置gps下传中断 case ICW_SETGPS_DOWN_INT: return setgpsdownint(); //清除gps下传中断 case ICW_CLEARGPS_DOWN_INT: return cleargpsdownint(); //清除gps上传中断 case ICW_CLEARGPS_UP_INT: return cleargpsupint(); case ICW_CLEARREADANDSETOK: return clearreadandsetok(arg); //给gps发送命令 case ICW_GPS_SENDCMD: { sdatastr *pdatastr;// cleargpsdownint(); if(TRUE == getgpsdownint()) { return -1; } pdatastr=(sdatastr *)arg; if(NULL == pdatastr) { return -EINVAL; } if(pdatastr->datalen != setgpsdowndata_fromuser(pdatastr->data,pdatastr->datalen)) { return -EINVAL; } return setgpsdownint(); } //读取gps命令响应 case ICW_GPS_GETDNDATA: { sdatastr *pdatastr; if(TRUE == getgpsdownint()) { return -1; } pdatastr=(sdatastr *)arg; if(NULL == pdatastr) { return -2; } if(pdatastr->datalen != getgpsdowndata_fromuser(pdatastr->data,pdatastr->datalen)) { return -3; } return 0; } //读取gps上传区内容 case ICW_GPS_GETUPDATA: { sdatastr *pdatastr; pdatastr=(sdatastr *)arg; if(NULL == pdatastr) { return -EINVAL; } if(pdatastr->datalen != getgpsupdata_fromuser(pdatastr->data,pdatastr->datalen)) { return -EINVAL; } return 0; }//gps上传命令响应 case ICW_GPS_RESPUPDATA: { sdatastr *pdatastr;// cleargpsdownint(); pdatastr=(sdatastr *)arg; if(NULL == pdatastr) { return -EINVAL; } if(pdatastr->datalen != setgpsupdata_fromuser(pdatastr->data,pdatastr->datalen)) { return -EINVAL; } return cleargpsupint(); } //写看门狗告警单元 case ICW_DOG_WARNING: { unsigned char flag=arg; if(sizeof(flag) != WB(DEVADDR_DOG_WARNING,&flag,sizeof(flag))) { printk("write DOG WARNING fail \n"); return -1; } else { return 0; } } case ICR_MONIRQSTATE: { int state; //读中断状态 state=getmonirqstate(); if(state <0 ) { //读错误 return -1; } if( 0 != copy_to_user((char *)arg,&state,sizeof(state))) { printk("copy monirqstate error\n"); return -EINVAL; } return 0; } case ICR_GETIN: { unsigned char instate; int ret; ret=getin(); if(ret < 0) { return -EINVAL; } instate=(unsigned char)ret; if( 0 != copy_to_user((char *)arg,&instate,sizeof(instate))) { printk("copy in state error\n"); return -EINVAL; } } return 0; case ICR_DEVIRQSTATE: if( 0 == arg) { return -EINVAL; } if( 0 == getdevirqstate(&(devpriv.devirqstate))) { if( 0 != copy_to_user((char *)arg,&(devpriv.devirqstate),sizeof(sdevirqstate))) { printk("copy devirqstate error\n"); return -EINVAL; } return 0; } return -EINVAL; case ICR_GETFAULTDATA: { unsigned char boardno;#ifdef _DEBUG struct timeval tv1; struct timeval tv2; int sec; int usec; int ret;#endif if( 0 != copy_from_user(&boardno,(char *)arg,sizeof(boardno))) { printk("copy from user boardno error\n"); return -1; }#ifdef _DEBUG do_gettimeofday(&tv1); ret=getfaultdata(boardno,(unsigned char *)arg); do_gettimeofday(&tv2); sec=tv2.tv_sec - tv1.tv_sec; usec=tv2.tv_usec - tv1.tv_usec; if(usec < 0) { usec += 1000000; sec --; } rwtimes=sec * 1000 + usec/1000; return ret;#else return getfaultdata(boardno,(unsigned char *)arg);#endif } case ICR_GETDNINT_DATA_OK: return getdspdownint(arg,DNINT_DATA_OK); //读取gps下传中断 case ICR_GETGPS_DOWN_INT: { unsigned char flag; flag=(unsigned char)getgpsdownint(); if( 0 != copy_to_user((char *)arg,&flag,sizeof(flag))) { printk("copy gps down int flag error\n"); return -EINVAL; } } return 0; //读取gps上传中断 case ICR_GETGPS_UP_INT: { unsigned char flag; flag=(unsigned char)getgpsupint(); if( 0 != copy_to_user((char *)arg,&flag,sizeof(flag))) { printk("copy gps up int flag error\n"); return -EINVAL; } } return 0; case ICR_RWTIMES: if(0 == arg) { return -EINVAL; } if(0 != put_user(rwtimes,(int *)arg)) { return -EINVAL; } return 0; case ICR_TEST: test_setdspdataok(arg); return 0; default: return -EINVAL; }}#ifdef VER2_6irqreturn_t myirq_handle(int irq,void *dev_id,struct pt_regs *regs)#elsevoid myirq_handle(int irq,void *dev_id,struct pt_regs *regs)#endif{ static stv_and_devirqstate tvdev; static unsigned int count; tvdev.irqtimes = ++count; hwirqdisable();// if(TRUE == clientisvalid()) { do_gettimeofday(&(tvdev.tv));// getdevirqstate(&(tvdev.devirqstate));// printk("kern catch sig times %d\n",count); //设备是独占中断,所以不判断 //直接发送信号到应用程序 sendsig(SIGRTMIN,&(tvdev),sizeof(stv_and_devirqstate),devpriv.pid); }#ifdef VER2_6 return 0;#endif}static struct file_operations fops= { .read =device_read, .write =device_write, .ioctl =device_ioctl, .open =device_open, .release =device_release, .mmap =device_mmap,};#ifdef VER2_6#define check_region check_mem_region#define request_region request_mem_region#define release_region release_mem_region#endifstatic int __init shdev_init_module(void){ int ret; printk("init\n"); if(0 == check_region(IOPORT_START,IOPORT_NUM)) { request_region(IOPORT_START,IOPORT_NUM,DEVICE_NAME); printk("request ipport from 0x%x num %d good\n",IOPORT_START,IOPORT_NUM); } else { printk("ipport from 0x%x num %d busy\n",IOPORT_START,IOPORT_NUM); return -1; } ret = register_chrdev(DEVICE_MARJOR,DEVICE_NAME,&fops); if(ret == 0) { } else { release_region(IOPORT_START,IOPORT_NUM); printk("register chr dev fail %d\n",ret); return -1; } return 0;}static void __exit shdev_cleanup_module(void){ int ret; printk("clearup\n"); //防止客户应用死机 clientdestroy(); release_region(IOPORT_START,IOPORT_NUM); ret=unregister_chrdev(DEVICE_MARJOR,DEVICE_NAME); if(ret<0) { printk("unregister char dev error %d\n",ret); }}module_init(shdev_init_module);module_exit(shdev_cleanup_module);/*//中断下半部处理程序void myirq_bhhandle(void){ static int count=0; printk("bh count %d\n",++count);// sendsig(SIGRTMIN);int ret; struct timespec t; unsigned long expire; t.tv_nsec=0; t.tv_sec = 5; expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); ret=interruptible_sleep_on_timeout(&sh_wait, expire); if(ret == 0) { //timeout printk("irq bh timeout \n"); } else { printk("irq bh wait end \n"); }}*/ /*读端口*//* sig=testirq(); if(sig > 0) { //关中段 enableirq(DISABLE_IRQ); printk("irq %d catach times %d sendsig %d\n",irq,++count,sig); sendsig(sig); }*/ /*给应用程序发送信号usr1*/// if(pid>0 && sendsig==1)/* if(1 == clientisvalid()) { queue_task(&task, &tq_immediate); mark_bh(IMMEDIATE_BH); }*//* //读中断状态 state=getmonirqstate(); if(state <0 ) { //读错误 return; } //有中断 if(TRUE == havmonirqstate(IRQSTATE_ALL,state)) { //处理中断 //irqevent(); if( 0 == getdevirqstate(&(devpriv.devirqstate))) { sendsig(SIGRTMIN,&(devpriv.devirqstate),sizeof(sdevirqstate)); } }*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -