--- Begin Message ---
Author: laforge
Date: 2007-06-19 13:20:16 +0200 (Tue, 19 Jun 2007)
New Revision: 2302
Modified:
trunk/src/target/u-boot/patches/uboot-gta02.patch
Log:
GTA02:
* add pcf50633 rtc driver
* enable pcf50633 rtc driver rather than s3c2440 one
* add power-cycling code for glamo
* major smedia driver update
* keep glamo driver disabled since it still locks up bus on vram access
Modified: trunk/src/target/u-boot/patches/uboot-gta02.patch
===================================================================
--- trunk/src/target/u-boot/patches/uboot-gta02.patch 2007-06-19 11:15:28 UTC
(rev 2301)
+++ trunk/src/target/u-boot/patches/uboot-gta02.patch 2007-06-19 11:20:16 UTC
(rev 2302)
@@ -88,7 +88,7 @@
===================================================================
--- /dev/null
+++ u-boot/board/neo1973/gta02/gta02.c
-@@ -0,0 +1,313 @@
+@@ -0,0 +1,323 @@
+/*
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Author: Harald Welte <[EMAIL PROTECTED]>
@@ -135,7 +135,8 @@
+/* That many seconds the power key needs to be pressed to power up */
+#define POWER_KEY_SECONDS 2
+
-+#define M_MDIV 0x7f /* Fout = 405.00MHz */
++//#define M_MDIV 0x7f /* Fout = 405.00MHz */
++#define M_MDIV 0x7d /* Fout = 399.00MHz */
+#define M_PDIV 0x2
+#define M_SDIV 0x1
+
@@ -222,6 +223,7 @@
+
+int board_late_init(void)
+{
++ S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+ extern unsigned char booted_from_nand;
+ unsigned char tmp;
+ char buf[32];
@@ -230,6 +232,14 @@
+
+ /* Initialize the Power Management Unit with a safe register set */
+ pcf50633_init();
++
++ /* Glamo3362 reset and power cycle */
++ gpio->GPJDAT &= ~0x000000001;
++ pcf50633_reg_write(PCF50633_REG_DOWN2ENA, 0);
++ udelay(50*1000);
++ pcf50633_reg_write(PCF50633_REG_DOWN2ENA, 0x2);
++ gpio->GPJDAT |= 0x000000001;
++
+#if 0
+ /* if there's no other reason, must be regular reset */
+ neo1973_wakeup_cause = NEO1973_WAKEUP_RESET;
@@ -469,7 +479,7 @@
===================================================================
--- /dev/null
+++ u-boot/include/configs/neo1973_gta02.h
-@@ -0,0 +1,276 @@
+@@ -0,0 +1,272 @@
+/*
+ * (C) Copyright 2007 OpenMoko, Inc.
+ * Author: Harald Welte <[EMAIL PROTECTED]>
@@ -536,11 +546,6 @@
+ */
+#define CONFIG_SERIAL3 1 /* we use SERIAL 1 on GTA01 */
+
-+/************************************************************
-+ * RTC
-+ ************************************************************/
-+#define CONFIG_RTC_S3C24X0 1
-+
+/* allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+
@@ -719,7 +724,7 @@
+
+#if 0
+#define CONFIG_VIDEO
-+#define CONFIG_VIDEO_S3C2410
++#define CONFIG_VIDEO_GLAMO3362
+#define CONFIG_CFB_CONSOLE
+#define CONFIG_VIDEO_LOGO
+#define CONFIG_SPLASH_SCREEN
@@ -732,13 +737,14 @@
+#define VIDEO_TSTC_FCT serial_tstc
+#define VIDEO_GETC_FCT serial_getc
+
-+#define LCD_VIDEO_ADDR 0x33d00000
++#define CONFIG_GLAMO_BASE 0x08000000
+#endif
+
+#define CONFIG_S3C2410_NAND_BBT 1
+//#define CONFIG_S3C2410_NAND_HWECC 1
+
+#define CONFIG_DRIVER_PCF50633 1
++#define CONFIG_RTC_PCF50633 1
+
+#define MTDIDS_DEFAULT "nand0=neo1973-nand"
+#define MTPARTS_DEFAULT
"neo1973-nand:256k(u-boot),128k(u-boot_env),2M(kernel),640k(splash),-(jffs2)"
@@ -1032,7 +1038,7 @@
===================================================================
--- /dev/null
+++ u-boot/drivers/pcf50633.c
-@@ -0,0 +1,142 @@
+@@ -0,0 +1,192 @@
+#include <common.h>
+
+#ifdef CONFIG_DRIVER_PCF50633
@@ -1174,6 +1180,56 @@
+ return pcf50633_reg_set_bit_mask(PCF50633_REG_MBCC7, 0x03, val);
+}
+
++#if defined(CONFIG_RTC_PCF50633) && (CONFIG_COMMANDS & CFG_CMD_DATE)
++
++#include <rtc.h>
++
++static unsigned bcd2bin (uchar n)
++{
++ return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
++}
++
++static unsigned char bin2bcd (unsigned int n)
++{
++ return (((n / 10) << 4) | (n % 10));
++}
++
++
++void rtc_get(struct rtc_time *tmp)
++{
++ tmp->tm_sec = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCSC));
++ tmp->tm_min = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCMN));
++ tmp->tm_hour = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCHR));
++ tmp->tm_wday = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCWD));
++ tmp->tm_mday = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCDT));
++ tmp->tm_mon = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCMT));
++ tmp->tm_year = bcd2bin(pcf50633_reg_read(PCF50633_REG_RTCYR));
++ if (tmp->tm_year < 70)
++ tmp->tm_year += 2000;
++ else
++ tmp->tm_year += 1900;
++ tmp->tm_yday = 0;
++ tmp->tm_isdst = 0;
++}
++
++void rtc_set(struct rtc_time *tmp)
++{
++ pcf50633_reg_write(PCF50633_REG_RTCSC, bin2bcd(tmp->tm_sec));
++ pcf50633_reg_write(PCF50633_REG_RTCMN, bin2bcd(tmp->tm_min));
++ pcf50633_reg_write(PCF50633_REG_RTCHR, bin2bcd(tmp->tm_hour));
++ pcf50633_reg_write(PCF50633_REG_RTCWD, bin2bcd(tmp->tm_wday));
++ pcf50633_reg_write(PCF50633_REG_RTCDT, bin2bcd(tmp->tm_mday));
++ pcf50633_reg_write(PCF50633_REG_RTCMN, bin2bcd(tmp->tm_mon));
++ pcf50633_reg_write(PCF50633_REG_RTCYR, bin2bcd(tmp->tm_year % 100));
++}
++
++void rtc_reset(void)
++{
++ /* FIXME */
++}
++#endif /* CONFIG_RTC_PCF50633 && CFG_CMD_DATE */
++
++
+#endif /* CONFIG DRIVER_PCF50633 */
Index: u-boot/board/neo1973/common/lowlevel_init.S
===================================================================
@@ -1366,7 +1422,7 @@
===================================================================
--- /dev/null
+++ u-boot/drivers/smedia3362.c
-@@ -0,0 +1,125 @@
+@@ -0,0 +1,188 @@
+/*
+ * (C) Copyright 2007 by OpenMoko, Inc.
+ * Author: Harald Welte <[EMAIL PROTECTED]>
@@ -1396,16 +1452,27 @@
+#include <s3c2410.h>
+#include "smedia3362.h"
+
-+/*
-+ * Export Graphic Device
-+ */
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++/* Export Graphic Device */
+GraphicDevice smi;
+
++#define GLAMO_REG(x) (*(volatile unsigned short *)(CONFIG_GLAMO_BASE + x))
+
++static inline void glamo_reg_write(u_int16_t reg, u_int16_t val)
++{
++ GLAMO_REG(reg) = val;
++}
++
++static inline u_int16_t glamo_reg_read(u_int16_t reg)
++{
++ return GLAMO_REG(reg);
++}
++
+struct glamo_script {
+ u_int16_t reg;
+ u_int16_t val;
-+} __attribute__((packed));
++}; // __attribute__((packed));
+
+/* from 'initial glamo 3365 script' */
+static struct glamo_script gl3362_init_script[] = {
@@ -1423,7 +1490,7 @@
+ { GLAMO_REG_CLOCK_MPROC, 0x12aa },
+ { 0xfffe, 5 },
+ { GLAMO_REG_CLOCK_HOST, 0x000d },
-+ { GLAMO_REG_CLOCK_MEMORY, 0x000a }I,
++ { GLAMO_REG_CLOCK_MEMORY, 0x000a },
+ { GLAMO_REG_CLOCK_LCD, 0x00ee },
+ { GLAMO_REG_CLOCK_MMC, 0x000a },
+ { GLAMO_REG_CLOCK_ISP, 0x02aa },
@@ -1469,34 +1536,86 @@
+ { GLAMO_REG_MEM_TIMING(10), 0x00ff },
+ { GLAMO_REG_MEM_TIMING(11), 0x0001 },
+ { GLAMO_REG_MEM_POWER1, 0x0020 },
-+ { GLAMO_REG_MEM_POWRE2, 0x0000 },
++ { GLAMO_REG_MEM_POWER2, 0x0000 },
+ { GLAMO_REG_MEM_DRAM1, 0x0000 },
+ { 0xfffe, 1 },
+ { GLAMO_REG_MEM_DRAM1, 0xc100 },
+ { GLAMO_REG_MEM_DRAM2, 0x01d6 },
+};
+
-+static int glamo3362_init(void)
++#if 0
++static struct glamo_script gl3362_init_script[] = {
++ /* clock */
++ { GLAMO_REG_CLOCK_MEMORY, 0x300a },
++};
++#endif
++
++static void glamo_run_script(struct glamo_script *script, int num)
+{
+ int i;
-+
+ for (i = 0; i < ARRAY_SIZE(gl3362_init_script); i++) {
-+ struct glamo_reg *reg = gl3362_init_script[i];
++ struct glamo_script *reg = script + i;
++ printf("reg=0x%04x, val=0x%04x\n", reg->reg, reg->val);
+
+ if (reg->reg == 0xfffe)
-+ delay(reg->val);
++ udelay(reg->val*1000);
+ else
-+ gl3362_reg_write(reg->reg, reg->val);
++ glamo_reg_write(reg->reg, reg->val);
+ }
-+ /* FIXME */
++
+}
+
++static void glamo_core_init(void)
++{
++ printf("Glamo core device ID: 0x%04x, Revision 0x%04x\n",
++ glamo_reg_read(GLAMO_REG_DEVICE_ID),
++ glamo_reg_read(GLAMO_REG_REVISION_ID));
++
++ glamo_run_script(gl3362_init_script, ARRAY_SIZE(gl3362_init_script));
++}
++
++void *video_hw_init(void)
++{
++ u_int16_t reg;
++ GraphicDevice *pGD = (GraphicDevice *)&smi;
++
++ glamo_core_init();
++
++ printf("Video: ");
++
++ /* FIXME: returning since vram access still locks up system */
++ return NULL;
++
++ /* FIXME: this is static */
++ pGD->winSizeX = pGD->plnSizeX = 480;
++ pGD->winSizeY = pGD->plnSizeY = 640;
++ pGD->gdfBytesPP = 2;
++ pGD->gdfIndex = GDF_16BIT_565RGB;
++
++ pGD->frameAdrs = CONFIG_GLAMO_BASE + 0x00800000;
++ pGD->memSize = 0x200000; /* 480x640x16bit = 614400 bytes */
++
++ //printf("memset ");
++ //memset(pGD->frameAdrs, 0, pGD->memSize);
++
++ printf("END\n");
++
++ return &smi;
++}
++
++void
++video_set_lut(unsigned int index, unsigned char r,
++ unsigned char g, unsigned char b)
++{
++ /* FIXME: we don't support any palletized formats */
++}
++
+#endif /* CONFIG_VIDEO_GLAMO3362 */
Index: u-boot/drivers/Makefile
===================================================================
--- u-boot.orig/drivers/Makefile
+++ u-boot/drivers/Makefile
-@@ -50,7 +50,7 @@
+@@ -50,10 +50,10 @@
usbdcore.o usbdfu.o usbdcore_ep0.o usbdcore_omap1510.o
usbdcore_s3c2410.o usbtty.o \
videomodes.o w83c553f.o \
ks8695eth.o \
@@ -1504,7 +1623,11 @@
+ pcf50606.o pcf50633.o \
pxa_pcmcia.o mpc8xx_pcmcia.o tqm8xx_pcmcia.o \
rpx_pcmcia.o \
- fsl_i2c.o s3c2410_fb.o
+- fsl_i2c.o s3c2410_fb.o
++ fsl_i2c.o s3c2410_fb.o smedia3362.o
+
+ SRCS := $(COBJS:.o=.c)
+ OBJS := $(addprefix $(obj),$(COBJS))
Index: u-boot/common/cmd_nand.c
===================================================================
--- u-boot.orig/common/cmd_nand.c
@@ -1546,7 +1669,17 @@
void udc_ctrl(enum usbd_event event, int param)
{
-@@ -23,6 +24,11 @@
+@@ -11,7 +12,8 @@
+ switch (event) {
+ case UDC_CTRL_PULLUP_ENABLE:
+ #if defined(CONFIG_ARCH_GTA01_v4) || defined(CONFIG_ARCH_GTA01B_v2) || \
+- defined(CONFIG_ARCH_GTA01B_v3) || defined(CONFIG_ARCH_GTA01B_v4)
++ defined(CONFIG_ARCH_GTA01B_v3) || defined(CONFIG_ARCH_GTA01B_v4) || \
++ defined(CONFIG_ARCH_GTA02_v1)
+ if (param)
+ gpio->GPBDAT |= (1 << 9);
+ else
+@@ -23,6 +25,11 @@
defined(CONFIG_ARCH_GTA01B_v2) || defined(CONFIG_ARCH_GTA01B_v3) || \
defined(CONFIG_ARCH_GTA01B_v4)
pcf50606_charge_autofast(param);
@@ -1558,3 +1691,393 @@
#endif
break;
default:
+Index: u-boot/drivers/smedia3362.h
+===================================================================
+--- /dev/null
++++ u-boot/drivers/smedia3362.h
+@@ -0,0 +1,385 @@
++#ifndef _GLAMO_REGS_H
++#define _GLAMO_REGS_H
++
++/* Smedia Glamo 336x/337x driver
++ *
++ * (C) 2007 by OpenMoko, Inc.
++ * Author: Harald Welte <[EMAIL PROTECTED]>
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++enum glamo_regster_offsets {
++ GLAMO_REGOFS_GENERIC = 0x0000,
++ GLAMO_REGOFS_HOSTBUS = 0x0200,
++ GLAMO_REGOFS_MEMORY = 0x0300,
++ GLAMO_REGOFS_VIDCAP = 0x0400,
++ GLAMO_REGOFS_ISP = 0x0500,
++ GLAMO_REGOFS_JPEG = 0x0800,
++ GLAMO_REGOFS_MPEG = 0x0c00,
++ GLAMO_REGOFS_LCD = 0x1100,
++ GLAMO_REGOFS_MMC = 0x1400,
++ GLAMO_REGOFS_MPROC0 = 0x1500,
++ GLAMO_REGOFS_MPROC1 = 0x1580,
++ GLAMO_REGOFS_CMDQUEUE = 0x1600,
++ GLAMO_REGOFS_RISC = 0x1680,
++ GLAMO_REGOFS_2D = 0x1700,
++ GLAMO_REGOFS_3D = 0x1b00,
++};
++
++
++enum glamo_register_generic {
++ GLAMO_REG_GCONF1 = 0x0000,
++ GLAMO_REG_GCONF2 = 0x0002,
++#define GLAMO_REG_DEVICE_ID GLAMO_REG_GCONF2
++ GLAMO_REG_GCONF3 = 0x0004,
++#define GLAMO_REG_REVISION_ID GLAMO_REG_GCONF3
++ GLAMO_REG_IRQ_GEN1 = 0x0006,
++#define GLAMO_REG_IRQ_ENABLE GLAMO_REG_IRQ_GEN1
++ GLAMO_REG_IRQ_GEN2 = 0x0008,
++#define GLAMO_REG_IRQ_SET GLAMO_REG_IRQ_GEN2
++ GLAMO_REG_IRQ_GEN3 = 0x000a,
++#define GLAMO_REG_IRQ_CLEAR GLAMO_REG_IRQ_GEN3
++ GLAMO_REG_IRQ_GEN4 = 0x000c,
++#define GLAMO_REG_IRQ_STATUS GLAMO_REG_IRQ_GEN4
++ GLAMO_REG_CLOCK_HOST = 0x0010,
++ GLAMO_REG_CLOCK_MEMORY = 0x0012,
++ GLAMO_REG_CLOCK_LCD = 0x0014,
++ GLAMO_REG_CLOCK_MMC = 0x0016,
++ GLAMO_REG_CLOCK_ISP = 0x0018,
++ GLAMO_REG_CLOCK_JPEG = 0x001a,
++ GLAMO_REG_CLOCK_3D = 0x001c,
++ GLAMO_REG_CLOCK_2D = 0x001e,
++ GLAMO_REG_CLOCK_RISC1 = 0x0020, /* 3365 only? */
++ GLAMO_REG_CLOCK_RISC2 = 0x0022, /* 3365 only? */
++ GLAMO_REG_CLOCK_MPEG = 0x0024,
++ GLAMO_REG_CLOCK_MPROC = 0x0026,
++
++ GLAMO_REG_CLOCK_GEN5_1 = 0x0030,
++ GLAMO_REG_CLOCK_GEN5_2 = 0x0032,
++ GLAMO_REG_CLOCK_GEN6 = 0x0034,
++ GLAMO_REG_CLOCK_GEN7 = 0x0036,
++ GLAMO_REG_CLOCK_GEN8 = 0x0038,
++ GLAMO_REG_CLOCK_GEN9 = 0x003a,
++ GLAMO_REG_CLOCK_GEN10 = 0x003c,
++ GLAMO_REG_CLOCK_GEN11 = 0x003e,
++ GLAMO_REG_PLL_GEN1 = 0x0040,
++ GLAMO_REG_PLL_GEN2 = 0x0042,
++ GLAMO_REG_PLL_GEN3 = 0x0044,
++ GLAMO_REG_PLL_GEN4 = 0x0046,
++ GLAMO_REG_PLL_GEN5 = 0x0048,
++ GLAMO_REG_GPIO_GEN1 = 0x0050,
++ GLAMO_REG_GPIO_GEN2 = 0x0052,
++ GLAMO_REG_GPIO_GEN3 = 0x0054,
++ GLAMO_REG_GPIO_GEN4 = 0x0056,
++ GLAMO_REG_GPIO_GEN5 = 0x0058,
++ GLAMO_REG_GPIO_GEN6 = 0x005a,
++ GLAMO_REG_GPIO_GEN7 = 0x005c,
++ GLAMO_REG_GPIO_GEN8 = 0x005e,
++ GLAMO_REG_GPIO_GEN9 = 0x0060,
++ GLAMO_REG_GPIO_GEN10 = 0x0062,
++ GLAMO_REG_DFT_GEN1 = 0x0070,
++ GLAMO_REG_DFT_GEN2 = 0x0072,
++ GLAMO_REG_DFT_GEN3 = 0x0074,
++ GLAMO_REG_DFT_GEN4 = 0x0076,
++
++ GLAMO_REG_PLL_GEN6 = 0x01e0,
++ GLAMO_REG_PLL_GEN7 = 0x01f0,
++};
++
++#define GLAMO_REG_HOSTBUS(x) (GLAMO_REGOFS_HOSTBUS-2+(x*2))
++
++#define REG_MEM(x) (GLAMO_REGOFS_MEMORY+(x))
++#define GLAMO_REG_MEM_TIMING(x) (GLAMO_REG_MEM_TIMING1-2+(x*2))
++
++enum glamo_register_mem {
++ GLAMO_REG_MEM_TYPE = REG_MEM(0x00),
++ GLAMO_REG_MEM_GEN = REG_MEM(0x02),
++ GLAMO_REG_MEM_TIMING1 = REG_MEM(0x04),
++ GLAMO_REG_MEM_TIMING2 = REG_MEM(0x06),
++ GLAMO_REG_MEM_TIMING3 = REG_MEM(0x08),
++ GLAMO_REG_MEM_TIMING4 = REG_MEM(0x0a),
++ GLAMO_REG_MEM_TIMING5 = REG_MEM(0x0c),
++ GLAMO_REG_MEM_TIMING6 = REG_MEM(0x0e),
++ GLAMO_REG_MEM_TIMING7 = REG_MEM(0x10),
++ GLAMO_REG_MEM_TIMING8 = REG_MEM(0x12),
++ GLAMO_REG_MEM_TIMING9 = REG_MEM(0x14),
++ GLAMO_REG_MEM_TIMING10 = REG_MEM(0x16),
++ GLAMO_REG_MEM_TIMING11 = REG_MEM(0x18),
++ GLAMO_REG_MEM_POWER1 = REG_MEM(0x1a),
++ GLAMO_REG_MEM_POWER2 = REG_MEM(0x1c),
++ GLAMO_REG_MEM_LCD_BUF1 = REG_MEM(0x1e),
++ GLAMO_REG_MEM_LCD_BUF2 = REG_MEM(0x20),
++ GLAMO_REG_MEM_LCD_BUF3 = REG_MEM(0x22),
++ GLAMO_REG_MEM_LCD_BUF4 = REG_MEM(0x24),
++ GLAMO_REG_MEM_BIST1 = REG_MEM(0x26),
++ GLAMO_REG_MEM_BIST2 = REG_MEM(0x28),
++ GLAMO_REG_MEM_BIST3 = REG_MEM(0x2a),
++ GLAMO_REG_MEM_BIST4 = REG_MEM(0x2c),
++ GLAMO_REG_MEM_BIST5 = REG_MEM(0x2e),
++ GLAMO_REG_MEM_MAH1 = REG_MEM(0x30),
++ GLAMO_REG_MEM_MAH2 = REG_MEM(0x32),
++ GLAMO_REG_MEM_DRAM1 = REG_MEM(0x34),
++ GLAMO_REG_MEM_DRAM2 = REG_MEM(0x36),
++ GLAMO_REG_MEM_CRC = REG_MEM(0x38),
++};
++
++enum glamo_irq {
++ GLAMO_IRQ_HOSTBUS = 0x0001,
++ GLAMO_IRQ_JPEG = 0x0002,
++ GLAMO_IRQ_MPEG = 0x0004,
++ GLAMO_IRQ_MPROC1 = 0x0008,
++ GLAMO_IRQ_MPROC0 = 0x0010,
++ GLAMO_IRQ_CMDQUEUE = 0x0020,
++ GLAMO_IRQ_2D = 0x0040,
++ GLAMO_IRQ_MMC = 0x0080,
++ GLAMO_IRQ_RISC = 0x0100,
++};
++
++enum glamo_reg_clock_host {
++ GLAMO_CLOCK_HOST_DG_BCLK = 0x0001,
++ GLAMO_CLOCK_HOST_DG_M0CLK = 0x0004,
++ GLAMO_CLOCK_HOST_RESET = 0x1000,
++};
++
++enum glamo_reg_clock_mem {
++ GLAMO_CLOCK_MEM_DG_M1CLK = 0x0001,
++ GLAMO_CLOCK_MEM_EN_M1CLK = 0x0002,
++ GLAMO_CLOCK_MEM_DG_MOCACLK = 0x0004,
++ GLAMO_CLOCK_MEM_EN_MOCACLK = 0x0008,
++ GLAMO_CLOCK_MEM_RESET = 0x1000,
++ GLAMO_CLOCK_MOCA_RESET = 0x2000,
++};
++
++enum glamo_reg_clock_lcd {
++ GLAMO_CLOCK_LCD_DG_DCLK = 0x0001,
++ GLAMO_CLOCK_LCD_EN_DCLK = 0x0002,
++ GLAMO_CLOCK_LCD_DG_DMCLK = 0x0004,
++ GLAMO_CLOCK_LCD_EN_DMCLK = 0x0008,
++ //
++ GLAMO_CLOCK_LCD_EN_DHCLK = 0x0020,
++ GLAMO_CLOCK_LCD_DG_M5CLK = 0x0040,
++ GLAMO_CLOCK_LCD_EN_M5CLK = 0x0080,
++ GLAMO_CLOCK_LCD_RESET = 0x1000,
++};
++
++enum glamo_reg_clock_mmc {
++ GLAMO_CLOCK_MMC_DG_TCLK = 0x0001,
++ GLAMO_CLOCK_MMC_EN_TCLK = 0x0002,
++ GLAMO_CLOCK_MMC_DG_M9CLK = 0x0004,
++ GLAMO_CLOCK_MMC_EN_M9CLK = 0x0008,
++ GLAMO_CLOCK_MMC_RESET = 0x1000,
++};
++
++enum glamo_reg_clock_isp {
++ GLAMO_CLOCK_ISP_DG_I1CLK = 0x0001,
++ GLAMO_CLOCK_ISP_EN_I1CLK = 0x0002,
++ GLAMO_CLOCK_ISP_DG_CCLK = 0x0004,
++ GLAMO_CLOCK_ISP_EN_CCLK = 0x0008,
++ //
++ GLAMO_CLOCK_ISP_EN_SCLK = 0x0020,
++ GLAMO_CLOCK_ISP_DG_M2CLK = 0x0040,
++ GLAMO_CLOCK_ISP_EN_M2CLK = 0x0080,
++ GLAMO_CLOCK_ISP_DG_M15CLK = 0x0100,
++ GLAMO_CLOCK_ISP_EN_M15CLK = 0x0200,
++ GLAMO_CLOCK_ISP1_RESET = 0x1000,
++ GLAMO_CLOCK_ISP2_RESET = 0x2000,
++};
++
++enum glamo_reg_clock_jpeg {
++ GLAMO_CLOCK_JPEG_DG_JCLK = 0x0001,
++ GLAMO_CLOCK_JPEG_EN_JCLK = 0x0002,
++ GLAMO_CLOCK_JPEG_DG_M3CLK = 0x0004,
++ GLAMO_CLOCK_JPEG_EN_M3CLK = 0x0008,
++ GLAMO_CLOCK_JPEG_RESET = 0x1000,
++};
++
++enum glamo_reg_clock_3d {
++ GLAMO_CLOCK_3D_DG_GCLK = 0x0001,
++ GLAMO_CLOCK_3D_EN_GCLK = 0x0002,
++ GLAMO_CLOCK_3D_DG_M7CLK = 0x0004,
++ GLAMO_CLOCK_3D_EN_M7CLK = 0x0008,
++ GLAMO_CLOCK_3D_DG_M6CLK = 0x0010,
++ GLAMO_CLOCK_3D_EN_M6CLK = 0x0020,
++ GLAMO_CLOCK_3D_2D_RESET = 0x1000,
++ GLAMO_CLOCK_3D_CQ_RESET = 0x2000,
++};
++
++enum glamo_reg_clock_mpeg {
++ GLAMO_CLOCK_MPEG_DG_X0CLK = 0x0001,
++ GLAMO_CLOCK_MPEG_EN_X0CLK = 0x0002,
++ GLAMO_CLOCK_MPEG_DG_X1CLK = 0x0004,
++ GLAMO_CLOCK_MPEG_EN_X1CLK = 0x0008,
++ GLAMO_CLOCK_MPEG_DG_X2CLK = 0x0010,
++ GLAMO_CLOCK_MPEG_EN_X2CLK = 0x0020,
++ GLAMO_CLOCK_MPEG_DG_X3CLK = 0x0040,
++ GLAMO_CLOCK_MPEG_EN_X3CLK = 0x0080,
++ GLAMO_CLOCK_MPEG_DG_X4CLK = 0x0100,
++ GLAMO_CLOCK_MPEG_EN_X4CLK = 0x0200,
++ GLAMO_CLOCK_MPEG_DG_X6CLK = 0x0400,
++ GLAMO_CLOCK_MPEG_EN_X6CLK = 0x0800,
++ GLAMO_CLOCK_MPEG_ENC_RESET = 0x1000,
++ GLAMO_CLOCK_MPEG_DEC_RESET = 0x2000,
++};
++
++/* LCD Controller */
++
++#define REG_LCD(x) (x)
++enum glamo_reg_lcd {
++ GLAMO_REG_LCD_MODE1 = REG_LCD(0x00),
++ GLAMO_REG_LCD_MODE2 = REG_LCD(0x02),
++ GLAMO_REG_LCD_MODE3 = REG_LCD(0x04),
++ GLAMO_REG_LCD_WIDTH = REG_LCD(0x06),
++ GLAMO_REG_LCD_HEIGHT = REG_LCD(0x08),
++ GLAMO_REG_LCD_POLARITY = REG_LCD(0x0a),
++ GLAMO_REG_LCD_A_BASE1 = REG_LCD(0x0c),
++ GLAMO_REG_LCD_A_BASE2 = REG_LCD(0x0e),
++ GLAMO_REG_LCD_B_BASE1 = REG_LCD(0x10),
++ GLAMO_REG_LCD_B_BASE2 = REG_LCD(0x12),
++ GLAMO_REG_LCD_C_BASE1 = REG_LCD(0x14),
++ GLAMO_REG_LCD_C_BASE2 = REG_LCD(0x16),
++ GLAMO_REG_LCD_PITCH = REG_LCD(0x18),
++ /* RES */
++ GLAMO_REG_LCD_HORIZ_TOTAL = REG_LCD(0x1c),
++ /* RES */
++ GLAMO_REG_LCD_HORIZ_RETR_START = REG_LCD(0x20),
++ /* RES */
++ GLAMO_REG_LCD_HORIZ_RETR_END = REG_LCD(0x24),
++ /* RES */
++ GLAMO_REG_LCD_HORIZ_DISP_START = REG_LCD(0x28),
++ /* RES */
++ GLAMO_REG_LCD_HORIZ_DISP_END = REG_LCD(0x2c),
++ /* RES */
++ GLAMO_REG_LCD_VERT_TOTAL = REG_LCD(0x30),
++ /* RES */
++ GLAMO_REG_LCD_VERT_RETR_START = REG_LCD(0x34),
++ /* RES */
++ GLAMO_REG_LCD_VERT_RETR_END = REG_LCD(0x38),
++ /* RES */
++ GLAMO_REG_LCD_VERT_DISP_START = REG_LCD(0x3c),
++ /* RES */
++ GLAMO_REG_LCD_VERT_DISP_END = REG_LCD(0x40),
++ /* RES */
++ GLAMO_REG_LCD_POL = REG_LCD(0x44),
++ GLAMO_REG_LCD_DATA_START = REG_LCD(0x46),
++ GLAMO_REG_LCD_FRATE_CONTRO = REG_LCD(0x48),
++ GLAMO_REG_LCD_DATA_CMD_HDR = REG_LCD(0x4a),
++ GLAMO_REG_LCD_SP_START = REG_LCD(0x4c),
++ GLAMO_REG_LCD_SP_END = REG_LCD(0x4e),
++ GLAMO_REG_LCD_CURSOR_BASE1 = REG_LCD(0x50),
++ GLAMO_REG_LCD_CURSOR_BASE2 = REG_LCD(0x52),
++ GLAMO_REG_LCD_CURSOR_PITCH = REG_LCD(0x54),
++ GLAMO_REG_LCD_CURSOR_X_SIZE = REG_LCD(0x56),
++ GLAMO_REG_LCD_CURSOR_Y_SIZE = REG_LCD(0x58),
++ GLAMO_REG_LCD_CURSOR_X_POS = REG_LCD(0x5a),
++ GLAMO_REG_LCD_CURSOR_Y_POS = REG_LCD(0x5c),
++ GLAMO_REG_LCD_CURSOR_PRESET = REG_LCD(0x5e),
++ GLAMO_REG_LCD_CURSOR_FG_COLOR = REG_LCD(0x60),
++ /* RES */
++ GLAMO_REG_LCD_CURSOR_BG_COLOR = REG_LCD(0x64),
++ /* RES */
++ GLAMO_REG_LCD_CURSOR_DST_COLOR = REG_LCD(0x68),
++ /* RES */
++ GLAMO_REG_LCD_STATUS1 = REG_LCD(0x80),
++ GLAMO_REG_LCD_STATUS2 = REG_LCD(0x82),
++ GLAMO_REG_LCD_STATUS3 = REG_LCD(0x84),
++ GLAMO_REG_LCD_STATUS4 = REG_LCD(0x86),
++ /* RES */
++ GLAMO_REG_LCD_COMMAND1 = REG_LCD(0xa0),
++ GLAMO_REG_LCD_COMMAND2 = REG_LCD(0xa2),
++ /* RES */
++ GLAMO_REG_LCD_WFORM_DELAY1 = REG_LCD(0xb0),
++ GLAMO_REG_LCD_WFORM_DELAY2 = REG_LCD(0xb2),
++ /* RES */
++ GLAMO_REG_LCD_GAMMA_CORR = REG_LCD(0x100),
++ /* RES */
++ GLAMO_REG_LCD_GAMMA_R_ENTRY01 = REG_LCD(0x110),
++ GLAMO_REG_LCD_GAMMA_R_ENTRY23 = REG_LCD(0x112),
++ GLAMO_REG_LCD_GAMMA_R_ENTRY45 = REG_LCD(0x114),
++ GLAMO_REG_LCD_GAMMA_R_ENTRY67 = REG_LCD(0x116),
++ GLAMO_REG_LCD_GAMMA_R_ENTRY8 = REG_LCD(0x118),
++ /* RES */
++ GLAMO_REG_LCD_GAMMA_G_ENTRY01 = REG_LCD(0x130),
++ GLAMO_REG_LCD_GAMMA_G_ENTRY23 = REG_LCD(0x132),
++ GLAMO_REG_LCD_GAMMA_G_ENTRY45 = REG_LCD(0x134),
++ GLAMO_REG_LCD_GAMMA_G_ENTRY67 = REG_LCD(0x136),
++ GLAMO_REG_LCD_GAMMA_G_ENTRY8 = REG_LCD(0x138),
++ /* RES */
++ GLAMO_REG_LCD_GAMMA_B_ENTRY01 = REG_LCD(0x150),
++ GLAMO_REG_LCD_GAMMA_B_ENTRY23 = REG_LCD(0x152),
++ GLAMO_REG_LCD_GAMMA_B_ENTRY45 = REG_LCD(0x154),
++ GLAMO_REG_LCD_GAMMA_B_ENTRY67 = REG_LCD(0x156),
++ GLAMO_REG_LCD_GAMMA_B_ENTRY8 = REG_LCD(0x158),
++ /* RES */
++ GLAMO_REG_LCD_SRAM_DRIVING1 = REG_LCD(0x160),
++ GLAMO_REG_LCD_SRAM_DRIVING2 = REG_LCD(0x162),
++ GLAMO_REG_LCD_SRAM_DRIVING3 = REG_LCD(0x164),
++};
++
++enum glamo_reg_lcd_mode1 {
++ GLAMO_LCD_MODE1_PWRSAVE = 0x0001,
++ GLAMO_LCD_MODE1_PARTIAL_PRT = 0x0002,
++ GLAMO_LCD_MODE1_HWFLIP = 0x0004,
++ GLAMO_LCD_MODE1_LCD2 = 0x0008,
++ /* RES */
++ GLAMO_LCD_MODE1_PARTIAL_MODE = 0x0020,
++ GLAMO_LCD_MODE1_CURSOR_DSTCOLOR = 0x0040,
++ GLAMO_LCD_MODE1_PARTIAL_ENABLE = 0x0080,
++ GLAMO_LCD_MODE1_TVCLK_IN_ENABLE = 0x0100,
++ GLAMO_LCD_MODE1_HSYNC_HIGH_ACT = 0x0200,
++ GLAMO_LCD_MODE1_VSYNC_HIGH_ACT = 0x0400,
++ GLAMO_LCD_MODE1_HSYNC_FLIP = 0x0800,
++ GLAMO_LCD_MODE1_GAMMA_COR_EN = 0x1000,
++ GLAMO_LCD_MODE1_DITHER_EN = 0x2000,
++ GLAMO_LCD_MODE1_CURSOR_EN = 0x4000,
++ GLAMO_LCD_MODE1_ROTATE_EN = 0x8000,
++};
++
++enum glamo_reg_lcd_mode2 {
++ GLAMO_LCD_MODE2_CRC_CHECK_EN = 0x0001,
++ GLAMO_LCD_MODE2_DCMD_PER_LINE = 0x0002,
++ GLAMO_LCD_MODE2_NOUSE_BDEF = 0x0004,
++ GLAMO_LCD_MODE2_OUT_POS_MODE = 0x0008,
++ GLAMO_LCD_MODE2_FRATE_CTRL_EN = 0x0010,
++ GLAMO_LCD_MODE2_SINGLE_BUFFER = 0x0020,
++ GLAMO_LCD_MODE2_SER_LSB_TO_MSB = 0x0040,
++ /* FIXME */
++};
++
++enum glamo_reg_lcd_mode3 {
++ /* LCD color source data format */
++ GLAMO_LCD_SRC_RGB565 = 0x0000,
++ GLAMO_LCD_SRC_ARGB1555 = 0x4000,
++ GLAMO_LCD_SRC_ARGB4444 = 0x8000,
++ /* interface type */
++ GLAMO_LCD_MODE3_LCD = 0x1000,
++ GLAMO_LCD_MODE3_RGB = 0x0800,
++ GLAMO_LCD_MODE3_CPU = 0x0000,
++ /* mode */
++ GLAMO_LCD_MODE3_RGB332 = 0x0000,
++ GLAMO_LCD_MODE3_RGB444 = 0x0100,
++ GLAMO_LCD_MODE3_RGB565 = 0x0200,
++ GLAMO_LCD_MODE3_RGB666 = 0x0300,
++ /* depth */
++ GLAMO_LCD_MODE3_6BITS = 0x0000,
++ GLAMO_LCD_MODE3_8BITS = 0x0010,
++ GLAMO_LCD_MODE3_9BITS = 0x0020,
++ GLAMO_LCD_MODE3_16BITS = 0x0030,
++ GLAMO_LCD_MODE3_18BITS = 0x0040,
++};
++
++#endif /* _GLAMO_REGS_H */
--- End Message ---
--- Begin Message ---
Author: andrew
Date: 2007-06-19 15:16:05 +0200 (Tue, 19 Jun 2007)
New Revision: 2303
Modified:
trunk/src/host/qemu-neo1973/hw/usb-hid.c
trunk/src/host/qemu-neo1973/hw/usb.h
trunk/src/host/qemu-neo1973/vl.c
Log:
Emulate a USB HID keyboard.
Modified: trunk/src/host/qemu-neo1973/hw/usb-hid.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-hid.c 2007-06-19 11:20:16 UTC (rev
2302)
+++ trunk/src/host/qemu-neo1973/hw/usb-hid.c 2007-06-19 13:16:05 UTC (rev
2303)
@@ -2,6 +2,7 @@
* QEMU USB HID devices
*
* Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc. ([EMAIL PROTECTED])
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
deal
@@ -27,21 +28,39 @@
#define GET_REPORT 0xa101
#define GET_IDLE 0xa102
#define GET_PROTOCOL 0xa103
+#define SET_REPORT 0x2101
#define SET_IDLE 0x210a
#define SET_PROTOCOL 0x210b
-#define USB_MOUSE 1
-#define USB_TABLET 2
+#define USB_MOUSE 1
+#define USB_TABLET 2
+#define USB_KEYBOARD 3
typedef struct USBMouseState {
- USBDevice dev;
int dx, dy, dz, buttons_state;
int x, y;
- int kind;
int mouse_grabbed;
QEMUPutMouseEntry *eh_entry;
} USBMouseState;
+typedef struct USBKeyboardState {
+ uint16_t modifiers;
+ uint8_t leds;
+ uint8_t key[16];
+ int keys;
+} USBKeyboardState;
+
+typedef struct USBHIDState {
+ USBDevice dev;
+ union {
+ USBMouseState ptr;
+ USBKeyboardState kbd;
+ };
+ int kind;
+ int protocol;
+ int idle;
+} USBHIDState;
+
/* mostly the same values as the Bochs USB Mouse device */
static const uint8_t qemu_mouse_dev_descriptor[] = {
0x12, /* u8 bLength; */
@@ -173,6 +192,61 @@
0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
};
+static const uint8_t qemu_keyboard_config_descriptor[] = {
+ /* one configuration */
+ 0x09, /* u8 bLength; */
+ 0x02, /* u8 bDescriptorType; Configuration */
+ 0x22, 0x00, /* u16 wTotalLength; */
+ 0x01, /* u8 bNumInterfaces; (1) */
+ 0x01, /* u8 bConfigurationValue; */
+ 0x04, /* u8 iConfiguration; */
+ 0xa0, /* u8 bmAttributes;
+ Bit 7: must be set,
+ 6: Self-powered,
+ 5: Remote wakeup,
+ 4..0: resvd */
+ 0x32, /* u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* u8 if_bLength; */
+ 0x04, /* u8 if_bDescriptorType; Interface */
+ 0x00, /* u8 if_bInterfaceNumber; */
+ 0x00, /* u8 if_bAlternateSetting; */
+ 0x01, /* u8 if_bNumEndpoints; */
+ 0x03, /* u8 if_bInterfaceClass; HID */
+ 0x01, /* u8 if_bInterfaceSubClass; Boot */
+ 0x01, /* u8 if_bInterfaceProtocol; Keyboard */
+ 0x05, /* u8 if_iInterface; */
+
+ /* HID descriptor */
+ 0x09, /* u8 bLength; */
+ 0x21, /* u8 bDescriptorType; */
+ 0x01, 0x11, /* u16 HID_class */
+ 0x00, /* u8 country_code */
+ 0x01, /* u8 num_descriptors */
+ 0x22, /* u8 type; Report */
+ 0x3f, 0x00, /* u16 len */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* u8 ep_bLength; */
+ 0x05, /* u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* u8 ep_bmAttributes; Interrupt */
+ 0x08, 0x00, /* u16 ep_wMaxPacketSize; */
+ 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
static const uint8_t qemu_mouse_hid_report_descriptor[] = {
0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
@@ -223,6 +297,83 @@
0xC0, /* End Collection */
};
+static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
+ 0x05, 0x01, /* Usage Page (Generic Desktop) */
+ 0x09, 0x06, /* Usage (Keyboard) */
+ 0xa1, 0x01, /* Collection (Application) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x95, 0x08, /* Report Count (8) */
+ 0x05, 0x07, /* Usage Page (Key Codes) */
+ 0x19, 0xe0, /* Usage Minimum (224) */
+ 0x29, 0xe7, /* Usage Maximum (231) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x81, 0x02, /* Input (Data, Variable, Absolute) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x81, 0x01, /* Input (Constant) */
+ 0x95, 0x05, /* Report Count (5) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x05, 0x08, /* Usage Page (LEDs) */
+ 0x19, 0x01, /* Usage Minimum (1) */
+ 0x29, 0x05, /* Usage Maximum (5) */
+ 0x91, 0x02, /* Output (Data, Variable, Absolute) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x75, 0x03, /* Report Size (3) */
+ 0x91, 0x01, /* Output (Constant) */
+ 0x95, 0x06, /* Report Count (6) */
+ 0x75, 0x08, /* Report Size (8) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0xff, /* Logical Maximum (255) */
+ 0x05, 0x07, /* Usage Page (Key Codes) */
+ 0x19, 0x00, /* Usage Minimum (0) */
+ 0x29, 0xff, /* Usage Maximum (255) */
+ 0x81, 0x00, /* Input (Data, Array) */
+ 0xc0, /* End Collection */
+};
+
+#define USB_HID_USAGE_ERROR_ROLLOVER 0x01
+#define USB_HID_USAGE_POSTFAIL 0x02
+#define USB_HID_USAGE_ERROR_UNDEFINED 0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
+static const uint8_t usb_hid_usage_keys[0x100] = {
+ 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+ 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+ 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+ 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+ 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+ 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+ 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+ 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+ 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+ 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+ 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+ 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+ 0x52, 0x4b, 0x00, 0x50, 0x4f, 0x00, 0x00, 0x4d,
+ 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
static void usb_mouse_event(void *opaque,
int dx1, int dy1, int dz1, int buttons_state)
{
@@ -245,6 +396,54 @@
s->buttons_state = buttons_state;
}
+static void usb_keyboard_event(void *opaque, int keycode)
+{
+ USBKeyboardState *s = opaque;
+ uint8_t hid_code, key;
+ int i;
+
+ key = keycode & 0x7f;
+ hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
+ s->modifiers &= ~(1 << 8);
+
+ switch (hid_code) {
+ case 0x00:
+ return;
+
+ case 0xe0:
+ if (s->modifiers & (1 << 9)) {
+ s->modifiers ^= 3 << 8;
+ return;
+ }
+ case 0xe1 ... 0xe7:
+ if (keycode & (1 << 7)) {
+ s->modifiers &= ~(1 << (hid_code & 0x0f));
+ return;
+ }
+ case 0xe8 ... 0xef:
+ s->modifiers |= 1 << (hid_code & 0x0f);
+ return;
+
+ default:
+ if (keycode & (1 << 7)) {
+ s->keys --;
+ for (i = 0; i <= s->keys; i ++)
+ if (s->key[i] == hid_code) {
+ s->key[i] = s->key[s->keys];
+ s->key[s->keys] = 0x00;
+ return;
+ }
+ } else {
+ for (i = 0; i < s->keys; i ++)
+ if (s->key[i] == hid_code)
+ return;
+ if (s->keys < sizeof(s->key))
+ s->key[s->keys] = hid_code;
+ s->keys ++;
+ }
+ }
+}
+
static inline int int_clamp(int val, int vmin, int vmax)
{
if (val < vmin)
@@ -326,22 +525,58 @@
return l;
}
+static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
+{
+ if (len < 2)
+ return 0;
+
+ buf[0] = s->modifiers & 0xff;
+ buf[1] = 0;
+ if (s->keys > 6)
+ memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+ else
+ memcpy(buf + 2, s->key, MIN(8, len) - 2);
+
+ return MIN(8, len);
+}
+
+static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
+{
+ if (len > 0) {
+ /* 0x01: Num Lock LED
+ * 0x02: Caps Lock LED
+ * 0x04: Scroll Lock LED
+ * 0x08: Compose LED
+ * 0x10: Kana LED */
+ s->leds = buf[0];
+ }
+ return 0;
+}
+
static void usb_mouse_handle_reset(USBDevice *dev)
{
- USBMouseState *s = (USBMouseState *)dev;
+ USBHIDState *s = (USBHIDState *)dev;
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- s->x = 0;
- s->y = 0;
- s->buttons_state = 0;
+ s->ptr.dx = 0;
+ s->ptr.dy = 0;
+ s->ptr.dz = 0;
+ s->ptr.x = 0;
+ s->ptr.y = 0;
+ s->ptr.buttons_state = 0;
+ s->protocol = 1;
}
-static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
+static void usb_keyboard_handle_reset(USBDevice *dev)
+{
+ USBHIDState *s = (USBHIDState *)dev;
+
+ s->protocol = 1;
+}
+
+static int usb_hid_handle_control(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data)
{
- USBMouseState *s = (USBMouseState *)dev;
+ USBHIDState *s = (USBHIDState *)dev;
int ret = 0;
switch(request) {
@@ -387,7 +622,11 @@
memcpy(data, qemu_tablet_config_descriptor,
sizeof(qemu_tablet_config_descriptor));
ret = sizeof(qemu_tablet_config_descriptor);
- }
+ } else if (s->kind == USB_KEYBOARD) {
+ memcpy(data, qemu_keyboard_config_descriptor,
+ sizeof(qemu_keyboard_config_descriptor));
+ ret = sizeof(qemu_keyboard_config_descriptor);
+ }
break;
case USB_DT_STRING:
switch(value & 0xff) {
@@ -405,10 +644,7 @@
break;
case 2:
/* product description */
- if (s->kind == USB_MOUSE)
- ret = set_usb_string(data, "QEMU USB Mouse");
- else if (s->kind == USB_TABLET)
- ret = set_usb_string(data, "QEMU USB Tablet");
+ ret = set_usb_string(data, s->dev.devname);
break;
case 3:
/* vendor description */
@@ -454,19 +690,48 @@
memcpy(data, qemu_tablet_hid_report_descriptor,
sizeof(qemu_tablet_hid_report_descriptor));
ret = sizeof(qemu_tablet_hid_report_descriptor);
- }
- break;
+ } else if (s->kind == USB_KEYBOARD) {
+ memcpy(data, qemu_keyboard_hid_report_descriptor,
+ sizeof(qemu_keyboard_hid_report_descriptor));
+ ret = sizeof(qemu_keyboard_hid_report_descriptor);
+ }
+ break;
default:
goto fail;
}
break;
case GET_REPORT:
if (s->kind == USB_MOUSE)
- ret = usb_mouse_poll(s, data, length);
+ ret = usb_mouse_poll(&s->ptr, data, length);
else if (s->kind == USB_TABLET)
- ret = usb_tablet_poll(s, data, length);
+ ret = usb_tablet_poll(&s->ptr, data, length);
+ else if (s->kind == USB_KEYBOARD)
+ ret = usb_keyboard_poll(&s->kbd, data, length);
break;
+ case SET_REPORT:
+ if (s->kind == USB_KEYBOARD)
+ ret = usb_keyboard_write(&s->kbd, data, length);
+ else
+ goto fail;
+ break;
+ case GET_PROTOCOL:
+ if (s->kind != USB_KEYBOARD)
+ goto fail;
+ ret = 1;
+ data[0] = s->protocol;
+ break;
+ case SET_PROTOCOL:
+ if (s->kind != USB_KEYBOARD)
+ goto fail;
+ ret = 0;
+ s->protocol = value;
+ break;
+ case GET_IDLE:
+ ret = 1;
+ data[0] = s->idle;
+ break;
case SET_IDLE:
+ s->idle = value;
ret = 0;
break;
default:
@@ -477,18 +742,20 @@
return ret;
}
-static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
+static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
{
- USBMouseState *s = (USBMouseState *)dev;
+ USBHIDState *s = (USBHIDState *)dev;
int ret = 0;
switch(p->pid) {
case USB_TOKEN_IN:
if (p->devep == 1) {
- if (s->kind == USB_MOUSE)
- ret = usb_mouse_poll(s, p->data, p->len);
- else if (s->kind == USB_TABLET)
- ret = usb_tablet_poll(s, p->data, p->len);
+ if (s->kind == USB_MOUSE)
+ ret = usb_mouse_poll(&s->ptr, p->data, p->len);
+ else if (s->kind == USB_TABLET)
+ ret = usb_tablet_poll(&s->ptr, p->data, p->len);
+ else if (s->kind == USB_KEYBOARD)
+ ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
} else {
goto fail;
}
@@ -502,28 +769,30 @@
return ret;
}
-static void usb_mouse_handle_destroy(USBDevice *dev)
+static void usb_hid_handle_destroy(USBDevice *dev)
{
- USBMouseState *s = (USBMouseState *)dev;
+ USBHIDState *s = (USBHIDState *)dev;
- qemu_remove_mouse_event_handler(s->eh_entry);
+ if (!s->kind == USB_KEYBOARD)
+ qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+ /* TODO: else */
qemu_free(s);
}
USBDevice *usb_tablet_init(void)
{
- USBMouseState *s;
+ USBHIDState *s;
- s = qemu_mallocz(sizeof(USBMouseState));
+ s = qemu_mallocz(sizeof(USBHIDState));
if (!s)
return NULL;
s->dev.speed = USB_SPEED_FULL;
s->dev.handle_packet = usb_generic_handle_packet;
s->dev.handle_reset = usb_mouse_handle_reset;
- s->dev.handle_control = usb_mouse_handle_control;
- s->dev.handle_data = usb_mouse_handle_data;
- s->dev.handle_destroy = usb_mouse_handle_destroy;
+ s->dev.handle_control = usb_hid_handle_control;
+ s->dev.handle_data = usb_hid_handle_data;
+ s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_TABLET;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
@@ -533,21 +802,44 @@
USBDevice *usb_mouse_init(void)
{
- USBMouseState *s;
+ USBHIDState *s;
- s = qemu_mallocz(sizeof(USBMouseState));
+ s = qemu_mallocz(sizeof(USBHIDState));
if (!s)
return NULL;
s->dev.speed = USB_SPEED_FULL;
s->dev.handle_packet = usb_generic_handle_packet;
s->dev.handle_reset = usb_mouse_handle_reset;
- s->dev.handle_control = usb_mouse_handle_control;
- s->dev.handle_data = usb_mouse_handle_data;
- s->dev.handle_destroy = usb_mouse_handle_destroy;
+ s->dev.handle_control = usb_hid_handle_control;
+ s->dev.handle_data = usb_hid_handle_data;
+ s->dev.handle_destroy = usb_hid_handle_destroy;
s->kind = USB_MOUSE;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
return (USBDevice *)s;
}
+
+USBDevice *usb_keyboard_init(void)
+{
+ USBHIDState *s;
+
+ s = qemu_mallocz(sizeof(USBHIDState));
+ if (!s)
+ return NULL;
+ s->dev.speed = USB_SPEED_FULL;
+ s->dev.handle_packet = usb_generic_handle_packet;
+
+ s->dev.handle_reset = usb_keyboard_handle_reset;
+ s->dev.handle_control = usb_hid_handle_control;
+ s->dev.handle_data = usb_hid_handle_data;
+ s->dev.handle_destroy = usb_hid_handle_destroy;
+ s->kind = USB_KEYBOARD;
+
+ pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard");
+
+ qemu_add_kbd_event_handler(usb_keyboard_event, &s->kbd);
+
+ return (USBDevice *) s;
+}
Modified: trunk/src/host/qemu-neo1973/hw/usb.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb.h 2007-06-19 11:20:16 UTC (rev
2302)
+++ trunk/src/host/qemu-neo1973/hw/usb.h 2007-06-19 13:16:05 UTC (rev
2303)
@@ -223,6 +223,7 @@
/* usb-hid.c */
USBDevice *usb_mouse_init(void);
USBDevice *usb_tablet_init(void);
+USBDevice *usb_keyboard_init(void);
/* usb-msd.c */
USBDevice *usb_msd_init(const char *filename);
Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c 2007-06-19 11:20:16 UTC (rev 2302)
+++ trunk/src/host/qemu-neo1973/vl.c 2007-06-19 13:16:05 UTC (rev 2303)
@@ -4370,7 +4370,9 @@
} else if (!strcmp(devname, "mouse")) {
dev = usb_mouse_init();
} else if (!strcmp(devname, "tablet")) {
- dev = usb_tablet_init();
+ dev = usb_tablet_init();
+ } else if (!strcmp(devname, "keyboard")) {
+ dev = usb_keyboard_init();
} else if (strstart(devname, "disk:", &p)) {
dev = usb_msd_init(p);
} else if (strstart(devname, "net:", &p)) {
--- End Message ---