diff -urN kernel26/arch/arm/mach-pxa/h4000/Kconfig kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/Kconfig
--- kernel26/arch/arm/mach-pxa/h4000/Kconfig	2005-06-28 21:45:37.000000000 -0600
+++ kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/Kconfig	2006-03-24 21:33:37.000000000 -0700
@@ -32,3 +32,7 @@
 config IPAQ_H4000_BUTTONS
         tristate "Buttons support"
         depends on IPAQ_HANDHELD && MACH_H4000 && HTC_ASIC3
+
+config IPAQ_H4300_KBD
+        tristate "Keyboard support for h4300 model"
+        depends on IPAQ_HANDHELD && MACH_H4000 && HTC_ASIC3
diff -urN kernel26/arch/arm/mach-pxa/h4000/Makefile kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/Makefile
--- kernel26/arch/arm/mach-pxa/h4000/Makefile	2005-12-07 21:35:07.000000000 -0700
+++ kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/Makefile	2006-03-24 21:32:49.000000000 -0700
@@ -9,3 +9,4 @@
 obj-$(CONFIG_IPAQ_H4000_UDC)     += h4000_udc.o
 obj-$(CONFIG_IPAQ_H4000_PCMCIA)  += h4000_pcmcia.o
 obj-$(CONFIG_IPAQ_H4000_BUTTONS) += h4000_buttons.o
+obj-$(CONFIG_IPAQ_H4300_KBD)     += h4300_kbd.o
diff -urN kernel26/arch/arm/mach-pxa/h4000/h4000.c kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/h4000.c
--- kernel26/arch/arm/mach-pxa/h4000/h4000.c	2006-03-23 20:22:45.000000000 -0700
+++ kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/h4000.c	2006-03-24 21:35:08.000000000 -0700
@@ -49,6 +49,7 @@
 void h4000_ll_pm_init(void);
 
 static struct platform_device h4000_lcd       = { .name = "h4000_lcd", };
+static struct platform_device h4300_kbd       = { .name = "h4300_kbd", };
 static struct platform_device h4000_buttons   = { .name = "h4000_buttons", };
 static struct platform_device h4000_ts        = { .name = "h4000_ts", };
 static struct platform_device h4000_udc       = { .name = "h4000_udc", };
@@ -56,6 +57,7 @@
 
 static struct platform_device *h4000_asic3_devices[] __initdata = {
 	&h4000_lcd,
+	&h4300_kbd,
 	&h4000_buttons,
 	&h4000_ts,
 	&h4000_udc,
diff -urN kernel26/arch/arm/mach-pxa/h4000/h4300_kbd.c kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/h4300_kbd.c
--- kernel26/arch/arm/mach-pxa/h4000/h4300_kbd.c	1969-12-31 17:00:00.000000000 -0700
+++ kernel26-mar24_h4300_kbd/arch/arm/mach-pxa/h4000/h4300_kbd.c	2006-03-24 21:32:04.000000000 -0700
@@ -0,0 +1,295 @@
+/*
+ *  h4300_kbd.c
+ *  Keyboard support for the h4350 ipaq
+ *
+ *  (c) Shawn Anderson, March, 2006
+ *  This code is released under the GNU General Public License
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <asm/arch/h4000-gpio.h>
+#include <asm/arch/h4000-asic.h>
+#include <linux/soc/asic3_base.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/hardware.h>
+#include <asm/arch/bitfield.h>
+
+static struct input_dev *h4300_kbd;
+#define a3 &h4000_asic3.dev
+
+#define KEY_RECORD_L   65 // Xmodmap - 73   F7
+#define KEY_SLEEP_L    64 // Xmodmap - 72   F6
+#define KEY_CALENDAR_L 67 // Xmodmap - 75   F9
+#define KEY_CONTACTS_L 68 // Xmodmap - 76   F10
+#define KEY_MAIL_L     66 // Xmodmap - 74   F8
+#define KEY_HOME_L     88 // Xmodmap - 96   F12
+
+#define KEY_FUNC 0x32
+static unsigned int h4300_keycode[0x80] = {
+/*0*/   0, 0, 0, 0, 0, 0, 0, 0,
+        0,             0,              KEY_CALENDAR_L, KEY_CONTACTS_L,
+        0,             0,              KEY_MAIL_L,     KEY_HOME_L,
+/*1*/   KEY_R,         KEY_RIGHT,      KEY_W,          KEY_E,
+        KEY_SELECT,    KEY_U,          KEY_I,          KEY_P,
+        KEY_F,         KEY_Y,          KEY_Q,          KEY_D,
+        KEY_DOWN,      KEY_K,          KEY_O,          KEY_BACKSPACE,
+/*2*/   KEY_X,         KEY_H,          KEY_A,          KEY_S,
+        KEY_T,         KEY_J,          KEY_L,          KEY_ENTER,
+        KEY_C,         KEY_B,          KEY_LEFTSHIFT,  KEY_Z,
+        KEY_G,         KEY_M,          KEY_1,          KEY_APOSTROPHE,
+/*3*/   KEY_ESC,       KEY_SPACE,      0/*KEY_FUNC*/,  KEY_TAB,
+        KEY_V,         KEY_N,          KEY_COMMA,      KEY_SLASH,
+        KEY_LEFT,      KEY_UP,         0, 0,
+        KEY_LEFTCTRL,  KEY_DOT,        0, 0,
+/*4*/   0, 0, 0, 0, 0, 0, 0, 0,
+        0,             0,              KEY_PROG1,      KEY_PROG2,
+        0,             0,              KEY_PROG3,      KEY_PROG4,
+/*5*/   KEY_5,         KEY_RIGHT,      KEY_2,          KEY_4,
+        KEY_SELECT,    KEY_1,          KEY_2,          KEY_SLASH,
+        KEY_EQUAL,     KEY_MINUS,      KEY_GRAVE,      KEY_SEMICOLON,
+        KEY_DOWN,      KEY_5,          KEY_3,          KEY_DELETE,
+/*6*/   KEY_SEMICOLON, KEY_KPPLUS,     KEY_9,          KEY_0,
+        KEY_MINUS,     KEY_4,          KEY_6,          KEY_ENTER,
+        KEY_LEFT,      KEY_RIGHT,      KEY_CAPSLOCK,   KEY_7,
+        KEY_UP,        KEY_8,          KEY_9,          KEY_APOSTROPHE,
+/*7*/   KEY_ESC,       KEY_COMPOSE,    0/*KEY_FUNC*/,  KEY_TAB,
+        KEY_DOWN,      KEY_7,          KEY_0,          KEY_3,
+        KEY_LEFT,      KEY_UP,         0, 0,
+        KEY_BACKSLASH, KEY_KPASTERISK, 0, 0
+};
+
+static int asic3_spi_process_byte(unsigned char data)
+{
+#define ASIC3_SPI_CTRL    (0x400)
+#define ASIC3_SPI_DATA    (0x408)
+#define SPI_CTRL_SEL      (1 << 6)
+#define SPI_CTRL_SPIE     (1 << 5)
+#define SPI_CTRL_SPE      (1 << 4)
+	unsigned long flags;
+	unsigned int timeout;
+	unsigned int ctrl;
+	int result = 0;
+
+	local_irq_save(flags);
+
+	/* Enable interrupts */
+	ctrl = asic3_read_register(a3, ASIC3_SPI_CTRL) | SPI_CTRL_SPIE;
+	asic3_write_register(a3, ASIC3_SPI_CTRL, ctrl);
+
+	/* Send data */
+	asic3_write_register(a3, ASIC3_SPI_DATA, data);
+	/* Start the transfer */
+	asic3_write_register(a3, ASIC3_SPI_CTRL, (ctrl | SPI_CTRL_SPE));
+
+	for (timeout = 255; timeout > 0; timeout--) {
+		if (!(asic3_read_register(a3, ASIC3_SPI_CTRL)&SPI_CTRL_SPE)){
+			udelay(20);    /* wait for a while, or we'll miss it */
+			result = asic3_read_register(a3, ASIC3_SPI_DATA);
+			break;
+		}
+	}
+
+	/* Disable interrupts */
+	ctrl = asic3_read_register(a3, ASIC3_SPI_CTRL) & ~SPI_CTRL_SPIE;
+	asic3_write_register(a3, ASIC3_SPI_CTRL, ctrl);
+
+	local_irq_restore(flags);
+	return result & 0xff;
+}
+
+void kbd_task(unsigned long na)
+{
+#define FNC_PRESS   (1<<0)
+#define FNC_REL     (1<<1)
+#define KEY_REL     (1<<2)
+#define FAKE_SHIFT  (1<<3)
+	static int pressed;
+	unsigned char scancode = 0;
+	static unsigned char flags = 0;
+
+	scancode = asic3_spi_process_byte(0);
+	pressed  = (scancode & 0x80) ? 0 : 1;
+	scancode &= ~0x80;
+
+	if ((scancode != KEY_FUNC) && (flags & FNC_PRESS)) {
+		if (!pressed) {
+			if (flags & FNC_REL)
+				flags &= ~(FNC_PRESS | FNC_REL | KEY_REL);
+			else
+				flags |= KEY_REL;
+		}
+		scancode += 0x40; // the keys alternate function
+	}
+
+	switch (scancode) {
+	case KEY_FUNC:
+		if (pressed)
+			flags = FNC_PRESS;
+		else if (flags & KEY_REL)
+			flags &= ~(FNC_PRESS | FNC_REL | KEY_REL);
+		else
+			flags |= FNC_REL;
+		break;
+
+	case 0x2e:case 0x37:case 0x50:case 0x52:case 0x53:case 0x5a: case 0x5b:
+	case 0x62:case 0x63:case 0x64:case 0x6b:case 0x6f:case 0x77: case 0x7c:
+		flags |= FAKE_SHIFT;
+		input_report_key(h4300_kbd, KEY_LEFTSHIFT, pressed);
+		break;
+
+	default:
+		if (flags & FAKE_SHIFT) {
+			input_report_key(h4300_kbd, KEY_LEFTSHIFT, 0);
+			flags &= ~FAKE_SHIFT;
+		}
+		break;
+	}
+
+	input_report_key(h4300_kbd, h4300_keycode[scancode], pressed);
+	input_sync(h4300_kbd);
+}
+DECLARE_TASKLET(task, kbd_task, 0);
+
+static irqreturn_t h4300_keyboard(int irq, void *dev_id, struct pt_regs *regs)
+{
+	tasklet_schedule(&task);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t h4300_rec_btn(int irq, void *data, struct pt_regs *regs)
+{
+	int pressed;
+	pressed = !(ipaq_asic3_read_gpio_status_d(a3) & GPIOD_RECORD_BUTTON_N);
+
+	printk("%s: pressed = %d\n", __FUNCTION__, pressed);
+
+	if (pressed)
+		set_irq_type(irq, IRQT_RISING);
+	else
+		set_irq_type(irq, IRQT_FALLING);
+
+	input_report_key(h4300_kbd, KEY_RECORD_L, pressed);
+	input_sync(h4300_kbd);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t h4300_pwr_btn(int irq, void* data, struct pt_regs *regs)
+{
+	int pressed;
+	pressed = !GET_H4000_GPIO(POWER_BUTTON_N);
+
+	input_report_key(h4300_kbd, KEY_SLEEP_L, pressed);
+	input_sync(h4300_kbd);
+
+	return IRQ_HANDLED;
+}
+
+static void setup_h4300kbd(void)
+{
+	asic3_set_clock_cdex(a3, CLOCK_CDEX_SPI, CLOCK_CDEX_SPI);
+	udelay(20);
+
+	ipaq_asic3_set_gpio_dir_b(a3, GPIOB_KEYBOARD_IRQ, 0);
+	ipaq_asic3_set_gpio_out_b(a3,
+	                (GPIOB_MICRO_3V3_EN | GPIOB_KEYBOARD_WAKE_UP),
+	                (GPIOB_MICRO_3V3_EN | GPIOB_KEYBOARD_WAKE_UP) );
+
+	ipaq_asic3_set_gpio_dir_c(a3, GPIOC_KEY_RXD, 0);
+
+	ipaq_asic3_set_gpio_alt_fn_c(a3,
+	                GPIOC_KEY_RXD | GPIOC_KEY_TXD | GPIOC_KEY_CLK,
+	                GPIOC_KEY_RXD | GPIOC_KEY_TXD | GPIOC_KEY_CLK);
+
+	ipaq_asic3_set_gpio_dir_d(a3,  // disable h4100 buttons
+	                (GPIOD_TASK_BUTTON_N     | GPIOD_MAIL_BUTTON_N |
+	                 GPIOD_CONTACTS_BUTTON_N | GPIOD_CALENDAR_BUTTON_N),
+	                (GPIOD_TASK_BUTTON_N     | GPIOD_MAIL_BUTTON_N |
+	                 GPIOD_CONTACTS_BUTTON_N | GPIOD_CALENDAR_BUTTON_N));
+	asic3_write_register(a3, 0x400, 0xa104);
+}
+
+static int __init h4300_kbd_probe(struct platform_device * pdev)
+{
+	int i, base_irq = asic3_irq_base(a3);
+
+	if (!(h4300_kbd = input_allocate_device()))
+		return -ENOMEM;
+
+	setup_h4300kbd();
+
+	h4300_kbd->name        = "HP iPAQ h4300 keyboard driver";
+	h4300_kbd->evbit[0]    = BIT(EV_KEY) | BIT(EV_REP);
+	h4300_kbd->keycode     = h4300_keycode;
+	h4300_kbd->keycodesize = sizeof(unsigned char);
+	h4300_kbd->keycodemax  = ARRAY_SIZE(h4300_keycode);
+
+	for (i = 0; i < h4300_kbd->keycodemax; i++)
+		if (h4300_keycode[i])
+			set_bit(h4300_keycode[i], h4300_kbd->keybit);
+	request_irq(base_irq + H4000_KEYBOARD_IRQ, &h4300_keyboard,
+			SA_SAMPLE_RANDOM, "Keyboard", NULL);
+
+
+	set_bit(KEY_RECORD_L, h4300_kbd->keybit);
+	request_irq(base_irq + H4000_RECORD_BTN_IRQ, h4300_rec_btn,
+			SA_SAMPLE_RANDOM, "Record button", NULL);
+	set_irq_type(base_irq + H4000_RECORD_BTN_IRQ, IRQT_FALLING);
+
+	set_bit(KEY_SLEEP_L, h4300_kbd->keybit);
+	request_irq(IRQ_GPIO(GPIO_NR_H4000_POWER_BUTTON_N), h4300_pwr_btn,
+			SA_SAMPLE_RANDOM, "Power button", NULL);
+	set_irq_type(IRQ_GPIO(GPIO_NR_H4000_POWER_BUTTON_N), IRQT_BOTHEDGE);
+
+	input_register_device(h4300_kbd);
+
+	return 0;
+}
+
+static int h4300_kbd_remove(struct platform_device * pdev)
+{       
+	int irq_base = asic3_irq_base(a3);
+
+	input_unregister_device(h4300_kbd);
+	free_irq(IRQ_GPIO(GPIO_NR_H4000_POWER_BUTTON_N), NULL);
+	free_irq(irq_base + H4000_RECORD_BTN_IRQ, &h4300_rec_btn);
+	free_irq(irq_base + H4000_KEYBOARD_IRQ, &h4300_keyboard);
+
+	return 0;
+}
+
+void h4300_kbd_shutdown(struct platform_device * pdev)
+{
+	ipaq_asic3_set_gpio_dir_b(a3, GPIOB_KEYBOARD_IRQ, GPIOB_KEYBOARD_IRQ);
+	ipaq_asic3_set_gpio_out_b(a3,
+	                (GPIOB_MICRO_3V3_EN | GPIOB_KEYBOARD_WAKE_UP), 0);
+	ipaq_asic3_set_gpio_dir_c(a3,GPIOC_KEY_RXD,GPIOC_KEY_RXD);
+}
+
+static struct platform_driver h4300_kbd_driver = {
+	.probe    = h4300_kbd_probe,
+	.remove   = h4300_kbd_remove,
+	.shutdown = h4300_kbd_shutdown,
+	.suspend  = NULL,
+	.resume   = NULL,
+	.driver   = {
+	    .name = "h4300_kbd",
+	},
+};
+
+static int __init h4300_kbd_init(void)
+{
+	return platform_driver_register(&h4300_kbd_driver);
+}
+
+static void __exit h4300_kbd_exit(void)
+{
+	platform_driver_unregister(&h4300_kbd_driver);
+}
+
+module_init(h4300_kbd_init);
+module_exit(h4300_kbd_exit);
+

