📄 kdriver.c
字号:
at91_set_gpio_value(AT91_PIN_PB15,0); break; case 3: at91_set_gpio_value(AT91_PIN_PB16,0); break; case 4: at91_set_gpio_value(AT91_PIN_PB17,0); break; } }//#define GET_ROWS_STATUS(c) (((GPLR1 & CORGI_GPIO_HIGH_SENSE_BIT) >> CORGI_GPIO_HIGH_SENSE_RSHIFT) | ((GPLR2 & CORGI_GPIO_LOW_SENSE_BIT) << CORGI_GPIO_LOW_SENSE_LSHIFT))/* * The scan keyboard only generates interrupts when a key is pressed. * When a key is pressed, we enable a timer which then scans the * keyboard to detect when the key is released. *///scan/* Scan the hardware keyboard and push any changes up through the input layer */static void scankbd_scankeyboard(struct scankbd *scankbd_data, struct pt_regs *regs){ unsigned int row, col, rowd, scancode; unsigned long flags; unsigned int num_pressed; spin_lock_irqsave(&scankbd_data->lock, flags); if (regs) input_regs(&scankbd_data->scan_kbd_dev, regs); scan_kbd_discharge_all(); udelay(10); num_pressed = 0; udelay(10); readr = GET_ROWS_STATUS(col);//获取键盘按下瞬间的行状态 for (col = 0; col < KB_COLS; col++) { // udelay(10); //scan_kbd_activate_all(); scan_kbd_activate_col(col);//设置一列为1 udelay(10); rowd = GET_ROWS_STATUS(col);//行端口状态 if(rowd!=readr) {//与键按下时的行状态比较 for (row = 0; row < KB_ROWS; row++) { scancode = SCANCODE(row, col);// //handle_scancode((readr & KB_ROWMASK(row)), scancode, scankbd_data);//get the key status if ( readr & KB_ROWMASK(row)) { num_pressed++; //printk(KERN_ALERT "col %i\n", col); //printk(KERN_ALERT "readr %i\n", readr); //printk(KERN_ALERT "KB_ROWMASK %i\n", KB_ROWMASK(row)); //printk(KERN_ALERT "row %i\n", row); //printk(KERN_ALERT "rowd %i\n", rowd); input_report_key(&(scankbd_data->scan_kbd_dev), scankbd_data->keycode[scancode], 1); //input_sync(&(scankbd_data->scan_kbd_dev)); printk(KERN_ALERT "keycode %i\n", scankbd_data->keycode[scancode]); } else input_report_key(&(scankbd_data->scan_kbd_dev), scankbd_data->keycode[scancode], 0); //input_sync(&(scankbd_data->scan_kbd_dev)); //printk(KERN_ALERT "scan_kbd %d\n", row); } } scan_kbd_reset_col(col); } //scan_kbd_activate_all(); input_sync(&scankbd_data->scan_kbd_dev); /* if any keys are pressed, enable the timer */ if (num_pressed) {//注册定时器 mod_timer(&scankbd_data->scan_timer, jiffies + SCAN_INTERVAL); } spin_unlock_irqrestore(&scankbd_data->lock, flags);}/* * timer checking for released keys */static void scan_timer_callback(unsigned long data){ printk(KERN_ALERT "Timer callback.\n"); struct scankbd *scankbd_data = (struct scankbd *) data; scankbd_scankeyboard(scankbd_data, NULL);}/* * The 4� keyboard only generates interrupts when a key is pressed. * When a key is pressed, we enable a timer which then scans the * keyboard to detect when the key is released. *//* Scan the hardware keyboard and push any changes up through the input layer */static irqreturn_t scan_kbd_interrupt(int irq, void *dummy, struct pt_regs *regs){ struct scankbd *scankbd_data = dummy; //printk(KERN_ALERT "scan_kbd_interrupt\n"); if (!timer_pending(&scankbd_data->scan_timer)) { /** wait chattering delay **/ udelay(20); scankbd_scankeyboard(scankbd_data, regs); } return IRQ_HANDLED;}static int khello_init_module(void){ int i; unsigned int status; struct scankbd *scankbd; /** * kcalloc - allocate memory for an array. The memory is set to zero. * @n: number of elements. * @size: element size. * @flags: the type of memory to allocate. */ scankbd = kcalloc(1, sizeof(struct scankbd), GFP_KERNEL);// //scankbd = input_allocate_device(); if (!scankbd) return -ENOMEM; //init 9200 gpio register //AT91_SYS->PIOB_PER |= ( AT91C_PIO_PB1 | AT91C_PIO_PB2 | AT91C_PIO_PB6 );//PIO Enable Register //AT91_SYS->PIOB_ODR |= ( AT91C_PIO_PB1 | AT91C_PIO_PB2 | AT91C_PIO_PB6 );//Output Disable Register //AT91_SYS->PIOB_PPUDR &= ~( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );//Pull-up Disable Register //AT91_SYS->PIOB_PPUER |= ( AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11 | AT91C_PIO_PB12 );//Pull-up Enable Register //init 9200 gpio attribute :input /output at91_set_gpio_input(AT91_PIN_PB1,1); at91_set_deglitch(AT91_PIN_PB1,1); at91_set_gpio_input(AT91_PIN_PB2,1); at91_set_deglitch(AT91_PIN_PB2,1); at91_set_gpio_input(AT91_PIN_PB6,1); at91_set_deglitch(AT91_PIN_PB6,1); at91_set_gpio_input(AT91_PIN_PA24,1); at91_set_deglitch(AT91_PIN_PA24,1); at91_set_gpio_output(AT91_PIN_PB7,1); at91_set_gpio_output(AT91_PIN_PB8,1); at91_set_gpio_output(AT91_PIN_PB15,1); at91_set_gpio_output(AT91_PIN_PB16,1); at91_set_gpio_output(AT91_PIN_PB17,1); //printk(KERN_ALERT "init output.\n"); scan_kbd_discharge_all(); AT91_SYS->PIOB_IER |= ( AT91C_PIO_PB1 | AT91C_PIO_PB2 | AT91C_PIO_PB6 );//Interrupt Enable Register AT91_SYS->PIOB_IDR &= ~( AT91C_PIO_PB1 | AT91C_PIO_PB2 | AT91C_PIO_PB6 );//Interrupt Disable Register AT91_SYS->PIOA_IER |= AT91C_PIO_PA24;//Interrupt Enable Register AT91_SYS->PIOA_IDR &= ~AT91C_PIO_PA24;//Interrupt Disable Register status = AT91_SYS->PIOB_ISR & AT91_SYS->PIOB_IMR;//Interrupt Status Register & Interrupt Mask Register AT91_SYS->PMC_PCER |= (1 << AT91C_ID_PIOB);// Peripheral Clock Enable Register AT91_SYS->PMC_PCER |= (1 << AT91C_ID_PIOA);// Peripheral Clock Enable Register /* Store the Source Mode Register as defined in table above */ AT91_SYS->AIC_SMR[2] = (AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED);//Parallel IO Controller A(AIC) Internal Sources Code Label Edge triggered AT91_SYS->AIC_SMR[3] = (AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED);//Parallel IO Controller B(AIC) Internal Sources Code Label Edge triggered init_input_dev(&scankbd->scan_kbd_dev);//init listhaed /listnode scankbd->scan_kbd_dev.evbit[0] = BIT(EV_KEY) ; scankbd->scan_kbd_dev.keycode = scan_kbd_keycode; scankbd->scan_kbd_dev.keycodesize = sizeof(unsigned char); scankbd->scan_kbd_dev.keycodemax = ARRAY_SIZE(scan_kbd_keycode); scankbd->scan_kbd_dev.private = scankbd; memcpy(scankbd->keycode, scan_kbd_keycode, sizeof(scankbd->keycode)); //printk(KERN_ALERT "keycode %i\n",scankbd->keycode[2]); for (i = 0; i < 20; i++) set_bit(scankbd->keycode[i], scankbd->scan_kbd_dev.keybit);//if (scan_kbd_keycode[i]) clear_bit(0, scankbd->scan_kbd_dev.keybit); scankbd->scan_kbd_dev.name = scan_kbd_name; scankbd->scan_kbd_dev.phys = scan_kbd_phys; scankbd->scan_kbd_dev.id.bustype = BUS_HOST; scankbd->scan_kbd_dev.id.vendor = 0x0001; scankbd->scan_kbd_dev.id.product = 0x0001; scankbd->scan_kbd_dev.id.version = 0x0100; /* Init Keyboard rescan timer */ init_timer(&scankbd->scan_timer); scankbd->scan_timer.function = scan_timer_callback; //printk(KERN_ALERT "timerdata: %ul\n", (unsigned long) scankbd); scankbd->scan_timer.data = (unsigned long) scankbd;//(unsigned long) scankbd //add_timer(&scankbd->scan_timer); //for (i = 0; i < 20; i++) // scankbd->state[i] = 0; scankbd_dev = scankbd; //Enable interrupt 内存泄露,中断源泄露 if(-EINVAL == request_irq(AT91_PIN_PA24,scan_kbd_interrupt,SA_INTERRUPT,scan_kbd_name,scankbd) ) { printk(KERN_ALERT"AT91C_PIO_PA24 is busy."); return -EBUSY; } if( request_irq(AT91_PIN_PB1,scan_kbd_interrupt,SA_INTERRUPT,scan_kbd_name,scankbd) ) { printk(KERN_ALERT"AT91C_PIO_PB1 is busy."); return -EBUSY; } if( request_irq(AT91_PIN_PB2 ,scan_kbd_interrupt,SA_INTERRUPT,scan_kbd_name,scankbd) ) { printk(KERN_ALERT"AT91C_PIO_PB2 is busy."); return -EBUSY; } if( request_irq(AT91_PIN_PB6,scan_kbd_interrupt,SA_INTERRUPT,scan_kbd_name,scankbd) ) { printk(KERN_ALERT"AT91C_PIO_PB6 is busy."); return -EBUSY; } input_register_device(&scankbd->scan_kbd_dev); printk(KERN_ALERT "input: %s init\n", scan_kbd_name); return 0;}static void khello_exit_module(void){ //struct scankbd *scankbd; free_irq(AT91C_PIO_PA24, scankbd_dev); free_irq(AT91C_PIO_PB6, scankbd_dev); free_irq(AT91C_PIO_PB2, scankbd_dev); free_irq(AT91C_PIO_PB1, scankbd_dev); del_timer_sync(&scankbd_dev->scan_timer); input_unregister_device(&scankbd_dev->scan_kbd_dev);/** * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. * * Don't free memory not originally allocated by kmalloc() * or you will run into trouble. */ kfree(scankbd_dev); printk(KERN_ALERT "Module khello exit\n" );}module_init(khello_init_module);module_exit(khello_exit_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -