📄 mc68328digi.c
字号:
#endif if(IS_BUSY_ENDED) { /* If first BUSY down, then */ ask_x_conv(); /* go on with conversion */ ts_drv_state++; } else fall_BUSY_enable_PENIRQ(); /* else, re-loop */ break; case TS_DRV_ASKY: ask_y_conv(); ts_drv_state++; break; case TS_DRV_READX: read_x_conv(); ts_drv_state++; break; case TS_DRV_READY: read_y_conv(); swap_xy(¤t_pos.x, ¤t_pos.y); ts_drv_state = TS_DRV_WAIT; break; case TS_DRV_WAIT: DISABLE_SPIM_IRQ; release_SPIM_transfert(); set_timer_irq(&ts_wake_time,sample_ticks); break; case TS_DRV_ERROR: if(IS_BUSY_ENDED) { /* If BUSY down... */ release_SPIM_transfert(); cause_event(CONV_ERROR); init_ts_state(); } else fall_BUSY_enable_PENIRQ(); /* else, re-loop */ break; default: init_ts_state(); } restore_flags(flags); /* Enable interrupts */#ifdef CONFIG_XCOPILOT_BUGS PENIRQ_DATA |= PEN_MASK;#endif}/*----------------------------------------------------------------------------*//* file_operations functions -------------------------------------------------*//* * Called whenever a process attempts to read the device it has already open. */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))static ssize_t ts_read (struct file *file, char *buff, /* the buffer to fill with data */ size_t len, /* the length of the buffer. */ loff_t *offset) { /* Our offset in the file */#elsestatic int ts_read(struct inode *inode, struct file *file, char *buff, /* the buffer to fill with data */ int len) { /* the length of the buffer. */ /* NO WRITE beyond that !!! */#endif char *p_buffer; char c; int i; int err; while(!new_pen_state) { /* noting to read */ if(file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on(&queue->proc_list);#if (LINUX_VERSION_CODE >= 0x020100) if(signal_pending(current))#else if(current->signal & ~current->blocked) /* a signal arrived */#endif return -ERESTARTSYS; /* tell the fs layer to handle it */ /* otherwise loop */ } /* Force length to the one available */ len = DATA_LENGTH; /* verify that the user space address to write is valid */ err = verify_area(VERIFY_WRITE,buff,len); if(err) return err; /* * The events are anyway put in the queue. * But the read could choose to get the last event or the next in queue. * This decision is controlled through the ioctl function. * When the read doesn't flush the queue, this last is always full. */ if(current_params.event_queue_on) { i = len; while((i>0) && !queue_empty()) { c = get_char_from_queue(); put_user(c,buff++); i--; } } else { p_buffer = (char *)&ts_pen; for(i=len-1;i>=0;i--) put_user(p_buffer[i],buff+i);/* for(i=0;i<len;i++) put_user(p_buffer[i],buff+i);*/ } if(queue_empty() || !current_params.event_queue_on) new_pen_state = 0; /* queue events fully consumned */ else new_pen_state = 1; /* queue not empty */ if(len-i) { file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* nfi */ return len-i; } return 0;}/* * select file operation seems to become poll since version 2.2 of the kernel */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))static unsigned int ts_poll(struct file *file, poll_table *table) { poll_wait(file,&queue->proc_list,table); if (new_pen_state) return POLLIN | POLLRDNORM; return 0;}#elsestatic int ts_select(struct inode *inode, struct file *file, int mode, select_table *table) { if(mode != SEL_IN) return 0; /* the device is readable only */ if(new_pen_state) return 1; /* there is some new stuff to read */ select_wait(&queue->proc_list,table); /* wait for data */ return 0;}#endif/* * Called whenever a process attempts to do an ioctl to the device it has * already open. */static int ts_ioctl(struct inode *inode, struct file *file, unsigned int cmd, /* the command to the ioctl */ unsigned long arg) { /* the parameter to it */ struct ts_drv_params new_params; int err; int i; char *p_in; char *p_out; switch(cmd) { case TS_PARAMS_GET: /* Get internal params. First check if user space area * to write is valid. */ err = verify_area(VERIFY_WRITE,(char *)arg,sizeof(current_params)); if(err) return err; p_in = (char *)¤t_params; p_out = (char *)arg; for(i=0;i<sizeof(current_params);i++) put_user(p_in[i],p_out+i); return 0; case TS_PARAMS_SET: /* Set internal params. First check if user space area * to read is valid. */ err = verify_area(VERIFY_READ,(char *)arg,sizeof(new_params)); if(err) { return err; } /* ok */ p_in = (char *)&new_params; p_out = (char *)arg; for(i=0;i<sizeof(new_params);i++) {#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) get_user(p_in[i],p_out+i);#else p_in[i] = get_user(p_out+i);#endif } /* All the params are set with minimal test. */ memcpy((void*)¤t_params, (void*)&new_params, sizeof(current_params)); sample_ticks = TICKS(current_params.sample_ms); /* check version */ if(new_params.version_req!=-1) { if(new_params.version_req!=MC68328DIGI_VERSION) { printk("%s: error: driver version is %d, requested version is %d\n", __file__, MC68328DIGI_VERSION, new_params.version_req); return -EBADRQC; } } return 0; default: /* cmd is not an ioctl command */ return -ENOIOCTLCMD; }} /* * Called whenever a process attempts to open the device file. */static int ts_open(struct inode *inode, struct file *file) { int err; /* To talk to only one device at a time */ if(device_open) return -EBUSY; /* IRQ registration have to be done before the hardware is instructed to * generate interruptions. */ /* IRQ for pen */ err = request_irq(PEN_IRQ_NUM, handle_pen_irq, IRQ_FLG_STD,"touch_screen",NULL); if(err) { printk("%s: Error. Cannot attach IRQ %d to touch screen device\n", __file__, PEN_IRQ_NUM); return err; } printk("%s: IRQ %d attached to touch screen\n", __file__, PEN_IRQ_NUM); /* IRQ for SPIM */ err = request_irq(SPI_IRQ_NUM, handle_spi_irq, IRQ_FLG_STD,"spi_irq",NULL); if(err) { printk("%s: Error. Cannot attach IRQ %d to SPIM device\n", __file__, SPI_IRQ_NUM); return err; } printk("%s: IRQ %d attached to SPIM\n", __file__, SPI_IRQ_NUM); /* Init hardware */ init_ts_drv(); printk("digi: init hardware done..\n"); /* Init the queue */ queue = (struct ts_queue *) kmalloc(sizeof(*queue),GFP_KERNEL); memset(queue,0,sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); /* Increment the usage count (number of opened references to the module) * to be sure the module couldn't be removed while the file is open. */ MOD_INC_USE_COUNT; /* And my own counter too */ device_open++; return 0; /* open succeed */}#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))static int ts_fasync(int inode, struct file *file, int mode) {#elsestatic int ts_fasync(struct inode *inode, struct file *file, int mode) {#endif int retval; retval = fasync_helper(inode,file,mode,&queue->fasync); if(retval < 0) return retval; return 0;}/* * Called whenever a process attempts to close the device file. */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))static int ts_release(struct inode *inode, struct file *file) {#elsestatic void ts_release(struct inode *inode, struct file *file) {#endif /* Remove this file from the asynchronously notified file's */ ts_fasync(inode,file,0); /* Release hardware */ release_ts_drv(); /* Free the allocated memory for the queue */ kfree(queue); /* IRQ have to be freed after the hardware is instructed not to interrupt * the processor any more. */ free_irq(SPI_IRQ_NUM,NULL); free_irq(PEN_IRQ_NUM,NULL); /* Decrement the usage count, otherwise once the file is open we'll never * get rid of the module. */ MOD_DEC_USE_COUNT; /* And my own counter too */ device_open--;#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) return 0;#endif}static struct file_operations ts_fops = {#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) owner: THIS_MODULE, read: ts_read, poll: ts_poll, ioctl: ts_ioctl, open: ts_open, release: ts_release, fasync: ts_fasync,#else NULL, /* lseek */ ts_read, /* read */ NULL, /* write */ NULL, /* readdir */# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) ts_poll, /* poll */# else ts_select, /* select */# endif ts_ioctl, /* ioctl */ NULL, /* mmap */ ts_open, /* open */# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) NULL, /* flush */# endif ts_release, /* release (close) */ NULL, /* fsync */ ts_fasync /* async notification */#endif};/* * miscdevice structure for misc driver registration. */static struct miscdevice mc68328_digi = { MC68328DIGI_MINOR,"mc68328 digitizer",&ts_fops};/* * Initialize the driver. */int __init mc68328digi_init(void) { int err; printk("%s: MC68328DIGI touch screen driver\n", __file__); /* Register the misc device driver */ err = misc_register(&mc68328_digi); if(err<0) printk("%s: Error registering the device\n", __file__); else printk("%s: Device register with name: %s and number: %d %d\n", __file__, mc68328_digi.name, MC68328DIGI_MAJOR, mc68328_digi.minor); /* Init prameters settings at boot time */ init_ts_settings(); return err; /* A non zero value means that init_module failed */}/* * Cleanup - undid whatever mc68328digi_init did. */void mc68328digi_cleanup(void) { /* Unregister device driver */ misc_deregister(&mc68328_digi);} module_init(mc68328digi_init);module_exit(mc68328digi_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -