The Touch Screen driver is not implemented using the input subsystem. In fact, it is not much different from the driver of a common character device. You only need to follow the touch screen steps.
① S3c2410_ts_init function, which is the entrance of the entire program. Implements various initialization functions.
/* Device initialization function */static int _ init s3c2410_ts_init (void) {int ret; tsevent = tsevent_dummy; /* If the first parameter of the character registration device is 0, it indicates automatic allocation */ret = register_chrdev (0, device_name, & s3c2410_fops); // normal registration failure judgment. If (Ret <0) {printk (device_name "can't get major number \ n"); return ret ;}// tsmajor is a global variable, here, the returned value tsmajor = ret;/* Set gpio to XP, ym, YP and ym * // operation corresponding gpio registers is assigned to the device, these functions are the interfaces left behind by the kernel. Set_gpio_ctrl (gpio_ypon); set_gpio_ctrl (gpio_ymon); set_gpio_ctrl (gpio_xpon); set_gpio_ctrl (gpio_xmon);/* Registration interrupt: register the ADC and TC interrupt respectively. Device_name has a macro definition at the beginning. */Ret = request_irq (response, s3c2410_isr_adc, response, device_name, s3c2410_isr_adc); If (RET) goto adc_failed; ret = request_irq (irq_tc, response, response, device_name, response ); if (RET) goto tc_failed;/* the function is implemented by Macro when the touch screen is interrupted. This is a waiting function that reminds me of Xiang ge. */Wait_down_int (); // create a device file. # Ifdef outputs = outputs (null, "touchscreen", null); devfs_tsraw = devfs_register (outputs, "0raw", outputs, tsmajor, outputs, s_ifchr | s_irusr | s_iwusr, & s3c2410_fops, null); # endifadcdly = 0 xFFFF; printk (device_name "initialized \ n"); Return 0; // two jump points that fail to interrupt registration. Tc_failed: free_irq (irq_adc_done, s3c2410_isr_adc); adc_failed: return ret ;}
In this function, Conditional compilation is unavailable before, so pay attention to it. However, the main function of Conditional compilation is to create a device file. At the same time, there are two Goto that fail to interrupt registration. To keep your programs confused, write down this sentence: // tsmajor is a global variable. The returned value tsmajor = RET is assigned to the device;
② S3c2410_ts_exit: this function is the exit function of the entire program. It mainly realizes device logout and disconnection release.
static void __exit s3c2410_ts_exit(void){#ifdef CONFIG_DEVFS_FSdevfs_unregister(devfs_tsraw);devfs_unregister(devfs_ts_dir);#endifunregister_chrdev(tsMajor, DEVICE_NAME);free_irq(IRQ_ADC_DONE, s3c2410_isr_adc);free_irq(IRQ_TC, s3c2410_isr_tc);}
③ When analyzing the driver of the character device, you should first look at the init function and then look for file_operation. However, the implementation of the touch screen driver must be interrupted, so let's take a look at the interrupt function first.
First look at the first interrupt function (registered in the init function)
/* The first interrupt generated when the key is pressed */static void s3c2410_isr_tc (int irq, void * dev_id, struct pt_regs * REG) {// use the spin lock to lock the interrupt. Spin_lock_irq (& (tsdev. Lock); // here pen_up is defined as 0 by macro, and penstatus is a struct member. If (tsdev. penstatus = pen_up)/* if it is interrupted by pressing */{start_ts_adc ();/* Start AD conversion */} else {tsdev. penstatus = pen_up;/* if it is a pop-up interrupt */dprintk ("pen up: X: % 08d, Y: % 08d \ n", x, y); wait_down_int (); /* Wait for the press to interrupt */tsevent ();/* call the subsequent processing function */} spin_unlock_irq (& (tsdev. lock ));}
Before talking about this interrupt function, let's talk about the main workflow of touch products:
Touch screen Workflow
① Select the acquisition mode of x/y.
② Set the status of the touch screen waiting for interruption.
③ If the interruption occurs, start the corresponding digital-analog conversion.
④ After the digital-analog conversion, you can obtain the x/y coordinate value and return it to the State awaiting interruption (before ② ).
At the same time, let's talk about two interruptions to the touch screen:
TC interruption: when the hand is pressed and picked up
ADC interruption: occurs in step 4.
The above interrupt processing function is actually the TC interrupt, which can be seen from the name, that is, the first interrupt of the touch screen.
When an interruption occurs, the spin lock is first used. Then, two cases are provided for Determination and allocation. If the conversion is indeed down, the adconversion starts. The adconversion function is implemented in another function, which is only called here. If an interrupt occurs, wait and call the subsequent functions (the subsequent functions must be carefully checked here ).
The above Tc interrupt function calls two functions: start_ts_adc and tsevent. The two functions are described below.
Start_ts_adc function:
// Enable the ad ing by setting the Response Register. // Mode_x_axis and start_adc_x are macro-defined functions. Static inline void start_ts_adc (void) {adc_state = 0; mode_x_axis (); start_adc_x ();}
This function is mainly implemented through the operation register. The specific definition is manifested in the macro definition at the beginning of the entire program.
Tsevent function:
Static void tsevent_raw (void) {If (tsdev. penstatus = pen_down) {/* Save the coordinates when you press */buf_head.x = x; buf_head.y = y; buf_head.pressure = pen_down; # ifdef hook_for_drag/* When the pen slides on the touch screen for a long time, it will not generate a point track if no special processing is performed. */Ts_timer.expires = jiffies + ts_timer_delay; add_timer (& ts_timer);/* specific implementation of processing this function by pressing the key for a long time is implemented in this function. */# Endif} else {# ifdef hook_for_drag del_timer (& ts_timer); # endifbuf_head.x = 0; buf_head.y = 0; buf_head.pressure = pen_up; /* Save the coordinates when the pop-up occurs */} tsdev. head = incbuf (tsdev. head, max_ts_buf); // The wake-up process corresponds to sleep on in the READ function. Wake_up_interruptible (& (tsdev. WQ);/* wake up the process */}
Wait until you press the interrupt function and then call the subsequent processing function. Here is a loop call. Note the following when processing functions:
# Ifdef hook_for_drag
/* When the pen slides on the touch screen for a long time, no point tracking will be generated if no special processing is performed. */
Ts_timer.expires = jiffies + ts_timer_delay;
Add_timer (& ts_timer );
/*
Handling of long-time key presses
The specific implementation of this function is implemented in this function.
*/
# Endif
This function is intended for long-time buttons. Here, ts_timer realizes the detection frequency. At the same time, ts_timer implements the following functions:
Static void ts_timer_handler (unsigned long data) {spin_lock_irq (& (tsdev. lock); If (tsdev. penstatus = pen_down) {start_ts_adc () ;}// unlock the program. Spin_unlock_irq (& (tsdev. Lock ));}
In this case, if you press the button for a long time, the detection is not interrupted, and the detection frequency can be set by yourself.
④ After the TC interrupt function is executed, it is necessary to execute another interrupt ADC interrupt according to the IRQ interrupt number.
static void s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg){spin_lock_irq(&(tsdev.lock));if (tsdev.penStatus == PEN_UP) s3c2410_get_XY();#ifdef HOOK_FOR_DRAGelse s3c2410_get_XY();#endifspin_unlock_irq(&(tsdev.lock));}
This part is the Code implemented by the ADC. This function mainly calls the s3c2410_get_xy function, including the execution after judgment, which is also performed after the s3c2410_get_xy function is further determined.
The following code lists the function s3c2410_get_xy:
Static inline void s3c2410_get_xy (void) {// The variable adc_state is used to identify which coordinates are being obtained. If (adc_state = 0) {/* convert x */adc_state = 1; disable_ts_adc (); y = (adcdat0 & 0x3ff ); /* obtain X coordinates */mode_y_axis (); start_adc_y ();/* Start y coordinate conversion */} else if (adc_state = 1) {/* convert y */adc_state = 0; disable_ts_adc (); X = (adcdat1 & 0x3ff);/* obtain Y coordinates */tsdev. penstatus = pen_down;/* change screen status */dprintk ("pen down: X: % 08d, Y: % 08d \ n", x, y); wait_up_int (); /* Wait for the disconnection */tsevent ();}}
Some of the above interrupt programs involve loop calls of process control, so you must read them carefully.
⑤ Start to talk about file_operations after the interruption is explained.
How kind you are!
Static struct file_operations s3c2410_fops = {
Owner: this_module,
Open: s3c2410_ts_open,
Read: s3c2410_ts_read,
Release: s3c2410_ts_release,
Poll: s3c2410_ts_poll,
};
When file_operations is mentioned, the code will be pasted out separately ~
S3c2410_ts_open:
static int s3c2410_ts_open(struct inode *inode, struct file *filp){tsdev.head = tsdev.tail = 0;tsdev.penStatus = PEN_UP;#ifdef HOOK_FOR_DRAG init_timer(&ts_timer);ts_timer.function = ts_timer_handler;#endiftsEvent = tsEvent_raw;init_waitqueue_head(&(tsdev.wq));MOD_INC_USE_COUNT;return 0;}
There is another problem I have not understood, that is, tsdev. Head = tsdev. Tail = 0; I don't know why the header and tail should be set to zero. The rest will not be explained too much.
S3c2410_ts_read function:
Static ssize_t s3c2410_ts_read (struct file * filp, char * buffer, size_t count, loff_t * PPOs) {ts_ret; retry: If (tsdev. Head! = Tsdev. tail) {int count; Count = tsread (& ts_ret); If (count) copy_to_user (buffer, (char *) & ts_ret, count); Return count ;} else {If (filp-> f_flags & o_nonblock) Return-eagain; interruptible_sleep_on (& (tsdev. WQ); // the function of this judgment is to determine whether it is a signal to wake it up if (signal_pending (current) Return-erestartsys; goto retry ;} return sizeof (ts_ret );}
Note: // the function of this judgment is to determine whether it is a signal to wake it up if (signal_pending (current )).
Release function:
static int s3c2410_ts_release(struct inode *inode, struct file *filp){#ifdef HOOK_FOR_DRAGdel_timer(&ts_timer);#endifMOD_DEC_USE_COUNT;return 0;}
In general, this is what I wrote after I saw the input subsystem implement the touch screen drive. It suddenly seems that the implementation of the input subsystem is much easier than this.