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

📄 pcikbd.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: pcikbd.c,v 1.49 2000/07/13 08:06:40 davem Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be) * JavaStation support by Pete A. Zaitcev. * * This code is mainly put together from various places in * drivers/char, please refer to these sources for credits * to the original authors. */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/poll.h>#include <linux/malloc.h>#include <linux/errno.h>#include <linux/random.h>#include <linux/miscdevice.h>#include <linux/kbd_ll.h>#include <linux/kbd_kern.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <asm/ebus.h>#include <asm/oplib.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/uaccess.h>/* * Different platforms provide different permutations of names. * AXi - kb_ps2, kdmouse. * MrCoffee - keyboard, mouse. * Espresso - keyboard, kdmouse. */#define	PCI_KB_NAME1	"kb_ps2"#define PCI_KB_NAME2	"keyboard"#define PCI_MS_NAME1	"kdmouse"#define PCI_MS_NAME2	"mouse"#include "pcikbd.h"#include "sunserial.h"#ifndef __sparc_v9__static int pcikbd_mrcoffee = 0;#else#define pcikbd_mrcoffee 0#endifstatic unsigned long pcikbd_iobase = 0;static unsigned int pcikbd_irq = 0;/* used only by send_data - set by keyboard_interrupt */static volatile unsigned char reply_expected = 0;static volatile unsigned char acknowledge = 0;static volatile unsigned char resend = 0;static spinlock_t pcikbd_lock = SPIN_LOCK_UNLOCKED;unsigned char pckbd_read_mask = KBD_STAT_OBF;extern int pcikbd_init(void);extern void pci_compute_shiftstate(void);extern int pci_setkeycode(unsigned int, unsigned int);extern int pci_getkeycode(unsigned int);extern void pci_setledstate(struct kbd_struct *, unsigned int);extern unsigned char pci_getledstate(void);#define pcikbd_inb(x)     inb(x)#define pcikbd_outb(v,x)  outb(v,x)/* Wait for keyboard controller input buffer to drain. * Must be invoked under the pcikbd_lock. */static void kb_wait(void){	unsigned long timeout = 250;	do {		if(!(pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG) & KBD_STAT_IBF))			return;		mdelay(1);	} while (--timeout);}/* * Translation of escaped scancodes to keycodes. * This is now user-settable. * The keycodes 1-88,96-111,119 are fairly standard, and * should probably not be changed - changing might confuse X. * X also interprets scancode 0x5d (KEY_Begin). * * For 1-88 keycode equals scancode. */#define E0_KPENTER 96#define E0_RCTRL   97#define E0_KPSLASH 98#define E0_PRSCR   99#define E0_RALT    100#define E0_BREAK   101  /* (control-pause) */#define E0_HOME    102#define E0_UP      103#define E0_PGUP    104#define E0_LEFT    105#define E0_RIGHT   106#define E0_END     107#define E0_DOWN    108#define E0_PGDN    109#define E0_INS     110#define E0_DEL     111#define E1_PAUSE   119/* * The keycodes below are randomly located in 89-95,112-118,120-127. * They could be thrown away (and all occurrences below replaced by 0), * but that would force many users to use the `setkeycodes' utility, where * they needed not before. It does not matter that there are duplicates, as * long as no duplication occurs for any single keyboard. */#define SC_LIM 89#define FOCUS_PF1 85           /* actual code! */#define FOCUS_PF2 89#define FOCUS_PF3 90#define FOCUS_PF4 91#define FOCUS_PF5 92#define FOCUS_PF6 93#define FOCUS_PF7 94#define FOCUS_PF8 95#define FOCUS_PF9 120#define FOCUS_PF10 121#define FOCUS_PF11 122#define FOCUS_PF12 123#define JAP_86     124/* tfj@olivia.ping.dk: * The four keys are located over the numeric keypad, and are * labelled A1-A4. It's an rc930 keyboard, from * Regnecentralen/RC International, Now ICL. * Scancodes: 59, 5a, 5b, 5c. */#define RGN1 124#define RGN2 125#define RGN3 126#define RGN4 127static unsigned char high_keys[128 - SC_LIM] = {  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */};/* BTC */#define E0_MACRO   112/* LK450 */#define E0_F13     113#define E0_F14     114#define E0_HELP    115#define E0_DO      116#define E0_F17     117#define E0_KPMINPLUS 118/* * My OmniKey generates e0 4c for  the "OMNI" key and the * right alt key does nada. [kkoller@nyx10.cs.du.edu] */#define E0_OK	124/* * New microsoft keyboard is rumoured to have * e0 5b (left window button), e0 5c (right window button), * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] * [or: Windows_L, Windows_R, TaskMan] */#define E0_MSLW	125#define E0_MSRW	126#define E0_MSTM	127static unsigned char e0_keys[128] = {  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */};/* Simple translation table for the SysRq keys */#ifdef CONFIG_MAGIC_SYSRQunsigned char pcikbd_sysrq_xlate[128] =	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */	"\r\000/";					/* 0x60 - 0x6f */#endifint pcikbd_setkeycode(unsigned int scancode, unsigned int keycode){	if(scancode < SC_LIM || scancode > 255 || keycode > 127)		return -EINVAL;	if(scancode < 128)		high_keys[scancode - SC_LIM] = keycode;	else		e0_keys[scancode - 128] = keycode;	return 0;}int pcikbd_getkeycode(unsigned int scancode){	return		(scancode < SC_LIM || scancode > 255) ? -EINVAL :		(scancode < 128) ? high_keys[scancode - SC_LIM] :		e0_keys[scancode - 128];}int do_acknowledge(unsigned char scancode){	if(reply_expected) {		if(scancode == KBD_REPLY_ACK) {			acknowledge = 1;			reply_expected = 0;			return 0;		} else if(scancode == KBD_REPLY_RESEND) {			resend = 1;			reply_expected = 0;			return 0;		}	}	return 1;}int pcikbd_translate(unsigned char scancode, unsigned char *keycode,		     char raw_mode){	static int prev_scancode = 0;	if (scancode == 0xe0 || scancode == 0xe1) {		prev_scancode = scancode;		return 0;	}	if (scancode == 0x00 || scancode == 0xff) {		prev_scancode = 0;		return 0;	}	scancode &= 0x7f;	if(prev_scancode) {		if(prev_scancode != 0xe0) {			if(prev_scancode == 0xe1 && scancode == 0x1d) {				prev_scancode = 0x100;				return 0;			} else if(prev_scancode == 0x100 && scancode == 0x45) {				*keycode = E1_PAUSE;				prev_scancode = 0;			} else {				prev_scancode = 0;				return 0;			}		} else {			prev_scancode = 0;			if(scancode == 0x2a || scancode == 0x36)				return 0;			if(e0_keys[scancode])				*keycode = e0_keys[scancode];			else				return 0;		}	} else if(scancode >= SC_LIM) {		*keycode = high_keys[scancode - SC_LIM];		if(!*keycode)			return 0;	} else		*keycode = scancode;	return 1;}char pcikbd_unexpected_up(unsigned char keycode){	if(keycode >= SC_LIM || keycode == 85)		return 0;	else		return 0200;}static voidpcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs){	unsigned long flags;	unsigned char status;	spin_lock_irqsave(&pcikbd_lock, flags);	kbd_pt_regs = regs;	status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);	do {		unsigned char scancode;		if(status & pckbd_read_mask & KBD_STAT_MOUSE_OBF)			break;		scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);		if((status & KBD_STAT_OBF) && do_acknowledge(scancode))			handle_scancode(scancode, !(scancode & 0x80));		status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);	} while(status & KBD_STAT_OBF);	tasklet_schedule(&keyboard_tasklet);	spin_unlock_irqrestore(&pcikbd_lock, flags);}static int send_data(unsigned char data){	int retries = 3;	unsigned long flags;	spin_lock_irqsave(&pcikbd_lock, flags);	do {		unsigned long timeout = 1000;		kb_wait();		acknowledge = 0;		resend = 0;		reply_expected = 1;		pcikbd_outb(data, pcikbd_iobase + KBD_DATA_REG);		do {			if (acknowledge)				goto out_ack;			if (resend)				break;			mdelay(1);		} while (--timeout);		if (timeout == 0)			goto out_timeout;	} while (retries-- > 0);out_timeout:	spin_unlock_irqrestore(&pcikbd_lock, flags);	return 0;out_ack:	spin_unlock_irqrestore(&pcikbd_lock, flags);	return 1;}void pcikbd_leds(unsigned char leds){	if(!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))		send_data(KBD_CMD_ENABLE);		}static int __init pcikbd_wait_for_input(void){	int status, data;	unsigned long timeout = 1000;	do {		mdelay(1);		status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);		if (!(status & KBD_STAT_OBF))			continue;		data = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);		if (status & (KBD_STAT_GTO | KBD_STAT_PERR))			continue;		return (data & 0xff);	} while (--timeout > 0);	return -1;}static void __init pcikbd_write(int address, int data){	int status;	do {		status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);	} while (status & KBD_STAT_IBF);	pcikbd_outb(data, pcikbd_iobase + address);}#ifdef __sparc_v9__static unsigned long pcibeep_iobase = 0;/* Timer routine to turn off the beep after the interval expires. */static void pcikbd_kd_nosound(unsigned long __unused){	outl(0, pcibeep_iobase);}/* * Initiate a keyboard beep. If the frequency is zero, then we stop * the beep. Any other frequency will start a monotone beep. The beep * will be stopped by a timer after "ticks" jiffies. If ticks is 0, * then we do not start a timer. */static void pcikbd_kd_mksound(unsigned int hz, unsigned int ticks){	unsigned long flags;	static struct timer_list sound_timer = { function: pcikbd_kd_nosound };	save_flags(flags); cli();	del_timer(&sound_timer);	if (hz) {		outl(1, pcibeep_iobase);		if (ticks) {			sound_timer.expires = jiffies + ticks;			add_timer(&sound_timer);		}	} else		outl(0, pcibeep_iobase);	restore_flags(flags);}#endifstatic void nop_kd_mksound(unsigned int hz, unsigned int ticks){}extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);static char * __init do_pcikbd_init_hw(void){	while(pcikbd_wait_for_input() != -1)		;	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);	if(pcikbd_wait_for_input() != 0x55)		return "Keyboard failed self test";	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);	if(pcikbd_wait_for_input() != 0x00)		return "Keyboard interface failed self test";	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);	pcikbd_write(KBD_DATA_REG, KBD_CMD_RESET);	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)		return "Keyboard reset failed, no ACK";	if(pcikbd_wait_for_input() != KBD_REPLY_POR)		return "Keyboard reset failed, no ACK";	pcikbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)		return "Disable keyboard: no ACK";	pcikbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);	pcikbd_write(KBD_DATA_REG,		     (KBD_MODE_KBD_INT | KBD_MODE_SYS |		      KBD_MODE_DISABLE_MOUSE | KBD_MODE_KCC));	pcikbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)		return "Enable keyboard: no ACK";	pcikbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)		return "Set rate: no ACK";	pcikbd_write(KBD_DATA_REG, 0x00);	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)		return "Set rate: no ACK";	return NULL; /* success */}void __init pcikbd_init_hw(void){	struct linux_ebus *ebus;	struct linux_ebus_device *edev;	struct linux_ebus_child *child;	char *msg;	if (pcikbd_mrcoffee) {		if ((pcikbd_iobase = (unsigned long) ioremap(0x71300060, 8)) == 0) {			prom_printf("pcikbd_init_hw: cannot map\n");			return;		}		pcikbd_irq = 13 | 0x20;		if (request_irq(pcikbd_irq, &pcikbd_interrupt,				SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) {			printk("8042: cannot register IRQ %x\n", pcikbd_irq);			return;		}		printk("8042(kbd): iobase[%x] irq[%x]\n",		    (unsigned)pcikbd_iobase, pcikbd_irq);	} else {		for_each_ebus(ebus) {			for_each_ebusdev(edev, ebus) {				if(!strcmp(edev->prom_name, "8042")) {					for_each_edevchild(edev, child) {                                                if (strcmp(child->prom_name, PCI_KB_NAME1) == 0 ||						    strcmp(child->prom_name, PCI_KB_NAME2) == 0)							goto found;					}				}			}		}		printk("pcikbd_init_hw: no 8042 found\n");		return;found:		pcikbd_iobase = child->resource[0].start;		pcikbd_irq = child->irqs[0];		if (request_irq(pcikbd_irq, &pcikbd_interrupt,				SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) {			printk("8042: cannot register IRQ %s\n",			       __irq_itoa(pcikbd_irq));			return;		}		printk("8042(kbd) at 0x%lx (irq %s)\n", pcikbd_iobase,		       __irq_itoa(pcikbd_irq));	}	kd_mksound = nop_kd_mksound;#ifdef __sparc_v9__	edev = 0;	for_each_ebus(ebus) {		for_each_ebusdev(edev, ebus) {			if(!strcmp(edev->prom_name, "beeper"))				goto ebus_done;		}	}ebus_done:	/*	 * XXX: my 3.1.3 PROM does not give me the beeper node for the audio	 *      auxio register, though I know it is there... (ecd)	 *	 * JavaStations appear not to have beeper. --zaitcev	 */	if (!edev)		pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000;	else		pcibeep_iobase = edev->resource[0].start;	kd_mksound = pcikbd_kd_mksound;	printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase,	       edev ? "" : " (forced)");#endif	disable_irq(pcikbd_irq);	msg = do_pcikbd_init_hw();	enable_irq(pcikbd_irq);	if(msg)

⌨️ 快捷键说明

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