Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/atkbdc/atkbd.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/psl.h> | #include <machine/psl.h> | ||||
#include <compat/x86bios/x86bios.h> | |||||
#include <machine/pc/bios.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
#include <isa/isareg.h> | #include <isa/isareg.h> | ||||
#endif /* __i386__ || __amd64__ */ | #endif /* __i386__ || __amd64__ */ | ||||
Show All 17 Lines | |||||
static void atkbd_timeout(void *arg); | static void atkbd_timeout(void *arg); | ||||
static void atkbd_shutdown_final(void *v); | static void atkbd_shutdown_final(void *v); | ||||
static int atkbd_reset(KBDC kbdc, int flags, int c); | static int atkbd_reset(KBDC kbdc, int flags, int c); | ||||
#define HAS_QUIRK(p, q) (((atkbdc_softc_t *)(p))->quirks & q) | #define HAS_QUIRK(p, q) (((atkbdc_softc_t *)(p))->quirks & q) | ||||
#define ALLOW_DISABLE_KBD(kbdc) !HAS_QUIRK(kbdc, KBDC_QUIRK_KEEP_ACTIVATED) | #define ALLOW_DISABLE_KBD(kbdc) !HAS_QUIRK(kbdc, KBDC_QUIRK_KEEP_ACTIVATED) | ||||
#define DEFAULT_DELAY 0x1 /* 500ms */ | |||||
#define DEFAULT_RATE 0x10 /* 14Hz */ | |||||
int | int | ||||
atkbd_probe_unit(device_t dev, int irq, int flags) | atkbd_probe_unit(device_t dev, int irq, int flags) | ||||
{ | { | ||||
keyboard_switch_t *sw; | keyboard_switch_t *sw; | ||||
int args[2]; | int args[2]; | ||||
int error; | int error; | ||||
sw = kbd_get_switch(ATKBD_DRIVER_NAME); | sw = kbd_get_switch(ATKBD_DRIVER_NAME); | ||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | static keyboard_switch_t atkbdsw = { | ||||
genkbd_get_fkeystr, | genkbd_get_fkeystr, | ||||
atkbd_poll, | atkbd_poll, | ||||
genkbd_diag, | genkbd_diag, | ||||
}; | }; | ||||
KEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); | KEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure); | ||||
/* local functions */ | /* local functions */ | ||||
static int get_typematic(keyboard_t *kbd); | static int set_typematic(keyboard_t *kbd); | ||||
static int setup_kbd_port(KBDC kbdc, int port, int intr); | static int setup_kbd_port(KBDC kbdc, int port, int intr); | ||||
static int get_kbd_echo(KBDC kbdc); | static int get_kbd_echo(KBDC kbdc); | ||||
static int probe_keyboard(KBDC kbdc, int flags); | static int probe_keyboard(KBDC kbdc, int flags); | ||||
static int init_keyboard(KBDC kbdc, int *type, int flags); | static int init_keyboard(KBDC kbdc, int *type, int flags); | ||||
static int write_kbd(KBDC kbdc, int command, int data); | static int write_kbd(KBDC kbdc, int command, int data); | ||||
static int get_kbd_id(KBDC kbdc); | static int get_kbd_id(KBDC kbdc); | ||||
static int typematic(int delay, int rate); | static int typematic(int delay, int rate); | ||||
static int typematic_delay(int delay); | static int typematic_delay(int delay); | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { | ||||
if (KBD_HAS_DEVICE(kbd) | if (KBD_HAS_DEVICE(kbd) | ||||
&& init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) | && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) | ||||
&& (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { | && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) { | ||||
kbd_unregister(kbd); | kbd_unregister(kbd); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); | atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); | ||||
get_typematic(kbd); | set_typematic(kbd); | ||||
delay[0] = kbd->kb_delay1; | delay[0] = kbd->kb_delay1; | ||||
delay[1] = kbd->kb_delay2; | delay[1] = kbd->kb_delay2; | ||||
atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); | atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); | ||||
KBD_INIT_DONE(kbd); | KBD_INIT_DONE(kbd); | ||||
} | } | ||||
if (!KBD_IS_CONFIGURED(kbd)) { | if (!KBD_IS_CONFIGURED(kbd)) { | ||||
if (kbd_register(kbd) < 0) { | if (kbd_register(kbd) < 0) { | ||||
error = ENXIO; | error = ENXIO; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | atkbd_intr(keyboard_t *kbd, void *arg) | ||||
if (!KBD_HAS_DEVICE(kbd)) { | if (!KBD_HAS_DEVICE(kbd)) { | ||||
/* | /* | ||||
* The keyboard was not detected before; | * The keyboard was not detected before; | ||||
* it must have been reconnected! | * it must have been reconnected! | ||||
*/ | */ | ||||
init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config); | init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config); | ||||
KBD_FOUND_DEVICE(kbd); | KBD_FOUND_DEVICE(kbd); | ||||
atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); | atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); | ||||
get_typematic(kbd); | set_typematic(kbd); | ||||
delay[0] = kbd->kb_delay1; | delay[0] = kbd->kb_delay1; | ||||
delay[1] = kbd->kb_delay2; | delay[1] = kbd->kb_delay2; | ||||
atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); | atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); | ||||
} | } | ||||
if (state->ks_polling) | if (state->ks_polling) | ||||
return 0; | return 0; | ||||
▲ Show 20 Lines • Show All 615 Lines • ▼ Show 20 Lines | if (!(flags & KB_CONF_NO_RESET) && !reset_kbd(kbdc)) { | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* local functions */ | /* local functions */ | ||||
static int | static int | ||||
get_typematic(keyboard_t *kbd) | set_typematic(keyboard_t *kbd) | ||||
{ | { | ||||
#if defined(__i386__) || defined(__amd64__) | int val, error; | ||||
/* | atkbd_state_t *state = kbd->kb_data; | ||||
* Only some systems allow us to retrieve the keyboard repeat | |||||
* rate previously set via the BIOS... | |||||
*/ | |||||
x86regs_t regs; | |||||
uint8_t *p; | |||||
/* | val = typematic(DEFAULT_DELAY, DEFAULT_RATE); | ||||
* Traditional entry points of int 0x15 and 0x16 are fixed | error = write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, val); | ||||
* and later BIOSes follow them. (U)EFI CSM specification | if (error == 0) { | ||||
* also mandates these fixed entry points. | kbd->kb_delay1 = typematic_delay(val); | ||||
* | kbd->kb_delay2 = typematic_rate(val); | ||||
* Validate the entry points here before we proceed further. | } | ||||
* It's known that some recent laptops does not have the | |||||
* same entry point and hang on boot if we call it. | |||||
*/ | |||||
if (x86bios_get_intr(0x15) != 0xf000f859 || | |||||
x86bios_get_intr(0x16) != 0xf000e82e) | |||||
return (ENODEV); | |||||
/* Is BIOS system configuration table supported? */ | return (error); | ||||
x86bios_init_regs(®s); | |||||
regs.R_AH = 0xc0; | |||||
x86bios_intr(®s, 0x15); | |||||
if ((regs.R_FLG & PSL_C) != 0 || regs.R_AH != 0) | |||||
return (ENODEV); | |||||
/* Is int 0x16, function 0x09 supported? */ | |||||
p = x86bios_offset((regs.R_ES << 4) + regs.R_BX); | |||||
if (readw(p) < 5 || (readb(p + 6) & 0x40) == 0) | |||||
return (ENODEV); | |||||
/* Is int 0x16, function 0x0306 supported? */ | |||||
x86bios_init_regs(®s); | |||||
regs.R_AH = 0x09; | |||||
x86bios_intr(®s, 0x16); | |||||
if ((regs.R_AL & 0x08) == 0) | |||||
return (ENODEV); | |||||
x86bios_init_regs(®s); | |||||
regs.R_AX = 0x0306; | |||||
x86bios_intr(®s, 0x16); | |||||
kbd->kb_delay1 = typematic_delay(regs.R_BH << 5); | |||||
kbd->kb_delay2 = typematic_rate(regs.R_BL); | |||||
return (0); | |||||
#else | |||||
return (ENODEV); | |||||
#endif /* __i386__ || __amd64__ */ | |||||
} | } | ||||
static int | static int | ||||
setup_kbd_port(KBDC kbdc, int port, int intr) | setup_kbd_port(KBDC kbdc, int port, int intr) | ||||
{ | { | ||||
if (!set_controller_command_byte(kbdc, | if (!set_controller_command_byte(kbdc, | ||||
KBD_KBD_CONTROL_BITS, | KBD_KBD_CONTROL_BITS, | ||||
((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) | ((port) ? KBD_ENABLE_KBD_PORT : KBD_DISABLE_KBD_PORT) | ||||
▲ Show 20 Lines • Show All 372 Lines • Show Last 20 Lines |