OpenBIOS
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1999 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1998 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1997 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1996 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1995 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1994 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1993 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1992 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1991 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1990 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1989 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1988 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1987 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1986 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1985 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1984 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1983 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1982 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1981 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1980 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1979 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1978 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1977 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1976 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1975 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1974 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1973 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1972 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1971 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1970 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1969 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1968 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1967 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1966 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1965 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1964 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1963 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1962 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1961 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1960 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1959 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1958 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1957 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1956 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1955 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1954 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1953 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1952 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1951 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1950 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1949 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1948 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1947 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1946 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1945 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1944 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1943 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1942 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1941 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1940 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1939 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1938 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1937 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1936 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1935 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1934 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1933 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1932 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1931 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1930 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1929 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1928 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1927 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1926 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1925 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1924 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1923 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1922 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1921 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1920 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1919 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1918 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1917 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1916 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1915 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1914 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1913 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1912 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1911 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1910 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1909 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1908 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1907 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1906 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1905 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 1904 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
August 2014
- 4 participants
- 13 discussions

[commit] r1316 - in trunk/openbios-devel: arch/ppc/qemu config/examples drivers include/drivers
by repository service Aug. 25, 2014
by repository service Aug. 25, 2014
Aug. 25, 2014
Author: mcayland
Date: Mon Aug 25 15:08:08 2014
New Revision: 1316
URL: http://tracker.coreboot.org/trac/openbios/changeset/1316
Log:
Add USB OHCI + HID driver
This driver is ported from CoreBoot's libpayload and fixed to work on
big endian CPUs (tested on PPC with QEMU). It is enough to support a
USB keyboard on an Apple Keylargo OHCI compliant USB host and makes
OpenBIOS usable on qemu-system-ppc64 with mac99 machine type as well
as allows to emulate PowerMac3,1 better.
Signed-off-by: BALATON Zoltan <balaton(a)eik.bme.hu>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
Added:
trunk/openbios-devel/drivers/usb.c
trunk/openbios-devel/drivers/usb.h
trunk/openbios-devel/drivers/usbhid.c
trunk/openbios-devel/drivers/usbohci.c
trunk/openbios-devel/drivers/usbohci.h
trunk/openbios-devel/drivers/usbohci_private.h
trunk/openbios-devel/drivers/usbohci_rh.c
trunk/openbios-devel/include/drivers/usb.h
Modified:
trunk/openbios-devel/arch/ppc/qemu/methods.c
trunk/openbios-devel/config/examples/ppc_config.xml
trunk/openbios-devel/drivers/Kconfig
trunk/openbios-devel/drivers/build.xml
trunk/openbios-devel/drivers/pci.c
trunk/openbios-devel/drivers/pci.h
trunk/openbios-devel/drivers/pci_database.c
trunk/openbios-devel/drivers/pci_database.h
trunk/openbios-devel/include/drivers/pci.h
Modified: trunk/openbios-devel/arch/ppc/qemu/methods.c
==============================================================================
--- trunk/openbios-devel/arch/ppc/qemu/methods.c Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/arch/ppc/qemu/methods.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -25,6 +25,7 @@
#include "qemu/qemu.h"
#include "libopenbios/ofmem.h"
#include "arch/ppc/processor.h"
+#include "drivers/usb.h"
/************************************************************************/
/* RTAS (run-time abstraction services) */
@@ -112,6 +113,7 @@
static void
ciface_quiesce( unsigned long args[], unsigned long ret[] )
{
+ usb_exit();
#if 0
unsigned long msr;
/* This seems to be the correct thing to do - but I'm not sure */
Modified: trunk/openbios-devel/config/examples/ppc_config.xml
==============================================================================
--- trunk/openbios-devel/config/examples/ppc_config.xml Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/config/examples/ppc_config.xml Mon Aug 25 15:08:08 2014 (r1316)
@@ -80,3 +80,6 @@
<option name="CONFIG_DRIVER_ESCC" type="boolean" value="true"/>
<option name="CONFIG_DRIVER_FW_CFG" type="boolean" value="true"/>
<option name="CONFIG_FW_CFG_ADDR" type="integer" value="0xf0000510"/>
+ <option name="CONFIG_DRIVER_USB" type="boolean" value="true"/>
+ <option name="CONFIG_DEBUG_USB" type="boolean" value="false"/>
+ <option name="CONFIG_USB_HID" type="boolean" value="true"/>
Modified: trunk/openbios-devel/drivers/Kconfig
==============================================================================
--- trunk/openbios-devel/drivers/Kconfig Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/drivers/Kconfig Mon Aug 25 15:08:08 2014 (r1316)
@@ -36,4 +36,24 @@
help
Debug IDE driver
+config DRIVER_USB
+ bool "USB Support"
+ default n
+ help
+ If you want to be able to use USB devices, enable this option.
+
+config DEBUG_USB
+ depends DRIVER_USB
+ bool "Debug USB driver"
+ default n
+ help
+ Debug USB driver
+
+config USB_HID
+ depends DRIVER_USB
+ bool "USB driver for HID devices"
+ default n
+ help
+ If you want to be able to use USB keyboard, enable this option.
+
endmenu
Modified: trunk/openbios-devel/drivers/build.xml
==============================================================================
--- trunk/openbios-devel/drivers/build.xml Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/drivers/build.xml Mon Aug 25 15:08:08 2014 (r1316)
@@ -22,6 +22,10 @@
<object source="pc_serial.c" condition="DRIVER_PC_SERIAL"/>
<object source="escc.c" condition="DRIVER_ESCC"/>
<object source="fw_cfg.c" condition="DRIVER_FW_CFG"/>
+ <object source="usb.c" condition="DRIVER_USB"/>
+ <object source="usbhid.c" condition="USB_HID"/>
+ <object source="usbohci.c" condition="DRIVER_USB"/>
+ <object source="usbohci_rh.c" condition="DRIVER_USB"/>
</library>
<dictionary name="openbios" target="forth">
Modified: trunk/openbios-devel/drivers/pci.c
==============================================================================
--- trunk/openbios-devel/drivers/pci.c Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/drivers/pci.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -34,6 +34,9 @@
#include "cuda.h"
#include "macio.h"
#endif
+#ifdef CONFIG_DRIVER_USB
+#include "drivers/usb.h"
+#endif
#if defined (CONFIG_DEBUG_PCI)
# define PCI_DPRINTF(format, ...) printk(format, ## __VA_ARGS__)
@@ -925,6 +928,14 @@
return 0;
}
+int usb_ohci_config_cb(const pci_config_t *config)
+{
+#ifdef CONFIG_DRIVER_USB
+ ob_usb_ohci_init(config->path, 0x80000000 | config->dev);
+#endif
+ return 0;
+}
+
static void ob_pci_add_properties(phandle_t phandle,
pci_addr addr, const pci_dev_t *pci_dev,
const pci_config_t *config, int num_bars)
Modified: trunk/openbios-devel/drivers/pci.h
==============================================================================
--- trunk/openbios-devel/drivers/pci.h Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/drivers/pci.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -7,6 +7,7 @@
#define PCI_COMMAND 0x04
#define PCI_COMMAND_IO 0x01
#define PCI_COMMAND_MEMORY 0x02
+#define PCI_COMMAND_BUS_MASTER 0x04
#define PCI_STATUS 0x06 /* 16 bits */
#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
Modified: trunk/openbios-devel/drivers/pci_database.c
==============================================================================
--- trunk/openbios-devel/drivers/pci_database.c Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/drivers/pci_database.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -845,6 +845,24 @@
},
};
+static const pci_dev_t usb_devices[] = {
+#if defined(CONFIG_QEMU)
+ {
+ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_KEYL_USB,
+ "usb", "usb", NULL,
+ "pci106b,3f\0pciclass,0c0310\0",
+ 1, 0, 0,
+ NULL, NULL,
+ },
+#endif
+ {
+ 0xFFFF, 0xFFFF,
+ NULL, NULL, NULL, NULL,
+ -1, -1, -1,
+ NULL, NULL,
+ },
+};
+
static const pci_iface_t usb_iface[] = {
{
0x00, "UHCI USB controller", NULL,
@@ -852,7 +870,7 @@
},
{
0x10, "OHCI USB controller", NULL,
- NULL, NULL, NULL,
+ usb_devices, &usb_ohci_config_cb, NULL,
},
{
0x20, "EHCI USB controller", NULL,
Modified: trunk/openbios-devel/drivers/pci_database.h
==============================================================================
--- trunk/openbios-devel/drivers/pci_database.h Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/drivers/pci_database.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -38,6 +38,7 @@
extern int bridge_config_cb(const pci_config_t *config);
extern int ebus_config_cb(const pci_config_t *config);
extern int i82378_config_cb(const pci_config_t *config);
+extern int usb_ohci_config_cb(const pci_config_t *config);
static inline int pci_compat_len(const pci_dev_t *dev)
{
Added: trunk/openbios-devel/drivers/usb.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usb.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,587 @@
+/*
+ * Driver for USB ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2008-2010 coresystems GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "drivers/usb.h"
+#include "usb.h"
+#include "timer.h"
+#include "libc/byteorder.h"
+
+hci_t *usb_hcs = 0;
+
+static void usb_nop_init (usbdev_t *dev);
+
+static void
+usb_nop_destroy (usbdev_t *dev)
+{
+ if (dev->descriptor != 0)
+ free (dev->descriptor);
+ usb_nop_init (dev);
+ dev->address = -1;
+ dev->hub = -1;
+ dev->port = -1;
+}
+
+static void
+usb_nop_poll (usbdev_t *dev)
+{
+ return;
+}
+
+static void
+usb_nop_init (usbdev_t *dev)
+{
+ dev->descriptor = 0;
+ dev->destroy = usb_nop_destroy;
+ dev->poll = usb_nop_poll;
+}
+
+hci_t *
+new_controller (void)
+{
+ hci_t *controller = malloc (sizeof (hci_t));
+
+ if (controller) {
+ /* atomic */
+ controller->next = usb_hcs;
+ usb_hcs = controller;
+ /* atomic end */
+ }
+
+ return controller;
+}
+
+void
+detach_controller (hci_t *controller)
+{
+ if (controller == NULL)
+ return;
+ if (usb_hcs == controller) {
+ usb_hcs = controller->next;
+ } else {
+ hci_t *it = usb_hcs;
+ while (it != NULL) {
+ if (it->next == controller) {
+ it->next = controller->next;
+ return;
+ }
+ it = it->next;
+ }
+ }
+}
+
+/**
+ * Shut down all controllers
+ */
+int
+usb_exit (void)
+{
+ while (usb_hcs != NULL) {
+ usb_hcs->shutdown(usb_hcs);
+ }
+ return 0;
+}
+
+/**
+ * Polls all hubs on all USB controllers, to find out about device changes
+ */
+void
+usb_poll (void)
+{
+ if (usb_hcs == 0)
+ return;
+ hci_t *controller = usb_hcs;
+ while (controller != NULL) {
+ int i;
+ for (i = 0; i < 128; i++) {
+ if (controller->devices[i] != 0) {
+ controller->devices[i]->poll (controller->devices[i]);
+ }
+ }
+ controller = controller->next;
+ }
+}
+
+void
+init_device_entry (hci_t *controller, int i)
+{
+ if (controller->devices[i] != 0)
+ usb_debug("warning: device %d reassigned?\n", i);
+ controller->devices[i] = malloc(sizeof(usbdev_t));
+ controller->devices[i]->controller = controller;
+ controller->devices[i]->address = -1;
+ controller->devices[i]->hub = -1;
+ controller->devices[i]->port = -1;
+ controller->devices[i]->init = usb_nop_init;
+ controller->devices[i]->init (controller->devices[i]);
+}
+
+void
+set_feature (usbdev_t *dev, int endp, int feature, int rtype)
+{
+ dev_req_t dr;
+
+ dr.bmRequestType = rtype;
+ dr.data_dir = host_to_device;
+ dr.bRequest = SET_FEATURE;
+ dr.wValue = __cpu_to_le16(feature);
+ dr.wIndex = __cpu_to_le16(endp);
+ dr.wLength = 0;
+ dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
+}
+
+void
+get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
+{
+ dev_req_t dr;
+
+ dr.bmRequestType = rtype;
+ dr.data_dir = device_to_host;
+ dr.bRequest = GET_STATUS;
+ dr.wValue = 0;
+ dr.wIndex = __cpu_to_le16(intf);
+ dr.wLength = __cpu_to_le16(len);
+ dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
+}
+
+u8 *
+get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
+ int descIdx, int langID)
+{
+ u8 buf[8];
+ u8 *result;
+ dev_req_t dr;
+ int size;
+
+ dr.bmRequestType = bmRequestType;
+ dr.data_dir = device_to_host; // always like this for descriptors
+ dr.bRequest = GET_DESCRIPTOR;
+ dr.wValue = __cpu_to_le16((descType << 8) | descIdx);
+ dr.wIndex = __cpu_to_le16(langID);
+ dr.wLength = __cpu_to_le16(8);
+ if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
+ usb_debug ("getting descriptor size (type %x) failed\n",
+ descType);
+ }
+
+ if (descType == 1) {
+ device_descriptor_t *dd = (device_descriptor_t *) buf;
+ usb_debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
+ if (dd->bMaxPacketSize0 != 0)
+ dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
+ }
+
+ /* special case for configuration descriptors: they carry all their
+ subsequent descriptors with them, and keep the entire size at a
+ different location */
+ size = buf[0];
+ if (buf[1] == 2) {
+ int realsize = __le16_to_cpu(((unsigned short *) (buf + 2))[0]);
+ size = realsize;
+ }
+ result = malloc (size);
+ memset (result, 0, size);
+ dr.wLength = __cpu_to_le16(size);
+ if (dev->controller->
+ control (dev, IN, sizeof (dr), &dr, size, result)) {
+ usb_debug ("getting descriptor (type %x, size %x) failed\n",
+ descType, size);
+ }
+
+ return result;
+}
+
+void
+set_configuration (usbdev_t *dev)
+{
+ dev_req_t dr;
+
+ dr.bmRequestType = 0;
+ dr.bRequest = SET_CONFIGURATION;
+ dr.wValue = __cpu_to_le16(dev->configuration[5]);
+ dr.wIndex = 0;
+ dr.wLength = 0;
+ dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
+}
+
+int
+clear_feature (usbdev_t *dev, int endp, int feature, int rtype)
+{
+ dev_req_t dr;
+
+ dr.bmRequestType = rtype;
+ dr.data_dir = host_to_device;
+ dr.bRequest = CLEAR_FEATURE;
+ dr.wValue = __cpu_to_le16(feature);
+ dr.wIndex = __cpu_to_le16(endp);
+ dr.wLength = 0;
+ return dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
+}
+
+int
+clear_stall (endpoint_t *ep)
+{
+ usbdev_t *dev = ep->dev;
+ int endp = ep->endpoint;
+ int rtype = gen_bmRequestType (host_to_device, standard_type,
+ endp ? endp_recp : dev_recp);
+
+ int ret = clear_feature (dev, endp, ENDPOINT_HALT, rtype);
+ ep->toggle = 0;
+ return ret;
+}
+
+/* returns free address or -1 */
+static int
+get_free_address (hci_t *controller)
+{
+ int i;
+ for (i = 1; i < 128; i++) {
+ if (controller->devices[i] == 0)
+ return i;
+ }
+ usb_debug ("no free address found\n");
+ return -1; // no free address
+}
+
+int
+generic_set_address (hci_t *controller, int speed, int hubport, int hubaddr)
+{
+ int adr = get_free_address (controller); // address to set
+ dev_req_t dr;
+
+ memset (&dr, 0, sizeof (dr));
+ dr.data_dir = host_to_device;
+ dr.req_type = standard_type;
+ dr.req_recp = dev_recp;
+ dr.bRequest = SET_ADDRESS;
+ dr.wValue = __cpu_to_le16(adr);
+ dr.wIndex = 0;
+ dr.wLength = 0;
+
+ init_device_entry(controller, adr);
+ usbdev_t *dev = controller->devices[adr];
+ // dummy values for registering the address
+ dev->address = 0;
+ dev->hub = hubaddr;
+ dev->port = hubport;
+ dev->speed = speed;
+ dev->endpoints[0].dev = dev;
+ dev->endpoints[0].endpoint = 0;
+ dev->endpoints[0].maxpacketsize = 8;
+ dev->endpoints[0].toggle = 0;
+ dev->endpoints[0].direction = SETUP;
+ mdelay (50);
+ if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
+ return -1;
+ }
+ mdelay (50);
+
+ return adr;
+}
+
+/* Normalize bInterval to log2 of microframes */
+static int
+usb_decode_interval(const int speed, const endpoint_type type, const unsigned char bInterval)
+{
+#define LOG2(a) ((sizeof(unsigned) << 3) - __builtin_clz(a) - 1)
+ switch (speed) {
+ case LOW_SPEED:
+ switch (type) {
+ case ISOCHRONOUS: case INTERRUPT:
+ return LOG2(bInterval) + 3;
+ default:
+ return 0;
+ }
+ case FULL_SPEED:
+ switch (type) {
+ case ISOCHRONOUS:
+ return (bInterval - 1) + 3;
+ case INTERRUPT:
+ return LOG2(bInterval) + 3;
+ default:
+ return 0;
+ }
+ case HIGH_SPEED:
+ switch (type) {
+ case ISOCHRONOUS: case INTERRUPT:
+ return bInterval - 1;
+ default:
+ return LOG2(bInterval);
+ }
+ case SUPER_SPEED:
+ switch (type) {
+ case ISOCHRONOUS: case INTERRUPT:
+ return bInterval - 1;
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
+#undef LOG2
+}
+
+static int
+set_address (hci_t *controller, int speed, int hubport, int hubaddr)
+{
+ int adr = controller->set_address(controller, speed, hubport, hubaddr);
+ if (adr < 0 || !controller->devices[adr]) {
+ usb_debug ("set_address failed\n");
+ return -1;
+ }
+ configuration_descriptor_t *cd;
+ device_descriptor_t *dd;
+
+ usbdev_t *dev = controller->devices[adr];
+ dev->address = adr;
+ dev->hub = hubaddr;
+ dev->port = hubport;
+ dev->speed = speed;
+ dev->descriptor = get_descriptor (dev, gen_bmRequestType
+ (device_to_host, standard_type, dev_recp), 1, 0, 0);
+ dd = (device_descriptor_t *) dev->descriptor;
+
+ usb_debug ("* found device (0x%04x:0x%04x, USB %x.%x)",
+ __le16_to_cpu(dd->idVendor), __le16_to_cpu(dd->idProduct),
+ __le16_to_cpu(dd->bcdUSB) >> 8, __le16_to_cpu(dd->bcdUSB) & 0xff);
+ dev->quirks = USB_QUIRK_NONE;
+
+ usb_debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
+ if (dd->bNumConfigurations == 0) {
+ /* device isn't usable */
+ usb_debug ("... no usable configuration!\n");
+ dev->address = 0;
+ return -1;
+ }
+
+ dev->configuration = get_descriptor (dev, gen_bmRequestType
+ (device_to_host, standard_type, dev_recp), 2, 0, 0);
+ cd = (configuration_descriptor_t *) dev->configuration;
+ interface_descriptor_t *interface =
+ (interface_descriptor_t *) (((char *) cd) + cd->bLength);
+ {
+ int i;
+ int num = cd->bNumInterfaces;
+ interface_descriptor_t *current = interface;
+ usb_debug ("device has %x interfaces\n", num);
+ if (num > 1) {
+ usb_debug ("\nNOTICE: This driver defaults to using the first interface.\n"
+ "This might be the wrong choice and lead to limited functionality\n"
+ "of the device.\n");
+ /* we limit to the first interface, as there was no need to
+ * implement something else for the time being. If you need
+ * it, see the SetInterface and GetInterface functions in
+ * the USB specification, and adapt appropriately.
+ */
+ num = (num > 1) ? 1 : num;
+ }
+ for (i = 0; i < num; i++) {
+ int j;
+ usb_debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
+ current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
+ endpoint_descriptor_t *endp =
+ (endpoint_descriptor_t *) (((char *) current)
+ + current->bLength);
+ /* Skip any non-endpoint descriptor */
+ if (endp->bDescriptorType != 0x05)
+ endp = (endpoint_descriptor_t *)(((char *)endp) + ((char *)endp)[0]);
+
+ memset (dev->endpoints, 0, sizeof (dev->endpoints));
+ dev->num_endp = 1; // 0 always exists
+ dev->endpoints[0].dev = dev;
+ dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
+ dev->endpoints[0].direction = SETUP;
+ dev->endpoints[0].type = CONTROL;
+ dev->endpoints[0].interval = usb_decode_interval(dev->speed, CONTROL, endp->bInterval);
+ for (j = 1; j <= current->bNumEndpoints; j++) {
+#ifdef CONFIG_DEBUG_USB
+ static const char *transfertypes[4] = {
+ "control", "isochronous", "bulk", "interrupt"
+ };
+ usb_debug (" #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", __le16_to_cpu(endp->wMaxPacketSize), transfertypes[endp->bmAttributes]);
+#endif
+ endpoint_t *ep =
+ &dev->endpoints[dev->num_endp++];
+ ep->dev = dev;
+ ep->endpoint = endp->bEndpointAddress;
+ ep->toggle = 0;
+ ep->maxpacketsize = __le16_to_cpu(endp->wMaxPacketSize);
+ ep->direction =
+ ((endp->bEndpointAddress & 0x80) ==
+ 0) ? OUT : IN;
+ ep->type = endp->bmAttributes;
+ ep->interval = usb_decode_interval(dev->speed, ep->type, endp->bInterval);
+ endp = (endpoint_descriptor_t
+ *) (((char *) endp) + endp->bLength);
+ }
+ current = (interface_descriptor_t *) endp;
+ }
+ }
+
+ if (controller->finish_device_config &&
+ controller->finish_device_config(dev))
+ return adr; /* Device isn't configured correctly,
+ only control transfers may work. */
+
+ set_configuration(dev);
+
+ int class = dd->bDeviceClass;
+ if (class == 0)
+ class = interface->bInterfaceClass;
+
+ usb_debug(", class: ");
+ switch (class) {
+ case audio_device:
+ usb_debug("audio\n");
+ break;
+ case comm_device:
+ usb_debug("communication\n");
+ break;
+ case hid_device:
+ usb_debug ("HID\n");
+#ifdef CONFIG_USB_HID
+ controller->devices[adr]->init = usb_hid_init;
+ return adr;
+#else
+ usb_debug ("NOTICE: USB HID support not compiled in\n");
+#endif
+ break;
+ case physical_device:
+ usb_debug("physical\n");
+ break;
+ case imaging_device:
+ usb_debug("camera\n");
+ break;
+ case printer_device:
+ usb_debug("printer\n");
+ break;
+ case msc_device:
+ usb_debug ("MSC\n");
+#ifdef CONFIG_USB_MSC
+ controller->devices[adr]->init = usb_msc_init;
+ return adr;
+#else
+ usb_debug ("NOTICE: USB MSC support not compiled in\n");
+#endif
+ break;
+ case hub_device:
+ usb_debug ("hub\n");
+#ifdef CONFIG_USB_HUB
+ controller->devices[adr]->init = usb_hub_init;
+ return adr;
+#else
+ usb_debug ("NOTICE: USB hub support not compiled in.\n");
+#endif
+ break;
+ case cdc_device:
+ usb_debug("CDC\n");
+ break;
+ case ccid_device:
+ usb_debug("smartcard / CCID\n");
+ break;
+ case security_device:
+ usb_debug("content security\n");
+ break;
+ case video_device:
+ usb_debug("video\n");
+ break;
+ case healthcare_device:
+ usb_debug("healthcare\n");
+ break;
+ case diagnostic_device:
+ usb_debug("diagnostic\n");
+ break;
+ case wireless_device:
+ usb_debug("wireless\n");
+ break;
+ default:
+ usb_debug("unsupported class %x\n", class);
+ break;
+ }
+ controller->devices[adr]->init = usb_generic_init;
+ return adr;
+}
+
+/*
+ * Should be called by the hub drivers whenever a physical detach occurs
+ * and can be called by usb class drivers if they are unsatisfied with a
+ * malfunctioning device.
+ */
+void
+usb_detach_device(hci_t *controller, int devno)
+{
+ /* check if device exists, as we may have
+ been called yet by the usb class driver */
+ if (controller->devices[devno]) {
+ controller->devices[devno]->destroy (controller->devices[devno]);
+ free(controller->devices[devno]);
+ controller->devices[devno] = NULL;
+ if (controller->destroy_device)
+ controller->destroy_device(controller, devno);
+ }
+}
+
+int
+usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
+{
+#ifdef CONFIG_USB_DEBUG
+ static const char* speeds[] = { "full", "low", "high" };
+ usb_debug ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
+#endif
+ int newdev = set_address (controller, speed, port, hubaddress);
+ if (newdev == -1)
+ return -1;
+ usbdev_t *newdev_t = controller->devices[newdev];
+ // determine responsible driver - current done in set_address
+ newdev_t->init (newdev_t);
+ /* init() may have called usb_detach_device() yet, so check */
+ return controller->devices[newdev] ? newdev : -1;
+}
+
+static void
+usb_generic_destroy (usbdev_t *dev)
+{
+ if (usb_generic_remove)
+ usb_generic_remove(dev);
+}
+
+void
+usb_generic_init (usbdev_t *dev)
+{
+ dev->data = NULL;
+ dev->destroy = usb_generic_destroy;
+
+ if (usb_generic_create)
+ usb_generic_create(dev);
+}
Added: trunk/openbios-devel/drivers/usb.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usb.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,357 @@
+/*
+ * Driver for USB ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2008 coresystems GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __USB_H
+#define __USB_H
+#include <drivers/pci.h>
+
+typedef enum { host_to_device = 0, device_to_host = 1 } dev_req_dir;
+typedef enum { standard_type = 0, class_type = 1, vendor_type =
+ 2, reserved_type = 3
+} dev_req_type;
+typedef enum { dev_recp = 0, iface_recp = 1, endp_recp = 2, other_recp = 3
+} dev_req_recp;
+
+typedef enum {
+ GET_STATUS = 0,
+ CLEAR_FEATURE = 1,
+ SET_FEATURE = 3,
+ SET_ADDRESS = 5,
+ GET_DESCRIPTOR = 6,
+ SET_DESCRIPTOR = 7,
+ GET_CONFIGURATION = 8,
+ SET_CONFIGURATION = 9,
+ GET_INTERFACE = 10,
+ SET_INTERFACE = 11,
+ SYNCH_FRAME = 12
+} bRequest_Codes;
+
+typedef enum {
+ ENDPOINT_HALT = 0,
+ DEVICE_REMOTE_WAKEUP = 1,
+ TEST_MODE = 2
+} feature_selectors;
+
+enum {
+ audio_device = 0x01,
+ comm_device = 0x02,
+ hid_device = 0x03,
+ physical_device = 0x05,
+ imaging_device = 0x06,
+ printer_device = 0x07,
+ msc_device = 0x08,
+ hub_device = 0x09,
+ cdc_device = 0x0a,
+ ccid_device = 0x0b,
+ security_device = 0x0d,
+ video_device = 0x0e,
+ healthcare_device = 0x0f,
+ diagnostic_device = 0xdc,
+ wireless_device = 0xe0,
+ misc_device = 0xef,
+};
+
+enum { hid_subclass_none = 0, hid_subclass_boot = 1 };
+
+enum {
+ hid_boot_proto_none = 0,
+ hid_boot_proto_keyboard = 1,
+ hid_boot_proto_mouse = 2
+};
+
+typedef struct {
+ union {
+ struct {
+#ifdef CONFIG_BIG_ENDIAN
+ dev_req_dir data_dir:1;
+ dev_req_type req_type:2;
+ dev_req_recp req_recp:5;
+#else
+ dev_req_recp req_recp:5;
+ dev_req_type req_type:2;
+ dev_req_dir data_dir:1;
+#endif
+ } __attribute__ ((packed));
+ unsigned char bmRequestType;
+ } __attribute__ ((packed));
+ unsigned char bRequest;
+ unsigned short wValue;
+ unsigned short wIndex;
+ unsigned short wLength;
+} __attribute__ ((packed)) dev_req_t;
+
+struct usbdev_hc;
+typedef struct usbdev_hc hci_t;
+
+struct usbdev;
+typedef struct usbdev usbdev_t;
+
+typedef enum { SETUP, IN, OUT } direction_t;
+typedef enum { CONTROL = 0, ISOCHRONOUS = 1, BULK = 2, INTERRUPT = 3
+} endpoint_type;
+
+typedef struct {
+ usbdev_t *dev;
+ int endpoint;
+ direction_t direction;
+ int toggle;
+ int maxpacketsize;
+ endpoint_type type;
+ int interval; /* expressed as binary logarithm of the number
+ of microframes (i.e. t = 125us * 2^interval) */
+} endpoint_t;
+
+enum { FULL_SPEED = 0, LOW_SPEED = 1, HIGH_SPEED = 2, SUPER_SPEED = 3 };
+
+struct usbdev {
+ hci_t *controller;
+ endpoint_t endpoints[32];
+ int num_endp;
+ int address; // usb address
+ int hub; // hub, device is attached to
+ int port; // port where device is attached
+ int speed; // 1: lowspeed, 0: fullspeed, 2: highspeed
+ u32 quirks; // quirks field. got to love usb
+ void *data;
+ u8 *descriptor;
+ u8 *configuration;
+ void (*init) (usbdev_t *dev);
+ void (*destroy) (usbdev_t *dev);
+ void (*poll) (usbdev_t *dev);
+};
+
+typedef enum { OHCI = 0, UHCI = 1, EHCI = 2, XHCI = 3} hc_type;
+
+struct usbdev_hc {
+ hci_t *next;
+ u32 reg_base;
+ hc_type type;
+ usbdev_t *devices[128]; // dev 0 is root hub, 127 is last addressable
+
+ /* start(): Resume operation. */
+ void (*start) (hci_t *controller);
+ /* stop(): Stop operation but keep controller initialized. */
+ void (*stop) (hci_t *controller);
+ /* reset(): Perform a controller reset. The controller needs to
+ be (re)initialized afterwards to work (again). */
+ void (*reset) (hci_t *controller);
+ /* init(): Initialize a (previously reset) controller
+ to a working state. */
+ void (*init) (hci_t *controller);
+ /* shutdown(): Stop operation, detach host controller and shutdown
+ this driver instance. After calling shutdown() any
+ other usage of this hci_t* is invalid. */
+ void (*shutdown) (hci_t *controller);
+
+ int (*bulk) (endpoint_t *ep, int size, u8 *data, int finalize);
+ int (*control) (usbdev_t *dev, direction_t pid, int dr_length,
+ void *devreq, int data_length, u8 *data);
+ void* (*create_intr_queue) (endpoint_t *ep, int reqsize, int reqcount, int reqtiming);
+ void (*destroy_intr_queue) (endpoint_t *ep, void *queue);
+ u8* (*poll_intr_queue) (void *queue);
+ void *instance;
+
+ /* set_address(): Tell the usb device its address and
+ return it. xHCI controllers want to
+ do this by themself. Also, the usbdev
+ structure has to be allocated and
+ initialized. */
+ int (*set_address) (hci_t *controller, int speed, int hubport, int hubaddr);
+ /* finish_device_config(): Another hook for xHCI,
+ returns 0 on success. */
+ int (*finish_device_config) (usbdev_t *dev);
+ /* destroy_device(): Finally, destroy all structures that
+ were allocated during set_address()
+ and finish_device_config(). */
+ void (*destroy_device) (hci_t *controller, int devaddr);
+};
+
+typedef struct {
+ unsigned char bDescLength;
+ unsigned char bDescriptorType;
+ unsigned char bNbrPorts;
+ union {
+ struct {
+#ifdef CONFIG_BIG_ENDIAN
+ unsigned long:8;
+ unsigned long arePortIndicatorsSupported:1;
+ unsigned long ttThinkTime:2;
+ unsigned long overcurrentProtectionMode:2;
+ unsigned long isCompoundDevice:1;
+ unsigned long logicalPowerSwitchingMode:2;
+#else
+ unsigned long logicalPowerSwitchingMode:2;
+ unsigned long isCompoundDevice:1;
+ unsigned long overcurrentProtectionMode:2;
+ unsigned long ttThinkTime:2;
+ unsigned long arePortIndicatorsSupported:1;
+ unsigned long:8;
+#endif
+ } __attribute__ ((packed));
+ unsigned short wHubCharacteristics;
+ } __attribute__ ((packed));
+ unsigned char bPowerOn2PwrGood;
+ unsigned char bHubContrCurrent;
+ char DeviceRemovable[];
+} __attribute__ ((packed)) hub_descriptor_t;
+
+typedef struct {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short bcdUSB;
+ unsigned char bDeviceClass;
+ unsigned char bDeviceSubClass;
+ unsigned char bDeviceProtocol;
+ unsigned char bMaxPacketSize0;
+ unsigned short idVendor;
+ unsigned short idProduct;
+ unsigned short bcdDevice;
+ unsigned char iManufacturer;
+ unsigned char iProduct;
+ unsigned char iSerialNumber;
+ unsigned char bNumConfigurations;
+} __attribute__ ((packed)) device_descriptor_t;
+
+typedef struct {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short wTotalLength;
+ unsigned char bNumInterfaces;
+ unsigned char bConfigurationValue;
+ unsigned char iConfiguration;
+ unsigned char bmAttributes;
+ unsigned char bMaxPower;
+} __attribute__ ((packed)) configuration_descriptor_t;
+
+typedef struct {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned char bInterfaceNumber;
+ unsigned char bAlternateSetting;
+ unsigned char bNumEndpoints;
+ unsigned char bInterfaceClass;
+ unsigned char bInterfaceSubClass;
+ unsigned char bInterfaceProtocol;
+ unsigned char iInterface;
+} __attribute__ ((packed)) interface_descriptor_t;
+
+typedef struct {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned char bEndpointAddress;
+ unsigned char bmAttributes;
+ unsigned short wMaxPacketSize;
+ unsigned char bInterval;
+} __attribute__ ((packed)) endpoint_descriptor_t;
+
+typedef struct {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short bcdHID;
+ unsigned char bCountryCode;
+ unsigned char bNumDescriptors;
+ unsigned char bReportDescriptorType;
+ unsigned short wReportDescriptorLength;
+} __attribute__ ((packed)) hid_descriptor_t;
+
+hci_t *new_controller (void);
+void detach_controller (hci_t *controller);
+void usb_poll (void);
+void init_device_entry (hci_t *controller, int num);
+
+void set_feature (usbdev_t *dev, int endp, int feature, int rtype);
+void get_status (usbdev_t *dev, int endp, int rtype, int len, void *data);
+void set_configuration (usbdev_t *dev);
+int clear_feature (usbdev_t *dev, int endp, int feature, int rtype);
+int clear_stall (endpoint_t *ep);
+
+void usb_hub_init (usbdev_t *dev);
+void usb_hid_init (usbdev_t *dev);
+void usb_msc_init (usbdev_t *dev);
+void usb_generic_init (usbdev_t *dev);
+
+u8 *get_descriptor (usbdev_t *dev, unsigned char bmRequestType,
+ int descType, int descIdx, int langID);
+
+static inline unsigned char
+gen_bmRequestType (dev_req_dir dir, dev_req_type type, dev_req_recp recp)
+{
+ return (dir << 7) | (type << 5) | recp;
+}
+
+/* default "set address" handler */
+int generic_set_address (hci_t *controller, int speed, int hubport, int hubaddr);
+
+void usb_detach_device(hci_t *controller, int devno);
+int usb_attach_device(hci_t *controller, int hubaddress, int port, int speed);
+
+u32 usb_quirk_check(u16 vendor, u16 device);
+int usb_interface_check(u16 vendor, u16 device);
+
+#define USB_QUIRK_MSC_FORCE_PROTO_SCSI (1 << 0)
+#define USB_QUIRK_MSC_FORCE_PROTO_ATAPI (1 << 1)
+#define USB_QUIRK_MSC_FORCE_PROTO_UFI (1 << 2)
+#define USB_QUIRK_MSC_FORCE_PROTO_RBC (1 << 3)
+#define USB_QUIRK_MSC_FORCE_TRANS_BBB (1 << 4)
+#define USB_QUIRK_MSC_FORCE_TRANS_CBI (1 << 5)
+#define USB_QUIRK_MSC_FORCE_TRANS_CBI_I (1 << 6)
+#define USB_QUIRK_MSC_NO_TEST_UNIT_READY (1 << 7)
+#define USB_QUIRK_MSC_SHORT_INQUIRY (1 << 8)
+#define USB_QUIRK_TEST (1 << 31)
+#define USB_QUIRK_NONE 0
+
+#ifdef CONFIG_DEBUG_USB
+#define usb_debug(fmt, args...) do { printk(fmt , ##args); } while (0)
+#else
+#define usb_debug(fmt, args...)
+#endif
+
+/**
+ * To be implemented by libpayload-client. It's called by the USB stack
+ * when a new USB device is found which isn't claimed by a built in driver,
+ * so the client has the chance to know about it.
+ *
+ * @param dev descriptor for the USB device
+ */
+void __attribute__((weak)) usb_generic_create (usbdev_t *dev);
+
+/**
+ * To be implemented by libpayload-client. It's called by the USB stack
+ * when it finds out that a USB device is removed which wasn't claimed by a
+ * built in driver.
+ *
+ * @param dev descriptor for the USB device
+ */
+void __attribute__((weak)) usb_generic_remove (usbdev_t *dev);
+
+#endif
Added: trunk/openbios-devel/drivers/usbhid.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usbhid.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,579 @@
+/*
+ * Driver for HID devices ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2008-2010 coresystems GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include <libc/string.h>
+#include "libc/byteorder.h"
+#include "libc/vsprintf.h"
+#include "drivers/usb.h"
+#include "usb.h"
+
+DECLARE_UNNAMED_NODE(usb_kbd, INSTALL_OPEN, sizeof(int));
+
+static void
+keyboard_open(int *idx)
+{
+ RET(-1);
+}
+
+static void
+keyboard_close(int *idx)
+{
+}
+
+static void keyboard_read(void);
+
+NODE_METHODS( usb_kbd ) = {
+ { "open", keyboard_open },
+ { "close", keyboard_close },
+ { "read", keyboard_read },
+};
+
+#ifdef CONFIG_USB_DEBUG
+static const char *boot_protos[3] = { "(none)", "keyboard", "mouse" };
+#endif
+typedef enum { hid_proto_boot = 0, hid_proto_report = 1 } hid_proto;
+enum { GET_REPORT = 0x1, GET_IDLE = 0x2, GET_PROTOCOL = 0x3, SET_REPORT =
+ 0x9, SET_IDLE = 0xa, SET_PROTOCOL = 0xb
+};
+
+typedef union {
+ struct {
+ u8 modifiers;
+ u8 repeats;
+ u8 keys[6];
+ };
+ u8 buffer[8];
+} usb_hid_keyboard_event_t;
+
+typedef struct {
+ void* queue;
+ hid_descriptor_t *descriptor;
+
+ usb_hid_keyboard_event_t previous;
+ int lastkeypress;
+ int repeat_delay;
+} usbhid_inst_t;
+
+#define HID_INST(dev) ((usbhid_inst_t*)(dev)->data)
+
+static void
+usb_hid_destroy (usbdev_t *dev)
+{
+ if (HID_INST(dev)->queue) {
+ int i;
+ for (i = 0; i <= dev->num_endp; i++) {
+ if (dev->endpoints[i].endpoint == 0)
+ continue;
+ if (dev->endpoints[i].type != INTERRUPT)
+ continue;
+ if (dev->endpoints[i].direction != IN)
+ continue;
+ break;
+ }
+ dev->controller->destroy_intr_queue(
+ &dev->endpoints[i], HID_INST(dev)->queue);
+ HID_INST(dev)->queue = NULL;
+ }
+ free (dev->data);
+}
+
+/* keybuffer is global to all USB keyboards */
+static int keycount;
+#define KEYBOARD_BUFFER_SIZE 16
+static short keybuffer[KEYBOARD_BUFFER_SIZE];
+
+const char *countries[36][2] = {
+ { "unknown", "us" },
+ { "Arabic", "ae" },
+ { "Belgian", "be" },
+ { "Canadian-Bilingual", "ca" },
+ { "Canadian-French", "ca" },
+ { "Czech Republic", "cz" },
+ { "Danish", "dk" },
+ { "Finnish", "fi" },
+ { "French", "fr" },
+ { "German", "de" },
+ { "Greek", "gr" },
+ { "Hebrew", "il" },
+ { "Hungary", "hu" },
+ { "International (ISO)", "iso" },
+ { "Italian", "it" },
+ { "Japan (Katakana)", "jp" },
+ { "Korean", "us" },
+ { "Latin American", "us" },
+ { "Netherlands/Dutch", "nl" },
+ { "Norwegian", "no" },
+ { "Persian (Farsi)", "ir" },
+ { "Poland", "pl" },
+ { "Portuguese", "pt" },
+ { "Russia", "ru" },
+ { "Slovakia", "sl" },
+ { "Spanish", "es" },
+ { "Swedish", "se" },
+ { "Swiss/French", "ch" },
+ { "Swiss/German", "ch" },
+ { "Switzerland", "ch" },
+ { "Taiwan", "tw" },
+ { "Turkish-Q", "tr" },
+ { "UK", "uk" },
+ { "US", "us" },
+ { "Yugoslavia", "yu" },
+ { "Turkish-F", "tr" },
+ /* 36 - 255: Reserved */
+};
+
+
+
+struct layout_maps {
+ const char *country;
+ const short map[4][0x80];
+};
+
+static const struct layout_maps *map;
+
+#define KEY_BREAK 0x101 /* Not on PC KBD */
+#define KEY_DOWN 0x102 /* Down arrow key */
+#define KEY_UP 0x103 /* Up arrow key */
+#define KEY_LEFT 0x104 /* Left arrow key */
+#define KEY_RIGHT 0x105 /* Right arrow key */
+#define KEY_HOME 0x106 /* home key */
+#define KEY_BACKSPACE 0x107 /* not on pc */
+#define KEY_F0 0x108 /* function keys; 64 reserved */
+#define KEY_F(n) (KEY_F0 + (n))
+
+#define KEY_DC 0x14a /* delete character */
+#define KEY_IC 0x14b /* insert char or enter ins mode */
+
+#define KEY_NPAGE 0x152 /* next page */
+#define KEY_PPAGE 0x153 /* previous page */
+
+#define KEY_ENTER 0x157 /* enter or send (unreliable) */
+
+#define KEY_PRINT 0x15a /* print/copy */
+
+#define KEY_END 0x166 /* end key */
+
+static const struct layout_maps keyboard_layouts[] = {
+// #ifdef CONFIG_PC_KEYBOARD_LAYOUT_US
+{ .country = "us", .map = {
+ { /* No modifier */
+ -1, -1, -1, -1, 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ /* 0x10 */
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
+ /* 0x20 */
+ '3', '4', '5', '6', '7', '8', '9', '0',
+ '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
+ /* 0x30 */
+ ']', '\\', -1, ';', '\'', '`', ',', '.',
+ '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
+ /* 0x40 */
+ KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
+ KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
+ /* 50 */
+ KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
+ KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
+ /* 60 */
+ KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* 70 */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ },
+ { /* Shift modifier */
+ -1, -1, -1, -1, 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ /* 0x10 */
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
+ /* 0x20 */
+ '#', '$', '%', '^', '&', '*', '(', ')',
+ '\n', '\e', '\b', '\t', ' ', '_', '+', '{',
+ /* 0x30 */
+ '}', '|', -1, ':', '"', '~', '<', '>',
+ '?', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
+ /* 0x40 */
+ KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
+ KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
+ /* 50 */
+ KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
+ KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
+ /* 60 */
+ KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* 70 */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ },
+ { /* Alt */
+ -1, -1, -1, -1, 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ /* 0x10 */
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
+ /* 0x20 */
+ '3', '4', '5', '6', '7', '8', '9', '0',
+ '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
+ /* 0x30 */
+ ']', '\\', -1, ';', '\'', '`', ',', '.',
+ '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
+ /* 0x40 */
+ KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
+ KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
+ /* 50 */
+ KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
+ KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
+ /* 60 */
+ KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* 70 */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ },
+ { /* Shift+Alt modifier */
+ -1, -1, -1, -1, 'A', 'B', 'C', 'D',
+ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+ /* 0x10 */
+ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
+ /* 0x20 */
+ '#', '$', '%', '^', '&', '*', '(', ')',
+ '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
+ /* 0x30 */
+ ']', '\\', -1, ':', '\'', '`', ',', '.',
+ '/', -1 /* CapsLk */, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
+ /* 0x40 */
+ KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), KEY_PRINT, -1 /* ScrLk */,
+ KEY_BREAK, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT,
+ /* 50 */
+ KEY_LEFT, KEY_DOWN, KEY_UP, -1 /*NumLck*/, '/', '*', '-' /* = ? */, '+',
+ KEY_ENTER, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
+ /* 60 */
+ KEY_UP, KEY_PPAGE, -1, KEY_DC, -1 /* < > | */, -1 /* Win Key Right */, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ /* 70 */
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ }
+}},
+//#endif
+};
+
+#define MOD_SHIFT (1 << 0)
+#define MOD_ALT (1 << 1)
+#define MOD_CTRL (1 << 2)
+
+static void usb_hid_keyboard_queue(int ch) {
+ /* ignore key presses if buffer full */
+ if (keycount < KEYBOARD_BUFFER_SIZE)
+ keybuffer[keycount++] = ch;
+}
+
+#define KEYBOARD_REPEAT_MS 30
+#define INITIAL_REPEAT_DELAY 10
+#define REPEAT_DELAY 2
+
+static void
+usb_hid_process_keyboard_event(usbhid_inst_t *const inst,
+ const usb_hid_keyboard_event_t *const current)
+{
+ const usb_hid_keyboard_event_t *const previous = &inst->previous;
+
+ int i, keypress = 0, modifiers = 0;
+
+ if (current->modifiers & 0x01) /* Left-Ctrl */ modifiers |= MOD_CTRL;
+ if (current->modifiers & 0x02) /* Left-Shift */ modifiers |= MOD_SHIFT;
+ if (current->modifiers & 0x04) /* Left-Alt */ modifiers |= MOD_ALT;
+ if (current->modifiers & 0x08) /* Left-GUI */ ;
+ if (current->modifiers & 0x10) /* Right-Ctrl */ modifiers |= MOD_CTRL;
+ if (current->modifiers & 0x20) /* Right-Shift */ modifiers |= MOD_SHIFT;
+ if (current->modifiers & 0x40) /* Right-AltGr */ modifiers |= MOD_ALT;
+ if (current->modifiers & 0x80) /* Right-GUI */ ;
+
+ /* Did the event change at all? */
+ if (inst->lastkeypress &&
+ !memcmp(current, previous, sizeof(*current))) {
+ /* No. Then it's a key repeat event. */
+ if (inst->repeat_delay) {
+ inst->repeat_delay--;
+ } else {
+ usb_hid_keyboard_queue(inst->lastkeypress);
+ inst->repeat_delay = REPEAT_DELAY;
+ }
+
+ return;
+ }
+
+ inst->lastkeypress = 0;
+
+ for (i=0; i<6; i++) {
+ int j;
+ int skip = 0;
+ // No more keys? skip
+ if (current->keys[i] == 0)
+ return;
+
+ for (j=0; j<6; j++) {
+ if (current->keys[i] == previous->keys[j]) {
+ skip = 1;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+
+
+ /* Mask off MOD_CTRL */
+ keypress = map->map[modifiers & 0x03][current->keys[i]];
+
+ if (modifiers & MOD_CTRL) {
+ switch (keypress) {
+ case 'a' ... 'z':
+ keypress &= 0x1f;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ if (keypress == -1) {
+ /* Debug: Print unknown keys */
+ usb_debug ("usbhid: <%x> %x [ %x %x %x %x %x %x ] %d\n",
+ current->modifiers, current->repeats,
+ current->keys[0], current->keys[1],
+ current->keys[2], current->keys[3],
+ current->keys[4], current->keys[5], i);
+
+ /* Unknown key? Try next one in the queue */
+ continue;
+ }
+
+ usb_hid_keyboard_queue(keypress);
+
+ /* Remember for authentic key repeat */
+ inst->lastkeypress = keypress;
+ inst->repeat_delay = INITIAL_REPEAT_DELAY;
+ }
+}
+
+static void
+usb_hid_poll (usbdev_t *dev)
+{
+ usb_hid_keyboard_event_t current;
+ const u8 *buf;
+
+ while ((buf=dev->controller->poll_intr_queue (HID_INST(dev)->queue))) {
+ memcpy(¤t.buffer, buf, 8);
+ usb_hid_process_keyboard_event(HID_INST(dev), ¤t);
+ HID_INST(dev)->previous = current;
+ }
+}
+
+static void
+usb_hid_set_idle (usbdev_t *dev, interface_descriptor_t *interface, u16 duration)
+{
+ dev_req_t dr;
+ dr.data_dir = host_to_device;
+ dr.req_type = class_type;
+ dr.req_recp = iface_recp;
+ dr.bRequest = SET_IDLE;
+ dr.wValue = __cpu_to_le16((duration >> 2) << 8);
+ dr.wIndex = __cpu_to_le16(interface->bInterfaceNumber);
+ dr.wLength = 0;
+ dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
+}
+
+static void
+usb_hid_set_protocol (usbdev_t *dev, interface_descriptor_t *interface, hid_proto proto)
+{
+ dev_req_t dr;
+ dr.data_dir = host_to_device;
+ dr.req_type = class_type;
+ dr.req_recp = iface_recp;
+ dr.bRequest = SET_PROTOCOL;
+ dr.wValue = __cpu_to_le16(proto);
+ dr.wIndex = __cpu_to_le16(interface->bInterfaceNumber);
+ dr.wLength = 0;
+ dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
+}
+
+static int usb_hid_set_layout (const char *country)
+{
+ /* FIXME should be per keyboard */
+ int i;
+
+ for (i=0; i<sizeof(keyboard_layouts)/sizeof(keyboard_layouts[0]); i++) {
+ if (strncmp(keyboard_layouts[i].country, country,
+ strlen(keyboard_layouts[i].country)))
+ continue;
+
+ /* Found, changing keyboard layout */
+ map = &keyboard_layouts[i];
+ usb_debug(" Keyboard layout '%s'\n", map->country);
+ return 0;
+ }
+
+ usb_debug(" Keyboard layout '%s' not found, using '%s'\n",
+ country, map->country);
+
+ /* Nothing found, not changed */
+ return -1;
+}
+
+void
+usb_hid_init (usbdev_t *dev)
+{
+ configuration_descriptor_t *cd = (configuration_descriptor_t*)dev->configuration;
+ interface_descriptor_t *interface = (interface_descriptor_t*)(((char *) cd) + cd->bLength);
+
+ if (interface->bInterfaceSubClass == hid_subclass_boot) {
+ u8 countrycode = 0;
+ usb_debug (" supports boot interface..\n");
+ usb_debug (" it's a %s\n",
+ boot_protos[interface->bInterfaceProtocol]);
+ switch (interface->bInterfaceProtocol) {
+ case hid_boot_proto_keyboard:
+ dev->data = malloc (sizeof (usbhid_inst_t));
+ if (!dev->data) {
+ printk("Not enough memory for USB HID device.\n");
+ return;
+ }
+ memset(&HID_INST(dev)->previous, 0x00,
+ sizeof(HID_INST(dev)->previous));
+ usb_debug (" configuring...\n");
+ usb_hid_set_protocol(dev, interface, hid_proto_boot);
+ usb_hid_set_idle(dev, interface, KEYBOARD_REPEAT_MS);
+ usb_debug (" activating...\n");
+#if 0
+ HID_INST (dev)->descriptor =
+ (hid_descriptor_t *)
+ get_descriptor(dev, gen_bmRequestType
+ (device_to_host, standard_type, iface_recp),
+ 0x21, 0, 0);
+ countrycode = HID_INST(dev)->descriptor->bCountryCode;
+#endif
+ /* 35 countries defined: */
+ if (countrycode > 35)
+ countrycode = 0;
+ usb_debug (" Keyboard has %s layout (country code %02x)\n",
+ countries[countrycode][0], countrycode);
+
+ /* Set keyboard layout accordingly */
+ usb_hid_set_layout(countries[countrycode][1]);
+
+ // only add here, because we only support boot-keyboard HID devices
+ dev->destroy = usb_hid_destroy;
+ dev->poll = usb_hid_poll;
+ int i;
+ for (i = 0; i <= dev->num_endp; i++) {
+ if (dev->endpoints[i].endpoint == 0)
+ continue;
+ if (dev->endpoints[i].type != INTERRUPT)
+ continue;
+ if (dev->endpoints[i].direction != IN)
+ continue;
+ break;
+ }
+ usb_debug (" found endpoint %x for interrupt-in\n", i);
+ /* 20 buffers of 8 bytes, for every 10 msecs */
+ HID_INST(dev)->queue = dev->controller->create_intr_queue (&dev->endpoints[i], 8, 20, 10);
+ keycount = 0;
+ usb_debug (" configuration done.\n");
+ break;
+ default:
+ usb_debug("NOTICE: HID interface protocol %d%s not supported.\n",
+ interface->bInterfaceProtocol,
+ (interface->bInterfaceProtocol == hid_boot_proto_mouse ?
+ " (USB mouse)" : ""));
+ break;
+ }
+ }
+}
+
+static int usbhid_havechar (void)
+{
+ return (keycount != 0);
+}
+
+static int usbhid_getchar (void)
+{
+ short ret;
+
+ if (keycount == 0)
+ return 0;
+ ret = keybuffer[0];
+ memmove(keybuffer, keybuffer + 1, --keycount);
+
+ return (int)ret;
+}
+
+/* ( addr len -- actual ) */
+static void keyboard_read(void)
+{
+ char *addr;
+ int len, key, i;
+
+ usb_poll();
+ len=POP();
+ addr=(char *)cell2pointer(POP());
+
+ for (i = 0; i < len; i++) {
+ if (!usbhid_havechar())
+ break;
+ key = usbhid_getchar();
+ *addr++ = (char)key;
+ }
+ PUSH(i);
+}
+
+void ob_usb_hid_add_keyboard(const char *path)
+{
+ char name[128];
+ phandle_t aliases;
+
+ snprintf(name, sizeof(name), "%s/keyboard", path);
+ usb_debug("Found keyboard at %s\n", name);
+ REGISTER_NAMED_NODE(usb_kbd, name);
+
+ push_str(name);
+ fword("find-device");
+
+ push_str("keyboard");
+ fword("device-type");
+
+ aliases = find_dev("/aliases");
+ set_property(aliases, "adb-keyboard", name, strlen(name) + 1);
+}
Added: trunk/openbios-devel/drivers/usbohci.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usbohci.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,926 @@
+/*
+ * Driver for USB OHCI ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2010 Patrick Georgi
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+//#define USB_DEBUG_ED
+
+#include "config.h"
+#include <asm/io.h>
+#include <libopenbios/ofmem.h>
+#include "timer.h"
+#include "drivers/pci.h"
+#include "pci.h"
+#include <drivers/usb.h>
+#include "usbohci_private.h"
+#include "usbohci.h"
+
+static void ohci_start (hci_t *controller);
+static void ohci_stop (hci_t *controller);
+static void ohci_reset (hci_t *controller);
+static void ohci_shutdown (hci_t *controller);
+static int ohci_bulk (endpoint_t *ep, int size, u8 *data, int finalize);
+static int ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq,
+ int dalen, u8 *data);
+static void* ohci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming);
+static void ohci_destroy_intr_queue (endpoint_t *ep, void *queue);
+static u8* ohci_poll_intr_queue (void *queue);
+static void ohci_process_done_queue(ohci_t *ohci, int spew_debug);
+
+#ifdef USB_DEBUG_ED
+static void
+dump_td (td_t *cur)
+{
+ usb_debug("+---------------------------------------------------+\n");
+ if (((__le32_to_cpu(cur->config) & (3UL << 19)) >> 19) == 0)
+ usb_debug("|..[SETUP]..........................................|\n");
+ else if (((__le32_to_cpu(cur->config) & (3UL << 8)) >> 8) == 2)
+ usb_debug("|..[IN].............................................|\n");
+ else if (((__le32_to_cpu(cur->config) & (3UL << 8)) >> 8) == 1)
+ usb_debug("|..[OUT]............................................|\n");
+ else
+ usb_debug("|..[]...............................................|\n");
+ usb_debug("|:|============ OHCI TD at [0x%08lx] ==========|:|\n", virt_to_phys(cur));
+ usb_debug("|:| ERRORS = [%ld] | CONFIG = [0x%08x] | |:|\n",
+ 3 - ((__le32_to_cpu(cur->config) & (3UL << 26)) >> 26), __le32_to_cpu(cur->config));
+ usb_debug("|:+-----------------------------------------------+:|\n");
+ usb_debug("|:| C | Condition Code | [%02ld] |:|\n",
+ (__le32_to_cpu(cur->config) & (0xFUL << 28)) >> 28);
+ usb_debug("|:| O | Direction/PID | [%ld] |:|\n",
+ (__le32_to_cpu(cur->config) & (3UL << 19)) >> 19);
+ usb_debug("|:| N | Buffer Rounding | [%ld] |:|\n",
+ (__le32_to_cpu(cur->config) & (1UL << 18)) >> 18);
+ usb_debug("|:| F | Delay Intterrupt | [%ld] |:|\n",
+ (__le32_to_cpu(cur->config) & (7UL << 21)) >> 21);
+ usb_debug("|:| I | Data Toggle | [%ld] |:|\n",
+ (__le32_to_cpu(cur->config) & (3UL << 24)) >> 24);
+ usb_debug("|:| G | Error Count | [%ld] |:|\n",
+ (__le32_to_cpu(cur->config) & (3UL << 26)) >> 26);
+ usb_debug("|:+-----------------------------------------------+:|\n");
+ usb_debug("|:| Current Buffer Pointer [0x%08x] |:|\n", __le32_to_cpu(cur->current_buffer_pointer));
+ usb_debug("|:+-----------------------------------------------+:|\n");
+ usb_debug("|:| Next TD [0x%08x] |:|\n", __le32_to_cpu(cur->next_td));
+ usb_debug("|:+-----------------------------------------------+:|\n");
+ usb_debug("|:| Current Buffer End [0x%08x] |:|\n", __le32_to_cpu(cur->buffer_end));
+ usb_debug("|:|-----------------------------------------------|:|\n");
+ usb_debug("|...................................................|\n");
+ usb_debug("+---------------------------------------------------+\n");
+}
+
+static void
+dump_ed (ed_t *cur)
+{
+ td_t *tmp_td = NULL;
+ usb_debug("+===================================================+\n");
+ usb_debug("| ############# OHCI ED at [0x%08lx] ########### |\n", virt_to_phys(cur));
+ usb_debug("+---------------------------------------------------+\n");
+ usb_debug("| Next Endpoint Descriptor [0x%08lx] |\n", __le32_to_cpu(cur->next_ed) & ~0xFUL);
+ usb_debug("+---------------------------------------------------+\n");
+ usb_debug("| | @ 0x%08x : |\n", __le32_to_cpu(cur->config));
+ usb_debug("| C | Maximum Packet Length | [%04ld] |\n",
+ ((__le32_to_cpu(cur->config) & (0x3fffUL << 16)) >> 16));
+ usb_debug("| O | Function Address | [%04d] |\n",
+ __le32_to_cpu(cur->config) & 0x7F);
+ usb_debug("| N | Endpoint Number | [%02ld] |\n",
+ (__le32_to_cpu(cur->config) & (0xFUL << 7)) >> 7);
+ usb_debug("| F | Endpoint Direction | [%ld] |\n",
+ ((__le32_to_cpu(cur->config) & (3UL << 11)) >> 11));
+ usb_debug("| I | Endpoint Speed | [%ld] |\n",
+ ((__le32_to_cpu(cur->config) & (1UL << 13)) >> 13));
+ usb_debug("| G | Skip | [%ld] |\n",
+ ((__le32_to_cpu(cur->config) & (1UL << 14)) >> 14));
+ usb_debug("| | Format | [%ld] |\n",
+ ((__le32_to_cpu(cur->config) & (1UL << 15)) >> 15));
+ usb_debug("+---------------------------------------------------+\n");
+ usb_debug("| TD Queue Tail Pointer [0x%08lx] |\n",
+ __le32_to_cpu(cur->tail_pointer) & ~0xFUL);
+ usb_debug("+---------------------------------------------------+\n");
+ usb_debug("| TD Queue Head Pointer [0x%08lx] |\n",
+ __le32_to_cpu(cur->head_pointer) & ~0xFUL);
+ usb_debug("| CarryToggleBit [%d] Halted [%d] |\n",
+ (u16)(__le32_to_cpu(cur->head_pointer) & 0x2UL)>>1, (u16)(__le32_to_cpu(cur->head_pointer) & 0x1UL));
+
+ tmp_td = (td_t *)phys_to_virt((__le32_to_cpu(cur->head_pointer) & ~0xFUL));
+ if ((__le32_to_cpu(cur->head_pointer) & ~0xFUL) != (__le32_to_cpu(cur->tail_pointer) & ~0xFUL)) {
+ usb_debug("|:::::::::::::::::: OHCI TD CHAIN ::::::::::::::::::|\n");
+ while (virt_to_phys(tmp_td) != (__le32_to_cpu(cur->tail_pointer) & ~0xFUL))
+ {
+ dump_td(tmp_td);
+ tmp_td = (td_t *)phys_to_virt((__le32_to_cpu(tmp_td->next_td) & ~0xFUL));
+ }
+ usb_debug("|:::::::::::::::: EOF OHCI TD CHAIN ::::::::::::::::|\n");
+ usb_debug("+---------------------------------------------------+\n");
+ } else {
+ usb_debug("+---------------------------------------------------+\n");
+ }
+}
+#endif
+
+static void
+ohci_reset (hci_t *controller)
+{
+ if (controller == NULL)
+ return;
+
+ OHCI_INST(controller)->opreg->HcCommandStatus = __cpu_to_le32(HostControllerReset);
+ mdelay(2); /* wait 2ms */
+ OHCI_INST(controller)->opreg->HcControl = 0;
+ mdelay(10); /* wait 10ms */
+}
+
+static void
+ohci_reinit (hci_t *controller)
+{
+}
+
+hci_t *
+ohci_init (void *bar)
+{
+ int i;
+
+ hci_t *controller = new_controller ();
+
+ if (!controller) {
+ printk("Could not create USB controller instance.\n");
+ return NULL;
+ }
+
+ controller->instance = malloc (sizeof (ohci_t));
+ if(!controller->instance) {
+ printk("Not enough memory creating USB controller instance.\n");
+ return NULL;
+ }
+
+ controller->type = OHCI;
+
+ controller->start = ohci_start;
+ controller->stop = ohci_stop;
+ controller->reset = ohci_reset;
+ controller->init = ohci_reinit;
+ controller->shutdown = ohci_shutdown;
+ controller->bulk = ohci_bulk;
+ controller->control = ohci_control;
+ controller->set_address = generic_set_address;
+ controller->finish_device_config = NULL;
+ controller->destroy_device = NULL;
+ controller->create_intr_queue = ohci_create_intr_queue;
+ controller->destroy_intr_queue = ohci_destroy_intr_queue;
+ controller->poll_intr_queue = ohci_poll_intr_queue;
+ for (i = 0; i < 128; i++) {
+ controller->devices[i] = 0;
+ }
+ init_device_entry (controller, 0);
+ OHCI_INST (controller)->roothub = controller->devices[0];
+
+ controller->reg_base = (u32)(unsigned long)bar;
+ OHCI_INST (controller)->opreg = (opreg_t*)phys_to_virt(controller->reg_base);
+ usb_debug("OHCI Version %x.%x\n",
+ (READ_OPREG(OHCI_INST(controller), HcRevision) >> 4) & 0xf,
+ READ_OPREG(OHCI_INST(controller), HcRevision) & 0xf);
+
+ if ((READ_OPREG(OHCI_INST(controller), HcControl) & HostControllerFunctionalStateMask) == USBReset) {
+ /* cold boot */
+ OHCI_INST (controller)->opreg->HcControl &= __cpu_to_le32(~RemoteWakeupConnected);
+ OHCI_INST (controller)->opreg->HcFmInterval =
+ __cpu_to_le32((11999 * FrameInterval) | ((((11999 - 210)*6)/7) * FSLargestDataPacket));
+ /* TODO: right value for PowerOnToPowerGoodTime ? */
+ OHCI_INST (controller)->opreg->HcRhDescriptorA =
+ __cpu_to_le32(NoPowerSwitching | NoOverCurrentProtection | (10 * PowerOnToPowerGoodTime));
+ OHCI_INST (controller)->opreg->HcRhDescriptorB = __cpu_to_le32(0 * DeviceRemovable);
+ udelay(100); /* TODO: reset asserting according to USB spec */
+ } else if ((READ_OPREG(OHCI_INST(controller), HcControl) & HostControllerFunctionalStateMask) != USBOperational) {
+ OHCI_INST (controller)->opreg->HcControl =
+ __cpu_to_le32((READ_OPREG(OHCI_INST(controller), HcControl) & ~HostControllerFunctionalStateMask)
+ | USBResume);
+ udelay(100); /* TODO: resume time according to USB spec */
+ }
+ int interval = OHCI_INST (controller)->opreg->HcFmInterval;
+
+ OHCI_INST (controller)->opreg->HcCommandStatus = __cpu_to_le32(HostControllerReset);
+ udelay (10); /* at most 10us for reset to complete. State must be set to Operational within 2ms (5.1.1.4) */
+ OHCI_INST (controller)->opreg->HcFmInterval = interval;
+ ofmem_posix_memalign((void **)&(OHCI_INST (controller)->hcca), 256, 256);
+ memset((void*)OHCI_INST (controller)->hcca, 0, 256);
+
+ usb_debug("HCCA addr %p\n", OHCI_INST(controller)->hcca);
+ /* Initialize interrupt table. */
+ u32 *const intr_table = OHCI_INST(controller)->hcca->HccaInterruptTable;
+ ed_t *const periodic_ed;
+ ofmem_posix_memalign((void **)&periodic_ed, sizeof(ed_t), sizeof(ed_t));
+ memset((void *)periodic_ed, 0, sizeof(*periodic_ed));
+ for (i = 0; i < 32; ++i)
+ intr_table[i] = __cpu_to_le32(virt_to_phys(periodic_ed));
+ OHCI_INST (controller)->periodic_ed = periodic_ed;
+
+ OHCI_INST (controller)->opreg->HcHCCA = __cpu_to_le32(virt_to_phys(OHCI_INST(controller)->hcca));
+ /* Make sure periodic schedule is enabled. */
+ OHCI_INST (controller)->opreg->HcControl |= __cpu_to_le32(PeriodicListEnable);
+ OHCI_INST (controller)->opreg->HcControl &= __cpu_to_le32(~IsochronousEnable); // unused by this driver
+ // disable everything, contrary to what OHCI spec says in 5.1.1.4, as we don't need IRQs
+ OHCI_INST (controller)->opreg->HcInterruptEnable = __cpu_to_le32(1<<31);
+ OHCI_INST (controller)->opreg->HcInterruptDisable = __cpu_to_le32(~(1<<31));
+ OHCI_INST (controller)->opreg->HcInterruptStatus = __cpu_to_le32(~0);
+ OHCI_INST (controller)->opreg->HcPeriodicStart =
+ __cpu_to_le32((READ_OPREG(OHCI_INST(controller), HcFmInterval) & FrameIntervalMask) / 10 * 9);
+ OHCI_INST (controller)->opreg->HcControl = __cpu_to_le32((READ_OPREG(OHCI_INST(controller), HcControl)
+ & ~HostControllerFunctionalStateMask) | USBOperational);
+
+ mdelay(100);
+
+ controller->devices[0]->controller = controller;
+ controller->devices[0]->init = ohci_rh_init;
+ controller->devices[0]->init (controller->devices[0]);
+ return controller;
+}
+
+hci_t *
+ohci_pci_init (pci_addr addr)
+{
+ u32 reg_base;
+ uint16_t cmd;
+
+ cmd = pci_config_read16(addr, PCI_COMMAND);
+ cmd |= PCI_COMMAND_BUS_MASTER;
+ pci_config_write16(addr, PCI_COMMAND, cmd);
+
+ /* regarding OHCI spec, Appendix A, BAR_OHCI register description, Table A-4
+ * BASE ADDRESS only [31-12] bits. All other usually 0, but not all.
+ * OHCI mandates MMIO, so bit 0 is clear */
+ reg_base = pci_config_read32 (addr, PCI_BASE_ADDR_0) & 0xfffff000;
+
+ return ohci_init((void *)(unsigned long)reg_base);
+}
+
+static void
+ohci_shutdown (hci_t *controller)
+{
+ if (controller == 0)
+ return;
+ detach_controller (controller);
+ ohci_stop(controller);
+ OHCI_INST (controller)->roothub->destroy (OHCI_INST (controller)->
+ roothub);
+ controller->reset (controller);
+ free ((void *)OHCI_INST (controller)->periodic_ed);
+ free (OHCI_INST (controller));
+ free (controller);
+}
+
+static void
+ohci_start (hci_t *controller)
+{
+// TODO: turn on all operation of OHCI, but assume that it's initialized.
+}
+
+static void
+ohci_stop (hci_t *controller)
+{
+// TODO: turn off all operation of OHCI
+}
+
+static int
+wait_for_ed(usbdev_t *dev, ed_t *head, int pages)
+{
+ usb_debug("Waiting for %d pages on dev %p with head %p\n", pages, dev, head);
+ /* wait for results */
+ /* TOTEST: how long to wait?
+ * give 2s per TD (2 pages) plus another 2s for now
+ */
+ int timeout = pages*1000 + 2000;
+ while (((__le32_to_cpu(head->head_pointer) & ~3) != __le32_to_cpu(head->tail_pointer)) &&
+ !(__le32_to_cpu(head->head_pointer) & 1) &&
+ ((__le32_to_cpu((((td_t*)phys_to_virt(__le32_to_cpu(head->head_pointer) & ~3)))->config)
+ & TD_CC_MASK) >= TD_CC_NOACCESS) && timeout--) {
+ /* don't log every ms */
+ if (!(timeout % 100))
+ usb_debug("intst: %x; ctrl: %x; cmdst: %x; head: %x -> %x, tail: %x, condition: %x\n",
+ READ_OPREG(OHCI_INST(dev->controller), HcInterruptStatus),
+ READ_OPREG(OHCI_INST(dev->controller), HcControl),
+ READ_OPREG(OHCI_INST(dev->controller), HcCommandStatus),
+ __le32_to_cpu(head->head_pointer),
+ __le32_to_cpu(((td_t*)phys_to_virt(__le32_to_cpu(head->head_pointer) & ~3))->next_td),
+ __le32_to_cpu(head->tail_pointer),
+ (__le32_to_cpu(((td_t*)phys_to_virt(__le32_to_cpu(head->head_pointer) & ~3))->config) & TD_CC_MASK) >> TD_CC_SHIFT);
+ mdelay(1);
+ }
+ if (timeout < 0)
+ usb_debug("Error: ohci: endpoint "
+ "descriptor processing timed out.\n");
+ /* Clear the done queue. */
+ ohci_process_done_queue(OHCI_INST(dev->controller), 1);
+
+ if (__le32_to_cpu(head->head_pointer) & 1) {
+ usb_debug("HALTED!\n");
+ return 1;
+ }
+ return 0;
+}
+
+static void
+ohci_free_ed (ed_t *const head)
+{
+ /* In case the transfer canceled, we have to free unprocessed TDs. */
+ while ((__le32_to_cpu(head->head_pointer) & ~0x3) != __le32_to_cpu(head->tail_pointer)) {
+ /* Save current TD pointer. */
+ td_t *const cur_td =
+ (td_t*)phys_to_virt(__le32_to_cpu(head->head_pointer) & ~0x3);
+ /* Advance head pointer. */
+ head->head_pointer = cur_td->next_td;
+ /* Free current TD. */
+ free((void *)cur_td);
+ }
+
+ /* Always free the dummy TD */
+ if ((__le32_to_cpu(head->head_pointer) & ~0x3) == __le32_to_cpu(head->tail_pointer))
+ free(phys_to_virt(__le32_to_cpu(head->head_pointer) & ~0x3));
+ /* and the ED. */
+ free((void *)head);
+}
+
+static int
+ohci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen,
+ unsigned char *data)
+{
+ td_t *cur;
+
+ // pages are specified as 4K in OHCI, so don't use getpagesize()
+ int first_page = (unsigned long)data / 4096;
+ int last_page = (unsigned long)(data+dalen-1)/4096;
+ if (last_page < first_page) last_page = first_page;
+ int pages = (dalen==0)?0:(last_page - first_page + 1);
+
+ /* First TD. */
+ td_t *const first_td;
+ ofmem_posix_memalign((void **)&first_td, sizeof(td_t), sizeof(td_t));
+ memset((void *)first_td, 0, sizeof(*first_td));
+ cur = first_td;
+
+ cur->config = __cpu_to_le32(TD_DIRECTION_SETUP |
+ TD_DELAY_INTERRUPT_NOINTR |
+ TD_TOGGLE_FROM_TD |
+ TD_TOGGLE_DATA0 |
+ TD_CC_NOACCESS);
+ cur->current_buffer_pointer = __cpu_to_le32(virt_to_phys(devreq));
+ cur->buffer_end = __cpu_to_le32(virt_to_phys((char *)devreq + drlen - 1));
+
+ while (pages > 0) {
+ /* One more TD. */
+ td_t *const next;
+ ofmem_posix_memalign((void **)&next, sizeof(td_t), sizeof(td_t));
+ memset((void *)next, 0, sizeof(*next));
+ /* Linked to the previous. */
+ cur->next_td = __cpu_to_le32(virt_to_phys(next));
+ /* Advance to the new TD. */
+ cur = next;
+
+ cur->config = __cpu_to_le32((dir == IN ? TD_DIRECTION_IN : TD_DIRECTION_OUT) |
+ TD_DELAY_INTERRUPT_NOINTR |
+ TD_TOGGLE_FROM_ED |
+ TD_CC_NOACCESS);
+ cur->current_buffer_pointer = __cpu_to_le32(virt_to_phys(data));
+ pages--;
+ int consumed = (4096 - ((unsigned long)data % 4096));
+ if (consumed >= dalen) {
+ // end of data is within same page
+ cur->buffer_end = __cpu_to_le32(virt_to_phys(data + dalen - 1));
+ dalen = 0;
+ /* assert(pages == 0); */
+ } else {
+ dalen -= consumed;
+ data += consumed;
+ pages--;
+ int second_page_size = dalen;
+ if (dalen > 4096) {
+ second_page_size = 4096;
+ }
+ cur->buffer_end = __cpu_to_le32(virt_to_phys(data + second_page_size - 1));
+ dalen -= second_page_size;
+ data += second_page_size;
+ }
+ }
+
+ /* One more TD. */
+ td_t *const next_td;
+ ofmem_posix_memalign((void **)&next_td, sizeof(td_t), sizeof(td_t));
+ memset((void *)next_td, 0, sizeof(*next_td));
+ /* Linked to the previous. */
+ cur->next_td = __cpu_to_le32(virt_to_phys(next_td));
+ /* Advance to the new TD. */
+ cur = next_td;
+ cur->config = __cpu_to_le32((dir == IN ? TD_DIRECTION_OUT : TD_DIRECTION_IN) |
+ TD_DELAY_INTERRUPT_ZERO | /* Write done head after this TD. */
+ TD_TOGGLE_FROM_TD |
+ TD_TOGGLE_DATA1 |
+ TD_CC_NOACCESS);
+ cur->current_buffer_pointer = 0;
+ cur->buffer_end = 0;
+
+ /* Final dummy TD. */
+ td_t *const final_td;
+ ofmem_posix_memalign((void **)&final_td, sizeof(td_t), sizeof(td_t));
+ memset((void *)final_td, 0, sizeof(*final_td));
+ /* Linked to the previous. */
+ cur->next_td = __cpu_to_le32(virt_to_phys(final_td));
+
+ /* Data structures */
+ ed_t *head;
+ ofmem_posix_memalign((void **)&head, sizeof(ed_t), sizeof(ed_t));
+ memset((void*)head, 0, sizeof(*head));
+ head->config = __cpu_to_le32((dev->address << ED_FUNC_SHIFT) |
+ (0 << ED_EP_SHIFT) |
+ (OHCI_FROM_TD << ED_DIR_SHIFT) |
+ (dev->speed?ED_LOWSPEED:0) |
+ (dev->endpoints[0].maxpacketsize << ED_MPS_SHIFT));
+ head->tail_pointer = __cpu_to_le32(virt_to_phys(final_td));
+ head->head_pointer = __cpu_to_le32(virt_to_phys(first_td));
+
+ usb_debug("ohci_control(): doing transfer with %x. first_td at %x\n",
+ __le32_to_cpu(head->config) & ED_FUNC_MASK, __le32_to_cpu(head->head_pointer));
+#ifdef USB_DEBUG_ED
+ dump_ed(head);
+#endif
+
+ /* activate schedule */
+ OHCI_INST(dev->controller)->opreg->HcControlHeadED = __cpu_to_le32(virt_to_phys(head));
+ OHCI_INST(dev->controller)->opreg->HcControl |= __cpu_to_le32(ControlListEnable);
+ OHCI_INST(dev->controller)->opreg->HcCommandStatus = __cpu_to_le32(ControlListFilled);
+
+ int failure = wait_for_ed(dev, head,
+ (dalen==0)?0:(last_page - first_page + 1));
+ /* Wait some frames before and one after disabling list access. */
+ mdelay(4);
+ OHCI_INST(dev->controller)->opreg->HcControl &= __cpu_to_le32(~ControlListEnable);
+ mdelay(1);
+
+ /* free memory */
+ ohci_free_ed(head);
+
+ return failure;
+}
+
+/* finalize == 1: if data is of packet aligned size, add a zero length packet */
+static int
+ohci_bulk (endpoint_t *ep, int dalen, u8 *data, int finalize)
+{
+ int i;
+ usb_debug("bulk: %x bytes from %p, finalize: %x, maxpacketsize: %x\n", dalen, data, finalize, ep->maxpacketsize);
+
+ td_t *cur, *next;
+
+ // pages are specified as 4K in OHCI, so don't use getpagesize()
+ int first_page = (unsigned long)data / 4096;
+ int last_page = (unsigned long)(data+dalen-1)/4096;
+ if (last_page < first_page) last_page = first_page;
+ int pages = (dalen==0)?0:(last_page - first_page + 1);
+ int td_count = (pages+1)/2;
+
+ if (finalize && ((dalen % ep->maxpacketsize) == 0)) {
+ td_count++;
+ }
+
+ /* First TD. */
+ td_t *const first_td;
+ ofmem_posix_memalign((void **)&first_td, sizeof(td_t), sizeof(td_t));
+ memset((void *)first_td, 0, sizeof(*first_td));
+ cur = next = first_td;
+
+ for (i = 0; i < td_count; ++i) {
+ /* Advance to next TD. */
+ cur = next;
+ cur->config = __cpu_to_le32((ep->direction == IN ? TD_DIRECTION_IN : TD_DIRECTION_OUT) |
+ TD_DELAY_INTERRUPT_NOINTR |
+ TD_TOGGLE_FROM_ED |
+ TD_CC_NOACCESS);
+ cur->current_buffer_pointer = __cpu_to_le32(virt_to_phys(data));
+ pages--;
+ if (dalen == 0) {
+ /* magic TD for empty packet transfer */
+ cur->current_buffer_pointer = 0;
+ cur->buffer_end = 0;
+ /* assert((pages == 0) && finalize); */
+ }
+ int consumed = (4096 - ((unsigned long)data % 4096));
+ if (consumed >= dalen) {
+ // end of data is within same page
+ cur->buffer_end = __cpu_to_le32(virt_to_phys(data + dalen - 1));
+ dalen = 0;
+ /* assert(pages == finalize); */
+ } else {
+ dalen -= consumed;
+ data += consumed;
+ pages--;
+ int second_page_size = dalen;
+ if (dalen > 4096) {
+ second_page_size = 4096;
+ }
+ cur->buffer_end = __cpu_to_le32(virt_to_phys(data + second_page_size - 1));
+ dalen -= second_page_size;
+ data += second_page_size;
+ }
+ /* One more TD. */
+ ofmem_posix_memalign((void **)&next, sizeof(td_t), sizeof(td_t));
+ memset((void *)next, 0, sizeof(*next));
+ /* Linked to the previous. */
+ cur->next_td = __cpu_to_le32(virt_to_phys(next));
+ }
+
+ /* Write done head after last TD. */
+ cur->config &= __cpu_to_le32(~TD_DELAY_INTERRUPT_MASK);
+ /* Advance to final, dummy TD. */
+ cur = next;
+
+ /* Data structures */
+ ed_t *head;
+ ofmem_posix_memalign((void **)&head, sizeof(ed_t), sizeof(ed_t));
+ memset((void*)head, 0, sizeof(*head));
+ head->config = __cpu_to_le32((ep->dev->address << ED_FUNC_SHIFT) |
+ ((ep->endpoint & 0xf) << ED_EP_SHIFT) |
+ (((ep->direction==IN)?OHCI_IN:OHCI_OUT) << ED_DIR_SHIFT) |
+ (ep->dev->speed?ED_LOWSPEED:0) |
+ (ep->maxpacketsize << ED_MPS_SHIFT));
+ head->tail_pointer = __cpu_to_le32(virt_to_phys(cur));
+ head->head_pointer = __cpu_to_le32(virt_to_phys(first_td) | (ep->toggle?ED_TOGGLE:0));
+
+ usb_debug("doing bulk transfer with %x(%x). first_td at %lx, last %lx\n",
+ __le32_to_cpu(head->config) & ED_FUNC_MASK,
+ (__le32_to_cpu(head->config) & ED_EP_MASK) >> ED_EP_SHIFT,
+ virt_to_phys(first_td), virt_to_phys(cur));
+
+ /* activate schedule */
+ OHCI_INST(ep->dev->controller)->opreg->HcBulkHeadED = __cpu_to_le32(virt_to_phys(head));
+ OHCI_INST(ep->dev->controller)->opreg->HcControl |= __cpu_to_le32(BulkListEnable);
+ OHCI_INST(ep->dev->controller)->opreg->HcCommandStatus = __cpu_to_le32(BulkListFilled);
+
+ int failure = wait_for_ed(ep->dev, head,
+ (dalen==0)?0:(last_page - first_page + 1));
+ /* Wait some frames before and one after disabling list access. */
+ mdelay(4);
+ OHCI_INST(ep->dev->controller)->opreg->HcControl &= __cpu_to_le32(~BulkListEnable);
+ mdelay(1);
+
+ ep->toggle = __le32_to_cpu(head->head_pointer) & ED_TOGGLE;
+
+ /* free memory */
+ ohci_free_ed(head);
+
+ if (failure) {
+ /* try cleanup */
+ clear_stall(ep);
+ }
+
+ return failure;
+}
+
+
+struct _intr_queue;
+
+struct _intrq_td {
+ volatile td_t td;
+ u8 *data;
+ struct _intrq_td *next;
+ struct _intr_queue *intrq;
+};
+
+struct _intr_queue {
+ volatile ed_t ed;
+ struct _intrq_td *head;
+ struct _intrq_td *tail;
+ u8 *data;
+ int reqsize;
+ endpoint_t *endp;
+ unsigned int remaining_tds;
+ int destroy;
+};
+
+typedef struct _intrq_td intrq_td_t;
+typedef struct _intr_queue intr_queue_t;
+
+#define INTRQ_TD_FROM_TD(x) ((intrq_td_t *)x)
+
+static void
+ohci_fill_intrq_td(intrq_td_t *const td, intr_queue_t *const intrq,
+ u8 *const data)
+{
+ memset(td, 0, sizeof(*td));
+ td->td.config = __cpu_to_le32(TD_QUEUETYPE_INTR |
+ (intrq->endp->direction == IN ? TD_DIRECTION_IN : TD_DIRECTION_OUT) |
+ TD_DELAY_INTERRUPT_ZERO |
+ TD_TOGGLE_FROM_ED |
+ TD_CC_NOACCESS);
+ td->td.current_buffer_pointer = __cpu_to_le32(virt_to_phys(data));
+ td->td.buffer_end = __cpu_to_le32(virt_to_phys(data) + intrq->reqsize - 1);
+ td->intrq = intrq;
+ td->data = data;
+}
+
+/* create and hook-up an intr queue into device schedule */
+static void *
+ohci_create_intr_queue(endpoint_t *const ep, const int reqsize,
+ const int reqcount, const int reqtiming)
+{
+ int i;
+ intrq_td_t *first_td = NULL, *last_td = NULL;
+
+ if (reqsize > 4096)
+ return NULL;
+
+ intr_queue_t *const intrq;
+ ofmem_posix_memalign((void **)&intrq, sizeof(intrq->ed), sizeof(*intrq));
+ memset(intrq, 0, sizeof(*intrq));
+ intrq->data = (u8 *)malloc(reqcount * reqsize);
+ intrq->reqsize = reqsize;
+ intrq->endp = ep;
+
+ /* Create #reqcount TDs. */
+ u8 *cur_data = intrq->data;
+ for (i = 0; i < reqcount; ++i) {
+ intrq_td_t *const td;
+ ofmem_posix_memalign((void **)&td, sizeof(td->td), sizeof(*td));
+ ++intrq->remaining_tds;
+ ohci_fill_intrq_td(td, intrq, cur_data);
+ cur_data += reqsize;
+ if (!first_td)
+ first_td = td;
+ else
+ last_td->td.next_td = __cpu_to_le32(virt_to_phys(&td->td));
+ last_td = td;
+ }
+
+ /* Create last, dummy TD. */
+ intrq_td_t *dummy_td;
+ ofmem_posix_memalign((void **)&dummy_td, sizeof(dummy_td->td), sizeof(*dummy_td));
+ memset(dummy_td, 0, sizeof(*dummy_td));
+ dummy_td->intrq = intrq;
+ if (last_td)
+ last_td->td.next_td = __cpu_to_le32(virt_to_phys(&dummy_td->td));
+ last_td = dummy_td;
+
+ /* Initialize ED. */
+ intrq->ed.config = __cpu_to_le32((ep->dev->address << ED_FUNC_SHIFT) |
+ ((ep->endpoint & 0xf) << ED_EP_SHIFT) |
+ (((ep->direction == IN) ? OHCI_IN : OHCI_OUT) << ED_DIR_SHIFT) |
+ (ep->dev->speed ? ED_LOWSPEED : 0) |
+ (ep->maxpacketsize << ED_MPS_SHIFT));
+ intrq->ed.tail_pointer = __cpu_to_le32(virt_to_phys(last_td));
+ intrq->ed.head_pointer = __cpu_to_le32(virt_to_phys(first_td) | (ep->toggle ? ED_TOGGLE : 0));
+
+#ifdef USB_DEBUG_ED
+ dump_ed(&intrq->ed);
+#endif
+ /* Insert ED into periodic table. */
+ int nothing_placed = 1;
+ ohci_t *const ohci = OHCI_INST(ep->dev->controller);
+ u32 *const intr_table = ohci->hcca->HccaInterruptTable;
+ const u32 dummy_ptr = __cpu_to_le32(virt_to_phys(ohci->periodic_ed));
+ for (i = 0; i < 32; i += reqtiming) {
+ /* Advance to the next free position. */
+ while ((i < 32) && (intr_table[i] != dummy_ptr)) ++i;
+ if (i < 32) {
+ usb_debug("Placed endpoint %lx to %d\n", virt_to_phys(&intrq->ed), i);
+ intr_table[i] = __cpu_to_le32(virt_to_phys(&intrq->ed));
+ nothing_placed = 0;
+ }
+ }
+ if (nothing_placed) {
+ usb_debug("Error: Failed to place ohci interrupt endpoint "
+ "descriptor into periodic table: no space left\n");
+ ohci_destroy_intr_queue(ep, intrq);
+ return NULL;
+ }
+
+ return intrq;
+}
+
+/* remove queue from device schedule, dropping all data that came in */
+static void
+ohci_destroy_intr_queue(endpoint_t *const ep, void *const q_)
+{
+ intr_queue_t *const intrq = (intr_queue_t *)q_;
+
+ int i;
+
+ /* Remove interrupt queue from periodic table. */
+ ohci_t *const ohci = OHCI_INST(ep->dev->controller);
+ u32 *const intr_table = ohci->hcca->HccaInterruptTable;
+ for (i=0; i < 32; ++i) {
+ if (intr_table[i] == __cpu_to_le32(virt_to_phys(intrq)))
+ intr_table[i] = __cpu_to_le32(virt_to_phys(ohci->periodic_ed));
+ }
+ /* Wait for frame to finish. */
+ mdelay(1);
+
+ /* Free unprocessed TDs. */
+ while ((__le32_to_cpu(intrq->ed.head_pointer) & ~0x3) != __le32_to_cpu(intrq->ed.tail_pointer)) {
+ td_t *const cur_td = (td_t *)phys_to_virt(__le32_to_cpu(intrq->ed.head_pointer) & ~0x3);
+ intrq->ed.head_pointer = cur_td->next_td;
+ free(INTRQ_TD_FROM_TD(cur_td));
+ --intrq->remaining_tds;
+ }
+ /* Free final, dummy TD. */
+ free(phys_to_virt(__le32_to_cpu(intrq->ed.head_pointer) & ~0x3));
+ /* Free data buffer. */
+ free(intrq->data);
+
+ /* Free TDs already fetched from the done queue. */
+ ohci_process_done_queue(ohci, 1);
+ while (intrq->head) {
+ intrq_td_t *const cur_td = (intrq_td_t *const )__le32_to_cpu(intrq->head);
+ intrq->head = intrq->head->next;
+ free(cur_td);
+ --intrq->remaining_tds;
+ }
+
+ /* Mark interrupt queue to be destroyed.
+ ohci_process_done_queue() will free the remaining TDs
+ and finish the interrupt queue off once all TDs are gone. */
+ intrq->destroy = 1;
+
+ /* Save data toggle. */
+ ep->toggle = __le32_to_cpu(intrq->ed.head_pointer) & ED_TOGGLE;
+}
+
+/* read one intr-packet from queue, if available. extend the queue for new input.
+ return NULL if nothing new available.
+ Recommended use: while (data=poll_intr_queue(q)) process(data);
+ */
+static u8 *
+ohci_poll_intr_queue(void *const q_)
+{
+ intr_queue_t *const intrq = (intr_queue_t *)q_;
+
+ u8 *data = NULL;
+
+ /* Process done queue first, then check if we have work to do. */
+ ohci_process_done_queue(OHCI_INST(intrq->endp->dev->controller), 0);
+
+ if (intrq->head) {
+ /* Save pointer to processed TD and advance. */
+ intrq_td_t *const cur_td = intrq->head;
+ intrq->head = cur_td->next;
+
+ /* Return data buffer of this TD. */
+ data = cur_td->data;
+
+ /* Requeue this TD (i.e. copy to dummy and requeue as dummy). */
+ intrq_td_t *const dummy_td =
+ INTRQ_TD_FROM_TD(phys_to_virt(__le32_to_cpu(intrq->ed.tail_pointer)));
+ ohci_fill_intrq_td(dummy_td, intrq, data);
+ /* Reset all but intrq pointer (i.e. init as dummy). */
+ memset(cur_td, 0, sizeof(*cur_td));
+ cur_td->intrq = intrq;
+ /* Insert into interrupt queue as dummy. */
+ dummy_td->td.next_td = __le32_to_cpu(virt_to_phys(&cur_td->td));
+ intrq->ed.tail_pointer = __le32_to_cpu(virt_to_phys(&cur_td->td));
+ }
+
+ return data;
+}
+
+static void
+ohci_process_done_queue(ohci_t *const ohci, const int spew_debug)
+{
+ int i, j;
+
+ /* Temporary queue of interrupt queue TDs (to reverse order). */
+ intrq_td_t *temp_tdq = NULL;
+
+ /* Check if done head has been written. */
+ if (!(READ_OPREG(ohci, HcInterruptStatus) & WritebackDoneHead))
+ return;
+ /* Fetch current done head.
+ Lsb is only interesting for hw interrupts. */
+ u32 phys_done_queue = __le32_to_cpu(ohci->hcca->HccaDoneHead) & ~1;
+ /* Tell host controller, he may overwrite the done head pointer. */
+ ohci->opreg->HcInterruptStatus = __cpu_to_le32(WritebackDoneHead);
+
+ i = 0;
+ /* Process done queue (it's in reversed order). */
+ while (phys_done_queue) {
+ td_t *const done_td = (td_t *)phys_to_virt(phys_done_queue);
+
+ /* Advance pointer to next TD. */
+ phys_done_queue = __le32_to_cpu(done_td->next_td);
+
+ switch (__le32_to_cpu(done_td->config) & TD_QUEUETYPE_MASK) {
+ case TD_QUEUETYPE_ASYNC:
+ /* Free processed async TDs. */
+ free((void *)done_td);
+ break;
+ case TD_QUEUETYPE_INTR: {
+ intrq_td_t *const td = INTRQ_TD_FROM_TD(done_td);
+ intr_queue_t *const intrq = td->intrq;
+ /* Check if the corresponding interrupt
+ queue is still beeing processed. */
+ if (intrq->destroy) {
+ /* Free this TD, and */
+ free(td);
+ --intrq->remaining_tds;
+ /* the interrupt queue if it has no more TDs. */
+ if (!intrq->remaining_tds)
+ free(intrq);
+ usb_debug("Freed TD from orphaned interrupt "
+ "queue, %d TDs remain.\n",
+ intrq->remaining_tds);
+ } else {
+ /* Save done TD to be processed. */
+ td->next = temp_tdq;
+ temp_tdq = td;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ ++i;
+ }
+ if (spew_debug)
+ usb_debug("Processed %d done TDs.\n", i);
+
+ j = 0;
+ /* Process interrupt queue TDs in right order. */
+ while (temp_tdq) {
+ /* Save pointer of current TD and advance. */
+ intrq_td_t *const cur_td = temp_tdq;
+ temp_tdq = temp_tdq->next;
+
+ /* The interrupt queue for the current TD. */
+ intr_queue_t *const intrq = cur_td->intrq;
+ /* Append to interrupt queue. */
+ if (!intrq->head) {
+ /* First element. */
+ intrq->head = intrq->tail = cur_td;
+ } else {
+ /* Insert at tail. */
+ intrq->tail->next = cur_td;
+ intrq->tail = cur_td;
+ }
+ /* It's always the last element. */
+ cur_td->next = NULL;
+ ++j;
+ }
+ if (spew_debug)
+ usb_debug("processed %d done tds, %d intr tds thereof.\n", i, j);
+}
+
+int ob_usb_ohci_init (const char *path, uint32_t addr)
+{
+ hci_t *ctrl;
+ int i;
+
+ usb_debug("ohci_init: %s addr = %x\n", path, addr);
+ ctrl = ohci_pci_init(addr);
+ if (!ctrl)
+ return 0;
+
+ /* Init ports */
+ usb_poll();
+
+ /* Look for a keyboard */
+ for (i = 0; i < 128; i++) {
+ if (ctrl->devices[i] && ctrl->devices[i]->configuration) {
+ configuration_descriptor_t *cd;
+ interface_descriptor_t *intf;
+
+ cd = (configuration_descriptor_t *)ctrl->devices[i]->configuration;
+ intf = (interface_descriptor_t *)(ctrl->devices[i]->configuration + cd->bLength);
+ usb_debug("Device at port %d is class %d\n", i, intf->bInterfaceClass);
+ if (intf->bInterfaceClass == hid_device &&
+ intf->bInterfaceSubClass == hid_subclass_boot &&
+ intf->bInterfaceProtocol == hid_boot_proto_keyboard ) {
+ break;
+ }
+ }
+ }
+ if ( i < 128 )
+ ob_usb_hid_add_keyboard(path);
+
+ return 1;
+}
Added: trunk/openbios-devel/drivers/usbohci.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usbohci.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,45 @@
+/*
+ * Driver for USB OHCI ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2010 Patrick Georgi
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __OHCI_H
+#define __OHCI_H
+
+#include "config.h"
+#include "usbohci_private.h"
+
+hci_t *ohci_pci_init (u32 addr);
+hci_t *ohci_init (void *bar);
+
+void ohci_rh_init (usbdev_t *dev);
+
+#endif
Added: trunk/openbios-devel/drivers/usbohci_private.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usbohci_private.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,270 @@
+/*
+ * Driver for USB OHCI ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2010 Patrick Georgi
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __OHCI_PRIVATE_H
+#define __OHCI_PRIVATE_H
+
+#include "libc/byteorder.h"
+#include "usb.h"
+
+#define READ_OPREG(ohci, field) (__le32_to_cpu((ohci)->opreg->field))
+#define MASK(startbit, lenbit) (((1<<(lenbit))-1)<<(startbit))
+
+ // FIXME: fake
+ typedef enum { CMD} reg;
+
+ enum {
+ NumberDownstreamPorts = 1<<0,
+ PowerSwitchingMode = 1<<8,
+ NoPowerSwitching = 1<<9,
+ DeviceType = 1<<10,
+ OverCurrentProtectionMode = 1<<11,
+ NoOverCurrentProtection = 1<<12,
+ PowerOnToPowerGoodTime = 1<<24
+ } HcRhDescriptorAReg;
+
+ enum {
+ NumberDownstreamPortsMask = MASK(0, 8),
+ PowerOnToPowerGoodTimeMask = MASK(24, 8)
+ } HcRhDescriptorAMask;
+
+ enum {
+ DeviceRemovable = 1<<0,
+ PortPowerControlMask = 1<<16
+ } HcRhDescriptorBReg;
+
+ enum {
+ CurrentConnectStatus = 1<<0,
+ PortEnableStatus = 1<<1,
+ PortSuspendStatus = 1<<2,
+ PortOverCurrentIndicator = 1<<3,
+ PortResetStatus = 1<<4,
+ PortPowerStatus = 1<<8,
+ LowSpeedDeviceAttached = 1<<9,
+ ConnectStatusChange = 1<<16,
+ PortEnableStatusChange = 1<<17,
+ PortSuspendStatusChange = 1<<18,
+ PortOverCurrentIndicatorChange = 1<<19,
+ PortResetStatusChange = 1<<20
+ } HcRhPortStatusRead;
+ enum {
+ ClearPortEnable = 1<<0,
+ SetPortEnable = 1<<1,
+ SetPortSuspend = 1<<2,
+ ClearSuspendStatus = 1<<3,
+ SetPortReset = 1<<4,
+ SetPortPower = 1<<8,
+ ClearPortPower = 1<<9,
+ } HcRhPortStatusSet;
+
+ enum {
+ LocalPowerStatus = 1<<0,
+ OverCurrentIndicator = 1<<1,
+ DeviceRemoteWakeupEnable = 1<<15,
+ LocalPowerStatusChange = 1<<16,
+ OverCurrentIndicatorChange = 1<<17,
+ ClearRemoteWakeupEnable = 1<<31
+ } HcRhStatusReg;
+
+ enum {
+ FrameInterval = 1<<0,
+ FSLargestDataPacket = 1<<16,
+ FrameIntervalToggle = 1<<31
+ } HcFmIntervalOffset;
+ enum {
+ FrameIntervalMask = MASK(0, 14),
+ FSLargestDataPacketMask = MASK(16, 15),
+ FrameIntervalToggleMask = MASK(31, 1)
+ } HcFmIntervalMask;
+
+ enum {
+ ControlBulkServiceRatio = 1<<0,
+ PeriodicListEnable = 1<<2,
+ IsochronousEnable = 1<<3,
+ ControlListEnable = 1<<4,
+ BulkListEnable = 1<<5,
+ HostControllerFunctionalState = 1<<6,
+ InterruptRouting = 1<<8,
+ RemoteWakeupConnected = 1<<9,
+ RemoteWakeupEnable = 1<<10
+ } HcControlReg;
+
+ enum {
+ ControlBulkServiceRatioMask = MASK(0, 2),
+ HostControllerFunctionalStateMask = MASK(6, 2)
+ } HcControlMask;
+
+ enum {
+ USBReset = 0*HostControllerFunctionalState,
+ USBResume = 1*HostControllerFunctionalState,
+ USBOperational = 2*HostControllerFunctionalState,
+ USBSuspend = 3*HostControllerFunctionalState
+ };
+
+ enum {
+ HostControllerReset = 1<<0,
+ ControlListFilled = 1<<1,
+ BulkListFilled = 1<<2,
+ OwnershipChangeRequest = 1<<3,
+ SchedulingOverrunCount = 1<<16
+ } HcCommandStatusReg;
+
+ enum {
+ SchedulingOverrunCountMask = MASK(16, 2)
+ } HcCommandStatusMask;
+
+ enum {
+ FrameRemaining = 1<<0,
+ FrameRemainingToggle = 1<<31
+ } HcFmRemainingReg;
+
+ enum {
+ SchedulingOverrung = 1<<0,
+ WritebackDoneHead = 1<<1,
+ StartofFrame = 1<<2,
+ ResumeDetected = 1<<3,
+ UnrecoverableError = 1<<4,
+ FrameNumberOverflow = 1<<5,
+ RootHubStatusChange = 1<<6,
+ OwnershipChange = 1<<30
+ } HcInterruptStatusReg;
+
+ typedef struct {
+ // Control and Status Partition
+ volatile u32 HcRevision;
+ volatile u32 HcControl;
+ volatile u32 HcCommandStatus;
+ volatile u32 HcInterruptStatus;
+ volatile u32 HcInterruptEnable;
+ volatile u32 HcInterruptDisable;
+
+ // Memory Pointer Partition
+ volatile u32 HcHCCA;
+ volatile u32 HcPeriodCurrentED;
+ volatile u32 HcControlHeadED;
+ volatile u32 HcControlCurrentED;
+ volatile u32 HcBulkHeadED;
+ volatile u32 HcBulkCurrentED;
+ volatile u32 HcDoneHead;
+
+ // Frame Counter Partition
+ volatile u32 HcFmInterval;
+ volatile u32 HcFmRemaining;
+ volatile u32 HcFmNumber;
+ volatile u32 HcPeriodicStart;
+ volatile u32 HcLSThreshold;
+
+ // Root Hub Partition
+ volatile u32 HcRhDescriptorA;
+ volatile u32 HcRhDescriptorB;
+ volatile u32 HcRhStatus;
+ /* all bits in HcRhPortStatus registers are R/WC, so
+ _DO NOT_ use |= to set the bits,
+ this clears the entire state */
+ volatile u32 HcRhPortStatus[];
+ } __attribute__ ((packed)) opreg_t;
+
+ typedef struct { /* should be 256 bytes according to spec */
+ u32 HccaInterruptTable[32];
+ volatile u16 HccaFrameNumber;
+ volatile u16 HccaPad1;
+ volatile u32 HccaDoneHead;
+ u8 reserved[116]; /* pad according to spec */
+ u8 what[4]; /* really pad to 256 as spec only covers 252 */
+ } __attribute__ ((packed)) hcca_t;
+
+ typedef volatile struct {
+ u32 config;
+ u32 tail_pointer;
+ u32 head_pointer;
+ u32 next_ed;
+ } __attribute__ ((packed)) ed_t;
+#define ED_HALTED 1
+#define ED_TOGGLE 2
+
+#define ED_FUNC_SHIFT 0
+#define ED_FUNC_MASK MASK(0, 7)
+#define ED_EP_SHIFT 7
+#define ED_EP_MASK MASK(7, 4)
+#define ED_DIR_SHIFT 11
+#define ED_DIR_MASK MASK(11, 2)
+#define ED_LOWSPEED (1 << 13)
+#define ED_MPS_SHIFT 16
+
+ typedef volatile struct {
+ u32 config;
+ u32 current_buffer_pointer;
+ u32 next_td;
+ u32 buffer_end;
+ } __attribute__ ((packed)) td_t;
+/*
+ * Bits 0 through 17 of .config won't be interpreted by the host controller
+ * (HC) and, after processing the TD, the HC has to ensure those bits have
+ * the same state as before. So we are free to use those bits for our own
+ * purpose.
+ */
+#define TD_QUEUETYPE_SHIFT 0
+#define TD_QUEUETYPE_MASK MASK(TD_QUEUETYPE_SHIFT, 2)
+#define TD_QUEUETYPE_ASYNC (0 << TD_QUEUETYPE_SHIFT)
+#define TD_QUEUETYPE_INTR (1 << TD_QUEUETYPE_SHIFT)
+
+#define TD_DIRECTION_SHIFT 19
+#define TD_DIRECTION_MASK MASK(TD_DIRECTION_SHIFT, 2)
+#define TD_DIRECTION_SETUP OHCI_SETUP << TD_DIRECTION_SHIFT
+#define TD_DIRECTION_IN OHCI_IN << TD_DIRECTION_SHIFT
+#define TD_DIRECTION_OUT OHCI_OUT << TD_DIRECTION_SHIFT
+#define TD_DELAY_INTERRUPT_SHIFT 21
+#define TD_DELAY_INTERRUPT_MASK MASK(TD_DELAY_INTERRUPT_SHIFT, 3)
+#define TD_DELAY_INTERRUPT_ZERO 0
+#define TD_DELAY_INTERRUPT_NOINTR (7 << TD_DELAY_INTERRUPT_SHIFT)
+#define TD_TOGGLE_DATA0 0
+#define TD_TOGGLE_DATA1 (1 << 24)
+#define TD_TOGGLE_FROM_ED 0
+#define TD_TOGGLE_FROM_TD (1 << 25)
+#define TD_CC_SHIFT 28
+#define TD_CC_MASK MASK(TD_CC_SHIFT, 4)
+#define TD_CC_NOERR 0
+#define TD_CC_NOACCESS (14 << TD_CC_SHIFT) /* the lower of the two values, so "no access" can be tested with >= */
+
+#define OHCI_INST(controller) ((ohci_t*)((controller)->instance))
+
+ typedef struct ohci {
+ opreg_t *opreg;
+ hcca_t *hcca;
+ usbdev_t *roothub;
+ ed_t *periodic_ed;
+ } ohci_t;
+
+ typedef enum { OHCI_SETUP=0, OHCI_OUT=1, OHCI_IN=2, OHCI_FROM_TD=3 } ohci_pid_t;
+
+#endif
Added: trunk/openbios-devel/drivers/usbohci_rh.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/drivers/usbohci_rh.c Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,212 @@
+/*
+ * Driver for USB OHCI Root Hubs ported from CoreBoot
+ *
+ * Copyright (C) 2014 BALATON Zoltan
+ *
+ * This file was part of the libpayload project.
+ *
+ * Copyright (C) 2010 Patrick Georgi
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "timer.h"
+#include "usbohci_private.h"
+#include "usbohci.h"
+
+typedef struct {
+ int numports;
+ int *port;
+} rh_inst_t;
+
+#define RH_INST(dev) ((rh_inst_t*)(dev)->data)
+
+static void
+ohci_rh_enable_port (usbdev_t *dev, int port)
+{
+ /* Reset RH port should hold 50ms with pulses of at least 10ms and
+ * gaps of at most 3ms (usb20 spec 7.1.7.5).
+ * After reset, the port will be enabled automatically (ohci spec
+ * 7.4.4).
+ */
+ int total_delay = 100; /* 100 * 500us == 50ms */
+ while (total_delay > 0) {
+ if (!(READ_OPREG(OHCI_INST(dev->controller), HcRhPortStatus[port])
+ & CurrentConnectStatus))
+ return;
+
+ /* start reset */
+ OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] =
+ __cpu_to_le32(SetPortReset);
+ int timeout = 200; /* timeout after 200 * 500us == 100ms */
+ while ((READ_OPREG(OHCI_INST(dev->controller), HcRhPortStatus[port])
+ & PortResetStatus)
+ && timeout--) {
+ udelay(500); total_delay--;
+ }
+ if (READ_OPREG(OHCI_INST(dev->controller), HcRhPortStatus[port])
+ & PortResetStatus) {
+ usb_debug("Warning: root-hub port reset timed out.\n");
+ break;
+ }
+ if ((200-timeout) < 20) {
+ usb_debug("Warning: port reset too short: %dms; "
+ "should be at least 10ms.\n",
+ (200-timeout)/2);
+ total_delay = 0; /* can happen on QEMU */
+ }
+ /* clear reset status change */
+ OHCI_INST(dev->controller)->opreg->HcRhPortStatus[port] =
+ __cpu_to_le32(PortResetStatusChange);
+ usb_debug ("rh port reset finished after %dms.\n", (200-timeout)/2);
+ }
+}
+
+/* disable root hub */
+static void
+ohci_rh_disable_port (usbdev_t *dev, int port)
+{
+ OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] =
+ __cpu_to_le32(ClearPortEnable); // disable port
+ int timeout = 50; /* timeout after 50 * 100us == 5ms */
+ while ((READ_OPREG(OHCI_INST (dev->controller), HcRhPortStatus[port])
+ & PortEnableStatus)
+ && timeout--) {
+ udelay(100);
+ }
+}
+
+static void
+ohci_rh_scanport (usbdev_t *dev, int port)
+{
+ if (port >= RH_INST(dev)->numports) {
+ usb_debug("Invalid port %d\n", port);
+ return;
+ }
+
+ /* device registered, and device change logged, so something must have happened */
+ if (RH_INST (dev)->port[port] != -1) {
+ usb_detach_device(dev->controller, RH_INST (dev)->port[port]);
+ RH_INST (dev)->port[port] = -1;
+ }
+
+ /* no device attached
+ previously registered devices are detached, nothing left to do */
+ if (!(READ_OPREG(OHCI_INST(dev->controller), HcRhPortStatus[port]) & CurrentConnectStatus))
+ return;
+
+ // clear port state change
+ OHCI_INST(dev->controller)->opreg->HcRhPortStatus[port] = __cpu_to_le32(ConnectStatusChange);
+ ohci_rh_enable_port (dev, port);
+
+ mdelay(100); // wait for signal to stabilize
+
+ if (!(READ_OPREG(OHCI_INST(dev->controller), HcRhPortStatus[port]) & PortEnableStatus)) {
+ usb_debug ("port enable failed\n");
+ return;
+ }
+
+ int speed = (READ_OPREG(OHCI_INST(dev->controller), HcRhPortStatus[port]) & LowSpeedDeviceAttached) != 0;
+ RH_INST (dev)->port[port] = usb_attach_device(dev->controller, dev->address, port, speed);
+}
+
+static int
+ohci_rh_report_port_changes (usbdev_t *dev)
+{
+ ohci_t *const ohcic = OHCI_INST (dev->controller);
+
+ int i;
+
+ for (i = 0; i < RH_INST(dev)->numports; i++) {
+ // maybe detach+attach happened between two scans?
+ if (READ_OPREG(ohcic, HcRhPortStatus[i]) & ConnectStatusChange) {
+ ohcic->opreg->HcRhPortStatus[i] = __cpu_to_le32(ConnectStatusChange);
+ usb_debug("attachment change on port %d\n", i);
+ return i;
+ }
+ }
+
+ // no change
+ return -1;
+}
+
+static void
+ohci_rh_destroy (usbdev_t *dev)
+{
+ int i;
+ for (i = 0; i < RH_INST (dev)->numports; i++)
+ ohci_rh_disable_port (dev, i);
+ free (RH_INST (dev));
+}
+
+static void
+ohci_rh_poll (usbdev_t *dev)
+{
+ ohci_t *const ohcic = OHCI_INST (dev->controller);
+
+ int port;
+
+ /* Check if anything changed. */
+ if (!(READ_OPREG(ohcic, HcInterruptStatus) & RootHubStatusChange))
+ return;
+ ohcic->opreg->HcInterruptStatus = __cpu_to_le32(RootHubStatusChange);
+ usb_debug("root hub status change\n");
+
+ /* Scan ports with changed connection status. */
+ while ((port = ohci_rh_report_port_changes (dev)) != -1)
+ ohci_rh_scanport (dev, port);
+}
+
+void
+ohci_rh_init (usbdev_t *dev)
+{
+ int i;
+
+ dev->destroy = ohci_rh_destroy;
+ dev->poll = ohci_rh_poll;
+
+ dev->data = malloc (sizeof (rh_inst_t));
+ if (!dev->data) {
+ printk("Not enough memory for OHCI RH.\n");
+ return;
+ }
+
+ RH_INST (dev)->numports = READ_OPREG(OHCI_INST(dev->controller), HcRhDescriptorA) & NumberDownstreamPortsMask;
+ RH_INST (dev)->port = malloc(sizeof(int) * RH_INST (dev)->numports);
+ usb_debug("%d ports registered\n", RH_INST (dev)->numports);
+
+ for (i = 0; i < RH_INST (dev)->numports; i++) {
+ ohci_rh_enable_port (dev, i);
+ RH_INST (dev)->port[i] = -1;
+ }
+
+ /* we can set them here because a root hub _really_ shouldn't
+ appear elsewhere */
+ dev->address = 0;
+ dev->hub = -1;
+ dev->port = -1;
+
+ usb_debug("rh init done\n");
+}
Modified: trunk/openbios-devel/include/drivers/pci.h
==============================================================================
--- trunk/openbios-devel/include/drivers/pci.h Mon Aug 25 15:07:56 2014 (r1315)
+++ trunk/openbios-devel/include/drivers/pci.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -188,6 +188,7 @@
#define PCI_DEVICE_ID_APPLE_UNI_N_PCI 0x001f
#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020
#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL 0x0022
+#define PCI_DEVICE_ID_APPLE_KEYL_USB 0x003f
#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b
#define PCI_VENDOR_ID_SUN 0x108e
Added: trunk/openbios-devel/include/drivers/usb.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/openbios-devel/include/drivers/usb.h Mon Aug 25 15:08:08 2014 (r1316)
@@ -0,0 +1,8 @@
+#ifndef USB_H
+#define USB_H
+
+int ob_usb_ohci_init(const char *path, uint32_t addr);
+void ob_usb_hid_add_keyboard(const char *path);
+int usb_exit(void);
+
+#endif /* USB_H */
1
0
Author: mcayland
Date: Mon Aug 25 15:07:56 2014
New Revision: 1315
URL: http://tracker.coreboot.org/trac/openbios/changeset/1315
Log:
macio ide: Fix dev tree entries for macio ide ports
Only add the two ide ports that are emulated by QEMU to the device
tree to avoid clients trying to access the non-existent third one and
fix their names and properties for mac99 to match those used by Apple.
This makes MorphOS able to find and use these.
Signed-off-by: BALATON Zoltan <balaton(a)eik.bme.hu>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
Modified:
trunk/openbios-devel/drivers/ide.c
trunk/openbios-devel/drivers/macio.c
Modified: trunk/openbios-devel/drivers/ide.c
==============================================================================
--- trunk/openbios-devel/drivers/ide.c Mon Aug 25 15:07:53 2014 (r1314)
+++ trunk/openbios-devel/drivers/ide.c Mon Aug 25 15:07:56 2014 (r1315)
@@ -1526,6 +1526,10 @@
u32 props[8];
struct ide_channel *chan;
+ /* IDE ports on Macs are numbered from 3.
+ * Also see comments in macio.c:openpic_init() */
+ current_channel = 3;
+
for (i = 0; i < nb_channels; i++, current_channel++) {
chan = malloc(sizeof(struct ide_channel));
@@ -1574,7 +1578,8 @@
dnode = find_dev(nodebuff);
- set_property(dnode, "compatible", "heathrow-ata", 13);
+ set_property(dnode, "compatible", (is_oldworld() ?
+ "heathrow-ata" : "keylargo-ata"), 13);
props[0] = 0x00000526;
props[1] = 0x00000085;
Modified: trunk/openbios-devel/drivers/macio.c
==============================================================================
--- trunk/openbios-devel/drivers/macio.c Mon Aug 25 15:07:53 2014 (r1314)
+++ trunk/openbios-devel/drivers/macio.c Mon Aug 25 15:07:56 2014 (r1315)
@@ -136,7 +136,7 @@
int i;
unsigned int it_shift = macio_nvram_shift();
- for (i=0; i< arch_nvram_size() ; i++)
+ for (i=0; i < arch_nvram_size(); i++)
nvram[i << it_shift] = buf[i];
#ifdef DUMP_NVRAM
printk("new nvram:\n");
@@ -203,13 +203,16 @@
target_node = find_dev("/pci/mac-io/escc/ch-b");
set_int_property(target_node, "interrupt-parent", dnode);
- target_node = find_dev("/pci/mac-io/ata-1");
- set_int_property(target_node, "interrupt-parent", dnode);
-
- target_node = find_dev("/pci/mac-io/ata-2");
+ /* QEMU only emulates 2 of the 3 ata buses currently */
+ /* On a new world Mac these are not numbered but named by the
+ * ATA version they support. Thus we have: ata-3, ata-3, ata-4
+ * On g3beige they all called just ide.
+ * We take ata-3 and ata-4 which seems to work for both
+ * at least for clients we care about */
+ target_node = find_dev("/pci/mac-io/ata-3");
set_int_property(target_node, "interrupt-parent", dnode);
- target_node = find_dev("/pci/mac-io/ata-3");
+ target_node = find_dev("/pci/mac-io/ata-4");
set_int_property(target_node, "interrupt-parent", dnode);
target_node = find_dev("/pci/mac-io/via-cuda");
@@ -312,7 +315,7 @@
/* The NewWorld NVRAM is not located in the MacIO device */
macio_nvram_init("", 0);
escc_init(path, addr);
- macio_ide_init(path, addr, 3);
+ macio_ide_init(path, addr, 2);
openpic_init(path, addr);
ob_unin_init();
}
1
0

Aug. 25, 2014
Author: mcayland
Date: Mon Aug 25 15:07:53 2014
New Revision: 1314
URL: http://tracker.coreboot.org/trac/openbios/changeset/1314
Log:
arch/ppc/qemu: Rename root node for Macs to match Apple
Apple calls the root node of the device tree "device-tree" and MorphOS
relies on this to decide what properties to get. Make it happy.
Signed-off-by: BALATON Zoltan <balaton(a)eik.bme.hu>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
Modified:
trunk/openbios-devel/arch/ppc/qemu/tree.fs
Modified: trunk/openbios-devel/arch/ppc/qemu/tree.fs
==============================================================================
--- trunk/openbios-devel/arch/ppc/qemu/tree.fs Sun Aug 17 15:06:47 2014 (r1313)
+++ trunk/openbios-devel/arch/ppc/qemu/tree.fs Mon Aug 25 15:07:53 2014 (r1314)
@@ -12,7 +12,8 @@
\ -------------------------------------------------------------
" /" find-device
-
+\ Apple calls the root node device-tree
+" device-tree" device-name
[IFDEF] CONFIG_PPC64 2 [ELSE] 1 [THEN] encode-int " #address-cells" property
1 encode-int " #size-cells" property
h# 05f5e100 encode-int " clock-frequency" property
1
0
hello,
i tried latest qemu on illumos based platform Intel 64bit with SPARC64 boot and i can see:
root@infra-99-016:/myshare/builds2/sparc# ./qemu-system-sparc64 -cdrom OpenIndiana_Text_SPARC.iso -boot d -m 2048 -hda hda.img -nographic
OpenBIOS for Sparc64
Configuration device id QEMU version 1 machine id 0
kernel cmdline
CPUs: 1 x SUNW,UltraSPARC-IIi
UUID: 00000000-0000-0000-0000-000000000000
Welcome to OpenBIOS v1.1 built on Jun 20 2014 22:57
Type 'help' for detailed information
Trying cdrom:f...
Not a bootable ELF image
Not a bootable a.out image
Loading FCode image...
Loaded 7120 bytes
entry point is 0x4000
Ignoring failed claim for va 10db4ec memsz 19!
Ignoring failed claim for va 1000000 memsz 1276ce!
Ignoring failed claim for va 1402000 memsz 346ca!
Ignoring failed claim for va 1800000 memsz 67750!
Jumping to entry point 0000000001007ad8 for type 0000000000000001...
switching to new context: entry point 0x1007ad8 stack 0x00000000ffe8aa09
warning:interpret: exception -13 caught
interpret warning @ warning off : sync %tl-c %tstate h# 18672e0 x! %g1 h# 18672e8 x! %g2 h# 18672f0 x! %g3 h# 18672f8 x! %g4 h# 1867300 x! %g5 h# 1867308 x! %g6 h# 1867310 x! %g7 h# 1867318 x! %o0 h# 1867320 x! %o1 h# 1867328 x! %o2 h# 1867330 x! %o3 h# 1867338 x! %o4 h# 1867340 x! %o5 h# 1867348 x! %o6 h# 1867350 x! %o7 h# 1867358 x! %tl-c %tpc h# 1867360 x! %tl-c %tnpc h# 1867368 x! %y h# 1867370 l! %tl-c %tt h# 1861618 x! sync ; warning ! failed with error ffffffffffffffed
OpenIndiana Build glasgall_oi_151a_prestable8 64-bit (illumos 7256a34efe)
SunOS Release 5.11 - Copyright 1983-2010 Oracle and/or its affiliates.
All rights reserved. Use is subject to license terms.
DEBUG enabled
spacex@:interpret: exception -13 caught
interpret h# d constant MMU_PAGESHIFT h# 0 constant TTE8K h# 20 constant SFHME_SIZE h# 0 constant SFHME_TTE h# 8 constant HMEBLK_TAG h# 0 constant HMEBLK_NEXT h# 2c constant HMEBLK_MISC h# 38 constant HMEBLK_HME1 h# 8 constant NHMENTS h# 7 constant HBLK_SZMASK h# 10 constant HBLK_RANGE_SHIFT h# 8 constant HMEBP_HBLK h# 1 constant HMEBLK_ENDPA h# 20 constant HMEBUCKET_SIZE h# 0 constant HTAG_SFMMUPSZ h# d constant HTAG_BSPAGE_SHIFT h# a constant HTAG_REHASH_SHIFT h# 3ff constant SFMMU_INVALID_SHMERID h# 3 cmisc/forthdebug (467615 bytes) could not find debugger-vocabulary-hook>threads:interpret: exception -13 caught
interpret \ ident "%Z%%M% %I% %E% SMI"
\ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
\ Use is subject to license terms.
\
\ CDDL HEADER START
\
\ The contents of this file are subject to the terms of the
\ Common Development and Distribution License, Version 1.0 only
\ (the "License"). You may not use this file except in compliance
\ with the License.
\
\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
\ or http://www.opensolaris.org/os/licensing.
\ See the License for loaded
(Can't load tod module) EXIT
boot start, but failed.
—
Best regards,
Igor Kozhukhov
2
1

Aug. 17, 2014
Commit r1287 (which only increases the L11 timer frequency from 10Hz to 100Hz)
causes HelenOS boot to become extremely unreliable under QEMU. Revert the
frequency fix so the timer frequency is set back to 10Hz, but instead increase
the get-msecs counter increment by 10. This ensures that while the timer
resolution is degraded, get-msecs still returns a reasonably time accurate
value.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
CC: Artyom Tarasenko <atar4qemu(a)gmail.com>
---
openbios-devel/arch/sparc64/entry.S | 2 +-
openbios-devel/arch/sparc64/vectors.S | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/openbios-devel/arch/sparc64/entry.S b/openbios-devel/arch/sparc64/entry.S
index d03128a..33632b1 100644
--- a/openbios-devel/arch/sparc64/entry.S
+++ b/openbios-devel/arch/sparc64/entry.S
@@ -17,7 +17,7 @@
#define PROM_ADDR 0x1fff0000000
#define CFG_ADDR 0x1fe02000510
-#define HZ 1 * 1000 * 1000
+#define HZ 10 * 1000 * 1000
#define TICK_INT_DIS 0x8000000000000000
.globl entry, _entry
diff --git a/openbios-devel/arch/sparc64/vectors.S b/openbios-devel/arch/sparc64/vectors.S
index 927c1cd..cd2b988 100644
--- a/openbios-devel/arch/sparc64/vectors.S
+++ b/openbios-devel/arch/sparc64/vectors.S
@@ -30,7 +30,7 @@
#define PROM_ADDR 0x1fff0000000
#define SER_ADDR 0x1fe020003f8
#define TICK_INT_DIS 0x8000000000000000
-#define TICK_INTERVAL 1*1000*1000
+#define TICK_INTERVAL 10*1000*1000
.section ".text.vectors", "ax"
.align 16384
@@ -630,7 +630,7 @@ softint_irq:
nop
ldx [%g3], %g1
- add %g1, 10, %g1 ! 100Hz = 10ms
+ add %g1, 100, %g1 ! 10Hz = 100ms
stx %g1, [%g3]
tick_rearm:
--
1.7.10.4
1
1
Author: mcayland
Date: Sun Aug 17 15:06:47 2014
New Revision: 1313
URL: http://tracker.coreboot.org/trac/openbios/changeset/1313
Log:
SPARC64: add empty no-streaming-cache property to Sabre node
This matches the device tree from a real Ultra 5 and prevents NetBSD from
attempting to manipulate the streaming cache.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
Modified:
trunk/openbios-devel/drivers/pci.c
Modified: trunk/openbios-devel/drivers/pci.c
==============================================================================
--- trunk/openbios-devel/drivers/pci.c Mon Aug 4 19:40:39 2014 (r1312)
+++ trunk/openbios-devel/drivers/pci.c Sun Aug 17 15:06:47 2014 (r1313)
@@ -565,6 +565,9 @@
sizeof(props[0]));
set_property(dev, "#virtual-dma-addr-cells", (char *)props,
sizeof(props[0]));
+
+ set_property(dev, "no-streaming-cache", (char *)props, 0);
+
props[0] = 0x000007f0;
props[1] = 0x000007ee;
props[2] = 0x000007ef;
1
0
I'm trying to solve the last bigger outstanding problem for MorphOS to run
with OpenBIOS. This is that it modifies exception vectors without first
turning the MMU off (probably expecting it to be off as happens on real
hardware). OpenBIOS on the other hand turns the MMU on and needs this for
client interface calls to work so calling the client boot code with MMU
off results in a hang. There is disabled code in the quiesce method to
clear the MMU bits but this is not sufficient/correct because MorphOS
continues to call client interface callbacks after calling quiesce. Thus I
was trying to save MSR, turn MMU on then restore MSR on client callbacks
with the patch below but it does not work and leads to writes to wrong
addresses and a crash on restore. (Probably the stack location is wrong
after the patch?) Can anyone tell why it's not working and what could be
done instead?
Regards,
BALATON Zoltan
diff --git a/openbios-devel/arch/ppc/qemu/start.S
b/openbios-devel/arch/ppc/qemu
index ae2fd53..384a8a6 100644
--- a/openbios-devel/arch/ppc/qemu/start.S
+++ b/openbios-devel/arch/ppc/qemu/start.S
@@ -515,13 +515,13 @@ _GLOBAL(call_elf):
LOAD_REG_IMMEDIATE(r5, of_client_callback) // r5 = callback
li r6,0 // r6 = address of client program
argume
li r7,0 // r7 = length of client program
argumen
- li r0,MSR_FP | MSR_ME | MSR_DR | MSR_IR
+ li r0,MSR_FP | MSR_ME
MTMSRD(r0)
blrl
#ifdef CONFIG_PPC64
/* Restore SF bit */
- LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME | MSR_DR | MSR_IR)
+ LOAD_REG_IMMEDIATE(r0, MSR_SF | MSR_FP | MSR_ME)
MTMSRD(r0)
#endif
LOAD_REG_IMMEDIATE(r8, saved_stack) // restore stack
pointer
@@ -535,10 +535,10 @@ _GLOBAL(call_elf):
#ifdef __powerpc64__
#define STKOFF STACKFRAME_MINSIZE
-#define SAVE_SPACE 320
+#define SAVE_SPACE 328
#else
#define STKOFF 8
-#define SAVE_SPACE 144
+#define SAVE_SPACE 148
#endif
GLOBL(of_client_callback):
@@ -607,6 +607,10 @@ GLOBL(of_client_callback):
PPC_STL r29, (STKOFF + 30 * ULONG_SIZE)(r1)
PPC_STL r30, (STKOFF + 31 * ULONG_SIZE)(r1)
PPC_STL r31, (STKOFF + 32 * ULONG_SIZE)(r1)
+ mfmsr r2
+ PPC_STL r2, (STKOFF + 33 * ULONG_SIZE)(r1)
+ ori r2, r2, (MSR_DR | MSR_IR)
+ mtmsr r2
#ifdef CONFIG_PPC64
LOAD_REG_IMMEDIATE(r2, of_client_interface)
@@ -643,6 +647,8 @@ GLOBL(of_client_callback):
PPC_LL r29, (STKOFF + 30 * ULONG_SIZE)(r1)
PPC_LL r30, (STKOFF + 31 * ULONG_SIZE)(r1)
PPC_LL r31, (STKOFF + 32 * ULONG_SIZE)(r1)
+ PPC_LL r2, (STKOFF + 33 * ULONG_SIZE)(r1)
+ mtmsr r2
/* restore ctr, cr and xer */
This results in:
Unassigned mem write 00000000100fff6c = 0x0
Unassigned mem write 00000000100fff74 = 0xfde7e90
Unassigned mem write 00000000100fff78 = 0x0
Unassigned mem write 00000000100fff7c = 0x4311d0
Unassigned mem write 00000000100fff80 = 0x0
Unassigned mem write 00000000100fff84 = 0x22000042
Unassigned mem write 00000000100fff88 = 0x20000000
Unassigned mem write 00000000100fff8c = 0x0
Unassigned mem write 00000000100fff90 = 0x8
Unassigned mem write 00000000100fff94 = 0x2
Unassigned mem write 00000000100fff98 = 0x0
Unassigned mem write 00000000100fff9c = 0x680000
Unassigned mem write 00000000100fffa0 = 0xfde7f98
Unassigned mem write 00000000100fffa4 = 0xfdf7e70
Unassigned mem write 00000000100fffa8 = 0x22000042
Unassigned mem write 00000000100fffac = 0x0
Unassigned mem write 00000000100fffb0 = 0xfff32687
Unassigned mem write 00000000100fffb4 = 0xfde7f60
Unassigned mem write 00000000100fffb8 = 0xfde7f20
Unassigned mem write 00000000100fffbc = 0x0
Unassigned mem write 00000000100fffc0 = 0xfffb0000
Unassigned mem write 00000000100fffc4 = 0x688000
Unassigned mem write 00000000100fffc8 = 0x3000
Unassigned mem write 00000000100fffcc = 0xfffb601c
Unassigned mem write 00000000100fffd0 = 0x0
Unassigned mem write 00000000100fffd4 = 0xfffb601c
Unassigned mem write 00000000100fffd8 = 0xfffb0000
Unassigned mem write 00000000100fffdc = 0x0
Unassigned mem write 00000000100fffe0 = 0xfff02620
Unassigned mem write 00000000100fffe4 = 0xfde7f60
Unassigned mem write 00000000100fffe8 = 0xfde7f20
Unassigned mem write 00000000100fffec = 0x688000
Unassigned mem write 00000000100ffff0 = 0xfffb0000
Unassigned mem write 00000000100ffff4 = 0x67bd80
Unassigned mem write 00000000100ffff8 = 0x3000
Unassigned mem read 0000000060000000
qemu: fatal: Trying to execute code outside RAM or ROM at 0x60000000
NIP 60000000 LR 60000000 CTR 00000000 XER 00000000
MSR 00000000 HID0 00000000 HF 00000000 idx 1
TB 00000000 836520711 DECR 3458446955
GPR00 0000000000000000 0000000060000000 0000000000000000 0000000000000000
GPR04 000000004bfffffc 0000000000000000 0000000000000000 0000000000000000
GPR08 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR12 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR16 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR20 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR24 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR28 0000000000000000 0000000000000000 0000000000000000 0000000000000000
CR 00000000 [ - - - - - - - - ] RES ffffffff
FPR00 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR04 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR08 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR12 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR16 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR20 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR24 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPR28 0000000000000000 0000000000000000 0000000000000000 0000000000000000
FPSCR 00000000
SRR0 fff0db1c SRR1 00003030 PVR 000c0209 VRSAVE 00000000
SPRG0 0fe00000 SPRG1 ffffff6c SPRG2 22000042 SPRG3 00000000
SPRG4 00000000 SPRG5 00000000 SPRG6 00000000 SPRG7 00000000
SDR1 0fe00000 DAR ffffff3c DSISR 42000000
end of dissassembly before the error:
0xfff02750: lwz r31,136(r1)
0xfff02754: lwz r2,140(r1)
0xfff02758: mtmsr r2
IN:
0xfff0275c: lwz r2,20(r1)
0xfff02760: mtctr r2
0xfff02764: lwz r2,24(r1)
0xfff02768: mtcr r2
0xfff0276c: lwz r2,28(r1)
0xfff02770: mtxer r2
0xfff02774: lwz r2,12(r1)
0xfff02778: lwz r0,16(r1)
0xfff0277c: lwz r1,8(r1)
0xfff02780: lwz r4,4(r1)
0xfff02784: mtlr r4
0xfff02788: lwz r4,8(r1)
0xfff0278c: lwz r1,0(r1)
0xfff02790: blr
qemu: fatal: Trying to execute code outside RAM or ROM at 0x60000000
4
50

Re: [OpenBIOS] [PATCH 6/6] SPARC64: add model to hwdefs array and set it to a suitable value
by Mark Cave-Ayland Aug. 4, 2014
by Mark Cave-Ayland Aug. 4, 2014
Aug. 4, 2014
On 28/07/14 15:33, Artyom Tarasenko wrote:
> On Sun, Jul 27, 2014 at 10:44 PM, Mark Cave-Ayland
> <mark.cave-ayland(a)ilande.co.uk> wrote:
>> At the moment we are probably closest to an Ultra250 with an UltraSPARC-IIi
>> processor and PCI bus.
>
> Are we? I thought QEMU was targeting Ultra-5. Both Ultra-5 and
> Enterpise-250 have different serial ports, but Enterprise-250 may have
> multiple CPUs, whereas QEMU can't.
Yeah, it was something to do with the serial ports, although I suspect
given the hacking over the past weekend that Ultra5 is probably still
valid now.
>> This property is checked by NetBSD during boot.
>
> Does it have to be something existing? Since QEMU doesn't exactly
> match any real machine, I'd prefer something like "QEMU,sun4u", but
> maybe it's personal.
I'm not exactly sure? But sure, at the very least we should have
something there to prevent errors on the console during boot.
ATB,
Mark.
1
1
Author: mcayland
Date: Mon Aug 4 19:40:39 2014
New Revision: 1312
URL: http://tracker.coreboot.org/trac/openbios/changeset/1312
Log:
SPARC64: switch to using interrupt-map property for interrupt pins
Instead of wiring the interrupt pins directly on the device, follow the PCI
bindings specification by storing the PCI interrupt pin on the device and then
using a combination of interrupt-map and interrupt-map-mask properties to
generate the final interrupt pin.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
Modified:
trunk/openbios-devel/drivers/pci.c
Modified: trunk/openbios-devel/drivers/pci.c
==============================================================================
--- trunk/openbios-devel/drivers/pci.c Mon Aug 4 19:40:36 2014 (r1311)
+++ trunk/openbios-devel/drivers/pci.c Mon Aug 4 19:40:39 2014 (r1312)
@@ -414,6 +414,10 @@
set_property(dev, "bus-range", (char *)props, 2 * sizeof(props[0]));
}
+/* Convert device/irq pin to interrupt property */
+#define SUN4U_INTERRUPT(dev, irq_pin) \
+ ((((dev >> 11) << 2) + irq_pin - 1) & 0x1f)
+
static void pci_host_set_interrupt_map(const pci_config_t *config)
{
/* XXX We currently have a hook in the MPIC init code to fill in its handle.
@@ -454,19 +458,27 @@
set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
#elif defined(CONFIG_SPARC64)
phandle_t dev = get_cur_dev();
- uint32_t props[5];
+ uint32_t props[12];
+ int ncells, device, i;
+
+ /* Set interrupt-map for devices 4 (NE2000) and 5 (CMD646) */
+ ncells = 0;
+ for (i = 4; i <= 5; i++) {
+ device = i << 11;
- props[0] = 0x000001fe;
- props[1] = 0x020003f8;
- props[2] = 1;
- props[3] = find_dev("/");
- props[4] = 0x2b;
- set_property(dev, "interrupt-map", (char *)props, 5 * sizeof(props[0]));
-
- props[0] = 0x000001ff;
- props[1] = 0xffffffff;
- props[2] = 3;
- set_property(dev, "interrupt-map-mask", (char *)props, 3 * sizeof(props[0]));
+ ncells += pci_encode_phys_addr(props + ncells, 0, 0, device, 0, 0);
+ props[ncells++] = 1;
+ props[ncells++] = get_cur_dev();
+ props[ncells++] = SUN4U_INTERRUPT(device, 1);
+ }
+
+ set_property(dev, "interrupt-map", (char *)props, ncells * sizeof(props[0]));
+
+ props[0] = 0x0000f800;
+ props[1] = 0x0;
+ props[2] = 0x0;
+ props[3] = 7;
+ set_property(dev, "interrupt-map-mask", (char *)props, 4 * sizeof(props[0]));
#endif
}
@@ -960,10 +972,7 @@
OLDWORLD(set_int_property(dev, "AAPL,interrupts",
config->irq_line));
#if defined(CONFIG_SPARC64)
- /* direct mapping bssnn (Bus, Slot, interrupt Number */
- set_int_property(get_cur_dev(), "interrupts",
- ((((config->dev >> 11) << 2)
- + config->irq_pin - 1) & 0x1f));
+ set_int_property(dev, "interrupts", config->irq_pin);
#else
NEWWORLD(set_int_property(dev, "interrupts", config->irq_pin));
#endif
1
0
Author: mcayland
Date: Mon Aug 4 19:40:36 2014
New Revision: 1311
URL: http://tracker.coreboot.org/trac/openbios/changeset/1311
Log:
SPARC64: build ebus ranges property from PCI BARs
Also fix up the interrupt-map property to match the altered addresses.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland(a)ilande.co.uk>
Modified:
trunk/openbios-devel/drivers/pci.c
Modified: trunk/openbios-devel/drivers/pci.c
==============================================================================
--- trunk/openbios-devel/drivers/pci.c Mon Aug 4 19:40:34 2014 (r1310)
+++ trunk/openbios-devel/drivers/pci.c Mon Aug 4 19:40:36 2014 (r1311)
@@ -841,10 +841,14 @@
{
#ifdef CONFIG_DRIVER_EBUS
phandle_t dev = get_cur_dev();
- uint32_t props[5];
+ uint32_t props[12];
+ int ncells;
+ int i;
+ uint32_t mask;
+ int flags, space_code;
- props[0] = 0x000001fe;
- props[1] = 0x020003f8;
+ props[0] = 0x14;
+ props[1] = 0x3f8;
props[2] = 1;
props[3] = find_dev("/");
props[4] = 0x2b;
@@ -855,14 +859,37 @@
props[2] = 3;
set_property(dev, "interrupt-map-mask", (char *)props, 3 * sizeof(props[0]));
+ /* Build ranges property from the BARs */
+ ncells = 0;
+ for (i = 0; i < 6; i++) {
+ /* consider only bars with non-zero region size */
+ if (!config->sizes[i])
+ continue;
+
+ pci_decode_pci_addr(config->assigned[i],
+ &flags, &space_code, &mask);
+
+ props[ncells++] = PCI_BASE_ADDR_0 + (i * sizeof(uint32_t));
+ props[ncells++] = 0x0;
+
+ ncells += pci_encode_phys_addr(props + ncells,
+ flags, space_code, config->dev,
+ PCI_BASE_ADDR_0 + (i * sizeof(uint32_t)),
+ 0);
+
+ props[ncells++] = config->sizes[i];
+ }
+
+ set_property(dev, "ranges", (char *)props, ncells * sizeof(props[0]));
+
#ifdef CONFIG_DRIVER_FLOPPY
ob_floppy_init(config->path, "fdthree", 0x3f0ULL, 0);
#endif
#ifdef CONFIG_DRIVER_PC_SERIAL
- ob_pc_serial_init(config->path, "su", arch->io_base, 0x3f8ULL, 0);
+ ob_pc_serial_init(config->path, "su", (PCI_BASE_ADDR_1 | 0ULL) << 32, 0x3f8ULL, 0);
#endif
#ifdef CONFIG_DRIVER_PC_KBD
- ob_pc_kbd_init(config->path, "kb_ps2", arch->io_base, 0x60ULL, 0);
+ ob_pc_kbd_init(config->path, "kb_ps2", (PCI_BASE_ADDR_1 | 0ULL) << 32, 0x60ULL, 0);
#endif
#endif
return 0;
1
0