⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wmt_keyb.c

📁 This document describes how to complie keyboard and mouse driver. 键盘驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
        /*Because after interrupt handle finish, the irq will open automatically         need it need close irq.
        */
       

        if (use_delay_20 == 1){
	    del_timer(&delay_20);
	    use_delay_20 = 0;
        }
        else if (use_delay_100 == 1){
	    del_timer(&delay_100);
	    use_delay_100 = 0;
        }
        else if (use_delay_300 == 1){
	    del_timer(&delay_300);
	    use_delay_300 = 0;
        }
	   

	tmp = GPLR0;
	irq_state = tmp & 0x0004; //get interrupt line(GPIO2) state.

      /*If the irq(the bit is 0) is still occur, it means press a key. 
          Otherwise it means no key pressed, it need finish this interrupt handle.
      */
	if(irq_state == 0){
	    buf = inl(KBD_WMT_DATA);
	    scancode = buf & 0xFF;
	    
        /*if scancode isn't which we need, it should enable irq, and return 0*/
           if((scancode!=CODE_1)&&(scancode!=CODE_2)&&(scancode!=CODE_3)&&
              (scancode!=CODE_4)&&(scancode!=CODE_5)&&(scancode!=CODE_6)&&
              (scancode!=CODE_7)&&(scancode!=CODE_8)&&(scancode!=CODE_9)&&
              (scancode!=CODE_0)&&(scancode!=CODE_XIN)&&(scancode!=CODE_JIN)&&
              (scancode!=CODE_UP)&&(scancode!=CODE_DOWN)&&
	      (scancode!=CODE_LEFT)&&(scancode!=CODE_RIGHT)&&
	      (scancode!=CODE_OK)&&(scancode!=CODE_CANCEL)&&
              (scancode!=CODE_LISTEN)&&(scancode!=CODE_SWITCH)&&
	      (scancode!=MOUSE_OK)&&(scancode!=MOUSE_LEFT)&&
	      (scancode!=MOUSE_RIGHT)&&(scancode!=MOUSE_UP)&&
	      (scancode!=MOUSE_DOWN)&&(scancode!=MOUSE_UPLEFT)&&
	      (scancode!=MOUSE_UPRIGHT)&&(scancode!=MOUSE_DOWNLEFT)&&
	      (scancode!=MOUSE_DOWNRIGHT)){

	      #ifdef DEBUG_KBD
	      printk("The key isn't what we need, it should return right now.\n");
	      #endif

	      tmp = GFER0;
	      GFER0 = tmp |0x0004; //open irq;
              handling_interrupt = 0;
			 
	       return 0;
	   }
		   
	

	/*If twice press isn't the same key, save current key, and eliminate tingle again.
           And if they are the same key, it means press a effective  key, handle it.
	*/
	    if (scancode != prev_scancode){
	   	prev_scancode = scancode;
		init_timer(&delay_20);
		delay_20.expires = jiffies + 2;
		delay_20.function = wmt_handle_kbd2_event;
		delay_20.data = 0;
		add_timer(&delay_20);
		use_delay_20 = 1;
		return 0;
	    }
		
	    #ifdef DEBUG_KBD
	    printk("after eliminate tingle, scancode is %x, it need send to upper layer. \n",scancode);
	    #endif
			
		
        if ((scancode == MOUSE_OK)||(scancode == MOUSE_UP)||
       	    (scancode == MOUSE_DOWN)||(scancode == MOUSE_LEFT)||
            (scancode == MOUSE_RIGHT)||(scancode == MOUSE_UPLEFT)||
            (scancode == MOUSE_UPRIGHT)||(scancode == MOUSE_DOWNLEFT)||
	    (scancode == MOUSE_DOWNRIGHT)){

            #ifdef DEBUG_KBD
	    printk("It is mouse key, it need translate into mouse message.\n");
	    #endif
			
	    wmt_handle_mouse_event(scancode);
			
	    if (scancode != MOUSE_OK){
		init_timer(&delay_100);
	        delay_100.expires = jiffies + 10;
		delay_100.function = wmt_handle_kbd2_event;
		delay_100.data = 0;
		add_timer(&delay_100);
		use_delay_100 = 1;
		return 0;
	    }
	    else{
		init_timer(&delay_300);
		delay_300.expires = jiffies + 30;
		delay_300.function = wmt_handle_kbd2_event;
		delay_300.data = 0;
		add_timer(&delay_300);
		use_delay_300 = 1;
		return 0;
	    }
	}
	else{
		  	
	    #ifdef DEBUG_KBD
	    printk("It is keyboard key, it need put into tty buffer.\n");
	    #endif
			
	    wmt_handle_keyboard_event(scancode);

             /* Finish handle this press key, delay 300ms to handle next key.*/
            init_timer(&delay_300);
	    delay_300.expires = jiffies + 30;
	    delay_300.function = wmt_handle_kbd2_event;
	    delay_300.data = 0;
	    add_timer(&delay_300);
	    use_delay_300 = 1;
		       
	    return 0;
	}
      }

      tmp = GFER0;
      GFER0 = tmp | 0x0004;  //open irq;
      handling_interrupt = 0;
	  
      return 0;
}

static void wmt_keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	unsigned long flags;

#ifdef CONFIG_VT
	kbd_pt_regs = regs;
#endif
	spin_lock_irqsave(&kbd_controller_lock, flags);
	wmt_handle_kbd_event();
	spin_unlock_irqrestore(&kbd_controller_lock, flags);
}

/*
 * send_data sends a character to the keyboard and waits
 * for an acknowledge, possibly retrying if asked to. Returns
 * the success status.
 *
 * Don't use 'jiffies', so that we don't depend on interrupts
 */

void wmt_leds(unsigned char leds)
{
	if (kbd_exists) {
		kbd_exists = 0;
	}
}



/*
 * Test the keyboard interface.  We basically check to make sure that
 * we can drive each line to the keyboard independently of each other.
 */

int __init wmt_kbd_init_hw(void)
{
       //unsigned int tmp;

       /*
	tmp = GPDR0;
	GPDR0 = tmp & ~(0x0004); //configure GPIO2 become input.

	#ifdef DEBUG_KBD
	printk(KERN_DEBUG "after configure, GPDR0 is %x \n",GPDR0);
	#endif
	   
	tmp = GFER0;
	GFER0 = tmp | 0x0004; //configure GPIO2 become falling-edge detect.

	#ifdef DEBUG_KBD
	printk(KERN_DEBUG "after configure, GFER0 is %x \n",GFER0);
	#endif
	
	tmp = GRER0;
	GRER0 = tmp & ~(0x0004); //disable GPIO2 rasing-edge detect.

	#ifdef DEBUG_KBD
	printk(KERN_DEBUG "after configure, GRER0 is %x \n",GRER0);
	#endif
	*/
	set_GPIO_IRQ_edge(2, GPIO_FALLING_EDGE); //set GPIO2 as interrup source.

	wmt_mouse_init();

	k_setkeycode	= wmt_setkeycode;
	k_getkeycode	= wmt_getkeycode;
	k_translate	= wmt_translate;
	k_unexpected_up	= wmt_unexpected_up;
	k_leds		= wmt_leds;
#ifdef CONFIG_MAGIC_SYSRQ
	k_sysrq_xlate	= wmt_sysrq_xlate;
	k_sysrq_key	= 0x54;
#endif

	/* Ok, finally allocate the IRQ, and off we go.. */
	if (request_irq(KEYBOARD_IRQ, wmt_keyboard_interrupt, 0, "keyboard", NULL)){
              printk("init keyboard failed.\n");
		return -EBUSY;
	}
	
	#ifdef DEBUG_KBD
	printk("Init keyboard successful.\n");
	#endif
	
	return 0;
}

static inline void wmt_handle_mouse_event(unsigned char scancode)
{
        int button = 0;
        int dx = 0;
        int dy = 0;
	static int old_scancode;
	static int press_number;
	static int time;
	static int oldtime;
	int interval_time;

	add_mouse_randomness(scancode);
	
        time = jiffies;
	if (old_scancode == scancode){
		interval_time = time - oldtime;
		//if press the same key in a short time, we need accelerate mouse move.
		if(interval_time<50){
		     press_number = press_number + 1;  
		     if (press_number >= MOVE_MAX)
			press_number = MOVE_MAX;
		}
		else
		     press_number = 0;   //if time is too long, it needn't accelerate mouse move.
	 }
	 else
		press_number = 0;
	
        oldtime = time;
	   
	if (scancode == MOUSE_OK){
	       button = 0x01;   //means left button down.
	       press_number = 0;
	}
	else if (scancode == MOUSE_UP)
	       dy = MOVE_FIRST+MOVE_LEN*press_number;
	else if (scancode == MOUSE_DOWN){
           /* 
          It will make dy become a unsigned char when transfer to uppre layre,
	    And the dy as a negative  number will become a big int number. So we need
	    set button to notify upper layer that it need dy-256 to get the negative number.
	    */
		dy = -1*MOVE_FIRST-MOVE_LEN*press_number;
                button = button + 32;
	}
        else if (scancode == MOUSE_LEFT){
		dx = -1*MOVE_FIRST-MOVE_LEN*press_number;
                button = button + 16;
	}
	else if (scancode == MOUSE_RIGHT)
	        dx = MOVE_FIRST+MOVE_LEN*press_number;
	else if (scancode == MOUSE_UPLEFT){
                dx = -1*MOVE_FIRST-MOVE_LEN*press_number;
		button = button + 16;
		dy = MOVE_FIRST+MOVE_LEN*press_number;
	}
	else if (scancode == MOUSE_UPRIGHT){
                dx = MOVE_FIRST+MOVE_LEN*press_number;
		dy = MOVE_FIRST+MOVE_LEN*press_number;
	}
	else if (scancode == MOUSE_DOWNLEFT){
                dx = -1*MOVE_FIRST-MOVE_LEN*press_number; 
		button = button + 16;
		dy = -1*MOVE_FIRST-MOVE_LEN*press_number;
		button = button + 32;
	}
	else if (scancode == MOUSE_DOWNRIGHT){
                dx = MOVE_FIRST+MOVE_LEN*press_number;
	        dy = -1*MOVE_FIRST-MOVE_LEN*press_number;
		button = button + 32;
	}

	old_scancode = scancode; 
	
	if (aux_count) {
		int head = queue->head;

                queue->buf[head] = button;
		head = (head + 1) & (AUX_BUF_SIZE-1);
		queue->buf[head] = dx;
		head = (head + 1) & (AUX_BUF_SIZE-1);
		queue->buf[head] = dy;
		head = (head + 1) & (AUX_BUF_SIZE-1);

		/*
		Because in our WMT system, it just occurs the key-down, and the upper 
		layer need key-down and key-down. And when press mouse left button
		down, it need add a message of mouse left buuton up.
		*/
                if (scancode == MOUSE_OK){
		        queue->buf[head] = 0;              //means left button up
		        head = (head + 1) & (AUX_BUF_SIZE-1);
		        queue->buf[head] = dx;
		        head = (head + 1) & (AUX_BUF_SIZE-1);
		        queue->buf[head] = dy;
		        head = (head + 1) & (AUX_BUF_SIZE-1);
                }
		
		if (head != queue->tail) {
			queue->head = head;
			kill_fasync(&queue->fasync, SIGIO, POLL_IN);
			wake_up_interruptible(&queue->proc_list);
		}
	}
}

static unsigned char get_from_queue(void)
{
	unsigned char result;
	unsigned long flags;

	spin_lock_irqsave(&kbd_controller_lock, flags);
	result = queue->buf[queue->tail];
	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE - 1);
	spin_unlock_irqrestore(&kbd_controller_lock, flags);
	return result;
}


static inline int queue_empty(void)
{
	return queue->head == queue->tail;
}

static int fasync_mouse(int fd, struct file *filp, int on)
{
	int retval;

	retval = fasync_helper(fd, filp, on, &queue->fasync);
	if (retval < 0)
		return retval;
	return 0;
}


/*
 * Random magic cookie for the aux device
 */
#define AUX_DEV ((void *)queue)

static int release_mouse(struct inode *inode, struct file *file)
{
	fasync_mouse(-1, file, 0);
	if (--aux_count) {
	
		return 0;
	}

	return 0;
}


/*
 * Install interrupt handler.
 * Enable auxiliary device.
 */

static int open_mouse(struct inode *inode, struct file *file)
{
	if (aux_count++) {
		return 0;
	}
	queue->head = queue->tail = 0;		/* Flush input queue */

	return 0;
}

/*
 * Put bytes from input queue to buffer.
 */

static ssize_t
read_mouse(struct file *file, char *buffer, size_t count, loff_t * ppos)
{
	DECLARE_WAITQUEUE(wait, current);
	ssize_t i = count;
	unsigned char c;

	if (queue_empty()) {
		if (file->f_flags & O_NONBLOCK)
			return -EAGAIN;
		add_wait_queue(&queue->proc_list, &wait);
	      repeat:
		set_current_state(TASK_INTERRUPTIBLE);
		if (queue_empty() && !signal_pending(current)) {
			schedule();
			goto repeat;
		}
		current->state = TASK_RUNNING;
		remove_wait_queue(&queue->proc_list, &wait);
	}
	while (i > 0 && !queue_empty()) {
		c = get_from_queue();
		put_user(c, buffer++);
		i--;
	}
	if (count - i) {
		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
		return count - i;
	}
	if (signal_pending(current))
		return -ERESTARTSYS;
	return 0;
}

/*
 * Write to the aux device.
 */

static ssize_t
write_mouse(struct file *file, const char *buffer, size_t count,
	  loff_t * ppos)
{
	ssize_t retval = 0;

	if (count) {
		ssize_t written = 0;

		if (count > 32)
			count = 32;	/* Limit to 32 bytes. */
		do {
			char c;
			get_user(c, buffer++);
			written++;
		}
		while (--count);
		retval = -EIO;
		if (written) {
			retval = written;
			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
		}
	}

	return retval;
}

static unsigned int mouse_poll(struct file *file, poll_table * wait)
{
	poll_wait(file, &queue->proc_list, wait);
	if (!queue_empty())
		return POLLIN | POLLRDNORM;
	return 0;
}

struct file_operations wmtmouse_fops = {
	read:		read_mouse,
	write:		write_mouse,
	poll:		mouse_poll,
	open:		open_mouse,
	release:	release_mouse,
	fasync:		fasync_mouse,
};

/*
 * Initialize driver.
 */
static struct miscdevice wmt_mouse = {
	8, "wmtmouse", &wmtmouse_fops
};


static int __init wmt_mouse_init(void)
{
       int retval;

	if ((retval = misc_register(&wmt_mouse))){
		printk("wmt_mouse register failed.\n");
		return retval;
	}
	
	#ifdef DEBUG_KBD
	printk("wmt_mouse register successful.\n");
	#endif

	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
	if (queue == NULL) {
		printk(KERN_ERR "wmtmouse_init(): out of memory\n");
		misc_deregister(&wmt_mouse);
		return -ENOMEM;
	}
	memset(queue, 0, sizeof(*queue));
	queue->head = queue->tail = 0;
	init_waitqueue_head(&queue->proc_list);
	
	return 0;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -