diff --git a/apps/main.c b/apps/main.c index 6d2609b..4b74784 100644 --- a/apps/main.c +++ b/apps/main.c @@ -326,6 +326,7 @@ static void init(void) viewportmanager_init(); gui_sync_wps_init(); + usb_init(); storage_init(); settings_reset(); settings_load(SETTINGS_ALL); diff --git a/firmware/SOURCES b/firmware/SOURCES index c1da067..e692a50 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -288,7 +288,6 @@ drivers/audio/uda1341.c #endif /* !defined(SIMULATOR) && !defined(BOOTLOADER) */ /* USB Stack */ -#if !defined(SIMULATOR) #ifdef HAVE_USBSTACK usbstack/usb_core.c #ifdef USB_ENABLE_STORAGE @@ -319,7 +318,6 @@ drivers/isp1362.c drivers/m5636.c #endif #endif /* !defined(HAVE_USBSTACK) */ -#endif /* !defined(SIMULATOR) */ /* Other Random Hardware */ #ifdef HAVE_TSC2100 diff --git a/firmware/export/as3525.h b/firmware/export/as3525.h index a8903d1..41f7e12 100644 --- a/firmware/export/as3525.h +++ b/firmware/export/as3525.h @@ -505,7 +505,9 @@ interface */ /* USB : TODO */ #define USB_NUM_ENDPOINTS 4 +#ifndef SIMULATOR #define USB_DEVBSS_ATTR IBSS_ATTR +#endif /* SIMULATOR */ /* I2SIN registers */ diff --git a/firmware/export/config.h b/firmware/export/config.h index 2b7c6d8..a510756 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -843,7 +843,10 @@ Lyre prototype 1 */ #if defined(HAVE_USBSTACK) /* Define the implemented USB transport classes */ -#if CONFIG_USBOTG == USBOTG_ISP1583 +#if defined(SIMULATOR) +#define USB_HAS_BULK +#define USB_HAS_INTERRUPT +#elif CONFIG_USBOTG == USBOTG_ISP1583 #define USB_HAS_BULK #elif (CONFIG_USBOTG == USBOTG_ARC) || \ (CONFIG_USBOTG == USBOTG_JZ4740) || \ @@ -878,8 +881,12 @@ Lyre prototype 1 */ #define USB_ENABLE_HID #else #define USB_ENABLE_CHARGING_ONLY -#endif -#endif +#endif /* USB_HAS_INTERRUPT */ +#else /* SIMULATOR */ +#define USB_ENABLE_HID +#define USB_ENABLE_SERIAL +//#define USB_ENABLE_STORAGE +#endif /* SIMULATOR */ #endif /* BOOTLOADER */ diff --git a/firmware/export/config/sim.h b/firmware/export/config/sim.h index ec398c8..2294aed 100644 --- a/firmware/export/config/sim.h +++ b/firmware/export/config/sim.h @@ -40,12 +40,14 @@ #undef USB_HANDLED_BY_OF -#undef HAVE_USBSTACK -#undef USE_ROCKBOX_USB -#undef USB_VENDOR_ID -#undef USB_PRODUCT_ID #undef USB_NUM_ENDPOINTS -#undef HAVE_USB_HID_MOUSE +#define USB_NUM_ENDPOINTS 8 +/* with the simulator, the previous definition can't be dangerous so keep it if already defined */ +#ifndef USB_DEVBSS_ATTR +#define USB_DEVBSS_ATTR +#endif /* USB_DEVBSS_ATTR */ +#define USB_STATUS_BY_EVENT +#define USB_DETECT_BY_DRV #undef HAVE_ADJUSTABLE_CPU_FREQ diff --git a/firmware/export/dm320.h b/firmware/export/dm320.h index f78fc6c..fd3a638 100644 --- a/firmware/export/dm320.h +++ b/firmware/export/dm320.h @@ -49,7 +49,9 @@ extern unsigned long _ttbstart; /* This needs to be 2048 byte aligned, but USB_QHARRAY_ATTR should take care * of that */ #define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(4))) +#ifndef SIMULATOR #define USB_DEVBSS_ATTR IBSS_ATTR +#endif /* SIMULATOR */ /* Timer 0-3 */ diff --git a/firmware/export/imx31l.h b/firmware/export/imx31l.h index dea5588..275e5cc 100644 --- a/firmware/export/imx31l.h +++ b/firmware/export/imx31l.h @@ -41,7 +41,9 @@ /* USBOTG */ #define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(2048))) #define USB_NUM_ENDPOINTS 8 +#ifndef SIMULATOR #define USB_DEVBSS_ATTR DEVBSS_ATTR +#endif /* SIMULATOR */ #define USB_BASE OTG_BASE_ADDR /* diff --git a/firmware/export/jz4740.h b/firmware/export/jz4740.h index 820b43f..3b39c39 100644 --- a/firmware/export/jz4740.h +++ b/firmware/export/jz4740.h @@ -5207,7 +5207,9 @@ struct Ration2m /* Rockbox USB defines */ #define USB_NUM_ENDPOINTS 3 +#ifndef SIMULATOR #define USB_DEVBSS_ATTR IBSS_ATTR +#endif /* SIMULATOR */ /* Timer frequency */ #define TIMER_FREQ (CFG_EXTAL) /* For full precision! */ diff --git a/firmware/export/pp5020.h b/firmware/export/pp5020.h index 2d8d0e1..8261b55 100644 --- a/firmware/export/pp5020.h +++ b/firmware/export/pp5020.h @@ -31,7 +31,9 @@ /* This needs to be 2048 byte aligned, but USB_QHARRAY_ATTR should take care * of that */ #define USB_QHARRAY_ATTR __attribute__((section(".qharray"),nocommon,aligned(4))) +#ifndef SIMULATOR #define USB_DEVBSS_ATTR IBSS_ATTR +#endif /* SIMULATOR */ /* DRAM starts at 0x10000000, but in Rockbox we remap it to 0x00000000 */ #define DRAM_START 0x10000000 diff --git a/firmware/export/tcc77x.h b/firmware/export/tcc77x.h index db128b6..f8c9e9c 100644 --- a/firmware/export/tcc77x.h +++ b/firmware/export/tcc77x.h @@ -251,7 +251,9 @@ #define USB_BASE 0x90000b00 #define USB_NUM_ENDPOINTS 3 +#ifndef SIMULATOR #define USB_DEVBSS_ATTR IBSS_ATTR +#endif /* SIMULATOR */ /* Timer frequency */ /* timers are based on XIN (12Mhz) */ diff --git a/firmware/export/tcc780x.h b/firmware/export/tcc780x.h index aca3bec..810d99e 100644 --- a/firmware/export/tcc780x.h +++ b/firmware/export/tcc780x.h @@ -287,7 +287,9 @@ #define USB_BASE 0xf0010000 #define USB_NUM_ENDPOINTS 3 +#ifndef SIMULATOR #define USB_DEVBSS_ATTR IBSS_ATTR +#endif /* SIMULATOR */ /* Timer frequency */ /* Timer is based on PCK_TCT (set to 2Mhz in system.c) */ diff --git a/firmware/export/usb.h b/firmware/export/usb.h index 59c0004..e4d9804 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -52,6 +52,9 @@ enum { USB_REQUEST_REBOOT, /* Event */ #endif USB_QUIT, /* Event */ +#if defined(SIMULATOR) && defined(HAVE_USBSTACK) + USB_ASK, /* Event */ +#endif }; #ifdef HAVE_USB_POWER @@ -129,6 +132,11 @@ struct usb_transfer_completion_event_data }; #endif /* HAVE_USBSTACK */ +#if defined(SIMULATOR) && defined(HAVE_USBSTACK) +#define USB_ASK_SIMULATE_INSERTION 1 +#define USB_ASK_SIMULATE_EXTRACTION 2 +void usb_ask(unsigned int what); /* Simulator: ask something (simulate insertion,extraction,...) */ +#endif void usb_init(void); void usb_enable(bool on); void usb_attach(void); diff --git a/firmware/usb.c b/firmware/usb.c index ccf12c1..9a013ac 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -27,7 +27,10 @@ #include "cpu.h" #include "kernel.h" #include "thread.h" -#include "system.h" +#ifdef SIMULATOR +#include "system-sdl.h" +#include "debug.h" +#endif #include "debug.h" #include "storage.h" #include "fat.h" @@ -42,6 +45,7 @@ #ifdef HAVE_USBSTACK #include "usb_core.h" #endif +#define LOGF_ENABLE #include "logf.h" #include "screendump.h" @@ -60,7 +64,7 @@ bool do_screendump_instead_of_usb = false; #endif -#if !defined(SIMULATOR) && !defined(USB_NONE) +#if !defined(USB_NONE) static int usb_state; @@ -232,6 +236,11 @@ static void usb_thread(void) queue_wait(&usb_queue, &ev); switch(ev.id) { +#if defined(SIMULATOR) && defined(HAVE_USBSTACK) + case USB_ASK: + usb_ask((unsigned int)ev.data); + break; +#endif #ifdef USB_DRIVER_CLOSE case USB_QUIT: return; @@ -314,7 +323,7 @@ static void usb_thread(void) usb_core_enable_driver(USB_DRIVER_HID, usb_hid); #endif #ifdef USB_ENABLE_CHARGING_ONLY - usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false); + usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true); #endif /* Check any drivers enabled at this point for exclusive storage @@ -532,6 +541,7 @@ static void usb_tick(void) readings in a row */ if(countdown == 0) { + DEBUGF("usb_tick: post %d\n", current_status); queue_post(&usb_queue, current_status, 0); } } @@ -560,6 +570,7 @@ void usb_acknowledge(long id) void usb_init(void) { + DEBUGF("usb_init\n"); /* We assume that the USB cable is extracted */ usb_state = USB_EXTRACTED; #ifdef USB_DETECT_BY_DRV diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index 7b80d0b..576f758 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -263,7 +263,7 @@ static unsigned char response_data[256] USB_DEVBSS_ATTR; static short hex[16] = {'0','1','2','3','4','5','6','7', '8','9','A','B','C','D','E','F'}; -#ifdef IPOD_ARCH +#if defined(IPOD_ARCH) && !defined(SIMULATOR) static void set_serial_descriptor(void) { #ifdef IPOD_VIDEO @@ -287,7 +287,7 @@ static void set_serial_descriptor(void) } usb_string_iSerial.bLength=52; } -#elif defined(HAVE_AS3514) +#elif defined(HAVE_AS3514) && !defined(SIMULATOR) static void set_serial_descriptor(void) { unsigned char serial[16]; @@ -321,7 +321,7 @@ static void set_serial_descriptor(void) } usb_string_iSerial.bLength=84; } -#elif (CONFIG_STORAGE & STORAGE_RAMDISK) +#elif (CONFIG_STORAGE & STORAGE_RAMDISK) || defined(SIMULATOR) /* This "serial number" isn't unique, but it should never actually appear in non-testing use */ static void set_serial_descriptor(void) diff --git a/uisimulator/common/SOURCES b/uisimulator/common/SOURCES index c186551..9569eb4 100644 --- a/uisimulator/common/SOURCES +++ b/uisimulator/common/SOURCES @@ -10,4 +10,7 @@ sim_tasks.c stubs.c powermgmt-sim.c backlight-sim.c - +#ifdef HAVE_USBSTACK +usb-drv.c +libusb_vhci/libusb_vhci.c +#endif diff --git a/uisimulator/common/libusb_vhci/libusb_vhci.c b/uisimulator/common/libusb_vhci/libusb_vhci.c new file mode 100644 index 0000000..1c749d8 --- /dev/null +++ b/uisimulator/common/libusb_vhci/libusb_vhci.c @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2009 Michael Singer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "vhci-hcd.h" +#include "libusb_vhci.h" + +int usb_vhci_open(uint8_t port_count, // [IN] number of ports + int32_t *id, // [OUT] controller id + int32_t *usb_busnum, // [OUT] usb bus number + char **bus_id) // [OUT] bus id (usually + // vhci_hcd.) +{ + int fd = open(USB_VHCI_DEVICE_FILE, O_RDWR); + if(fd == -1) return -1; + + struct vhci_ioc_register r; + r.port_count = port_count; + if(ioctl(fd, VHCI_HCD_IOCREGISTER, &r) == -1) + { + int err = errno; + usb_vhci_close(fd); + errno = err; + return -1; + } + + if(id) *id = r.id; + if(usb_busnum) *usb_busnum = r.usb_busnum; + if(bus_id) + { + size_t s = sizeof r.bus_id / sizeof *r.bus_id - 1; + r.bus_id[s] = 0; + size_t ss = (strlen(r.bus_id) + 1) * sizeof **bus_id; + if((*bus_id = malloc(ss))) + memcpy(*bus_id, r.bus_id, ss); + } + + return fd; +} + +int usb_vhci_close(int fd) +{ + int result; + while((result = close(fd)) == -1 && errno == EINTR); + return result; +} + +int usb_vhci_fetch_work(int fd, struct usb_vhci_work *work) +{ + struct vhci_ioc_work w; + if(ioctl(fd, VHCI_HCD_IOCFETCHWORK, &w) == -1) + return -1; + + switch(w.type) + { + case VHCI_IOC_WORK_TYPE_PORT_STAT: + work->type = USB_VHCI_WORK_TYPE_PORT_STAT; + work->work.port_stat.status = w.work.port.status; + work->work.port_stat.change = w.work.port.change; + work->work.port_stat.index = w.work.port.index; + work->work.port_stat.flags = w.work.port.flags; + return 0; + + case VHCI_IOC_WORK_TYPE_PROCESS_URB: + memset(&work->work.urb, 0, sizeof work->work.urb); + switch(w.work.urb.type) + { + case VHCI_IOC_URB_TYPE_ISO: + work->work.urb.type = USB_VHCI_URB_TYPE_ISO; + work->work.urb.packet_count = w.work.urb.packet_count; + work->work.urb.interval = w.work.urb.interval; + break; + case VHCI_IOC_URB_TYPE_INT: + work->work.urb.type = USB_VHCI_URB_TYPE_INT; + work->work.urb.interval = w.work.urb.interval; + break; + case VHCI_IOC_URB_TYPE_CONTROL: + work->work.urb.type = USB_VHCI_URB_TYPE_CONTROL; + work->work.urb.wValue = w.work.urb.setup_packet.wValue; + work->work.urb.wIndex = w.work.urb.setup_packet.wIndex; + work->work.urb.wLength = w.work.urb.setup_packet.wLength; + work->work.urb.bmRequestType = w.work.urb.setup_packet.bmRequestType; + work->work.urb.bRequest = w.work.urb.setup_packet.bRequest; + break; + case VHCI_IOC_URB_TYPE_BULK: + work->work.urb.type = USB_VHCI_URB_TYPE_BULK; + work->work.urb.flags = ((w.work.urb.flags & VHCI_IOC_URB_FLAGS_SHORT_NOT_OK) ? + USB_VHCI_URB_FLAGS_SHORT_NOT_OK : 0) | + ((w.work.urb.flags & VHCI_IOC_URB_FLAGS_ZERO_PACKET) ? + USB_VHCI_URB_FLAGS_ZERO_PACKET : 0); + break; + default: + errno = EBADMSG; + return -1; + } + work->type = USB_VHCI_WORK_TYPE_PROCESS_URB; + work->work.urb.status = -EINPROGRESS; + work->work.urb.handle = w.handle; + work->work.urb.buffer_length = w.work.urb.buffer_length; + if(usb_vhci_is_out(w.work.urb.endpoint) || usb_vhci_is_iso(work->work.urb.type)) + work->work.urb.buffer_actual = w.work.urb.buffer_length; + work->work.urb.devadr = w.work.urb.address; + work->work.urb.epadr = w.work.urb.endpoint; + // return 1 if usb_vhci_fetch_data should be called + return work->work.urb.buffer_actual || work->work.urb.packet_count; + + case VHCI_IOC_WORK_TYPE_CANCEL_URB: + work->type = USB_VHCI_WORK_TYPE_CANCEL_URB; + work->work.handle = w.handle; + return 0; + + default: + errno = EBADMSG; + return -1; + } +} + +int usb_vhci_fetch_data(int fd, const struct usb_vhci_urb *urb) +{ + struct vhci_ioc_urb_data u; + u.handle = urb->handle; + u.buffer_length = urb->buffer_length; + const int pc = urb->packet_count; + u.packet_count = pc; + u.buffer = urb->buffer; + u.iso_packets = NULL; + if(pc > 0) + u.iso_packets = malloc(sizeof *u.iso_packets * pc); + + int ret = ioctl(fd, VHCI_HCD_IOCFETCHDATA, &u); + if(ret == -1) + goto err; + ret = 0; + int i; + for(i = 0; i < pc; i++) + { + urb->iso_packets[i].offset = u.iso_packets[i].offset; + urb->iso_packets[i].packet_length = (int32_t)u.iso_packets[i].packet_length; + urb->iso_packets[i].packet_actual = 0; + urb->iso_packets[i].status = -EINPROGRESS; + } + +err: + if(u.iso_packets) + free(u.iso_packets); + return ret; +} + +int usb_vhci_giveback(int fd, const struct usb_vhci_urb *urb) +{ + struct vhci_ioc_giveback gb; + gb.handle = urb->handle; + gb.status = urb->status; + gb.buffer_actual = urb->buffer_actual; + gb.buffer = NULL; + gb.iso_packets = NULL; + gb.packet_count = 0; + gb.error_count = 0; + + if(usb_vhci_is_in(urb->epadr) && gb.buffer_actual > 0) + gb.buffer = urb->buffer; + if(usb_vhci_is_iso(urb->type)) + { + const int pc = urb->packet_count; + gb.iso_packets = malloc(sizeof *gb.iso_packets * pc); + gb.packet_count = pc; + gb.error_count = urb->error_count; + int i; + for(i = 0; i < pc; i++) + { + gb.iso_packets[i].status = urb->iso_packets[i].status; + gb.iso_packets[i].packet_actual = (uint32_t)urb->iso_packets[i].packet_actual; + } + } + + int ret = ioctl(fd, VHCI_HCD_IOCGIVEBACK, &gb); + + if(gb.iso_packets) + free(gb.iso_packets); + if(ret == -1) + return (errno == ECANCELED) ? 0 : -1; + errno = 0; + return 0; +} + +int usb_vhci_port_connect(int fd, uint8_t port, uint8_t data_rate) +{ + if(!port || + (data_rate != USB_VHCI_DATA_RATE_FULL && + data_rate != USB_VHCI_DATA_RATE_LOW && + data_rate != USB_VHCI_DATA_RATE_HIGH)) + { + errno = EINVAL; + return -1; + } + struct vhci_ioc_port_stat ps; + ps.status = USB_PORT_STAT_CONNECTION; + if(data_rate == USB_VHCI_DATA_RATE_LOW) + ps.status |= USB_PORT_STAT_LOW_SPEED; + if(data_rate == USB_VHCI_DATA_RATE_HIGH) + ps.status |= USB_PORT_STAT_HIGH_SPEED; + ps.change = USB_PORT_STAT_C_CONNECTION; + ps.index = port; + ps.flags = 0; + if(ioctl(fd, VHCI_HCD_IOCPORTSTAT, &ps) == -1) + return -1; + return 0; +} + +int usb_vhci_port_disconnect(int fd, uint8_t port) +{ + if(!port) + { + errno = EINVAL; + return -1; + } + struct vhci_ioc_port_stat ps; + ps.status = 0; + ps.change = USB_PORT_STAT_C_CONNECTION; + ps.index = port; + ps.flags = 0; + if(ioctl(fd, VHCI_HCD_IOCPORTSTAT, &ps) == -1) + return -1; + return 0; +} + +int usb_vhci_port_disable(int fd, uint8_t port) +{ + if(!port) + { + errno = EINVAL; + return -1; + } + struct vhci_ioc_port_stat ps; + ps.status = 0; + ps.change = USB_PORT_STAT_C_ENABLE; + ps.index = port; + ps.flags = 0; + if(ioctl(fd, VHCI_HCD_IOCPORTSTAT, &ps) == -1) + return -1; + return 0; +} + +int usb_vhci_port_resumed(int fd, uint8_t port) +{ + if(!port) + { + errno = EINVAL; + return -1; + } + struct vhci_ioc_port_stat ps; + ps.status = 0; + ps.change = USB_PORT_STAT_C_SUSPEND; + ps.index = port; + ps.flags = 0; + if(ioctl(fd, VHCI_HCD_IOCPORTSTAT, &ps) == -1) + return -1; + return 0; +} + +int usb_vhci_port_overcurrent(int fd, uint8_t port, uint8_t set) +{ + if(!port) + { + errno = EINVAL; + return -1; + } + struct vhci_ioc_port_stat ps; + ps.status = set ? USB_PORT_STAT_OVERCURRENT : 0; + ps.change = USB_PORT_STAT_C_OVERCURRENT; + ps.index = port; + ps.flags = 0; + if(ioctl(fd, VHCI_HCD_IOCPORTSTAT, &ps) == -1) + return -1; + return 0; +} + +int usb_vhci_port_reset_done(int fd, uint8_t port, uint8_t enable) +{ + if(!port) + { + errno = EINVAL; + return -1; + } + struct vhci_ioc_port_stat ps; + ps.status = enable ? USB_PORT_STAT_ENABLE : 0;; + ps.change = USB_PORT_STAT_C_RESET; + ps.change |= enable ? 0 : USB_PORT_STAT_C_ENABLE; + ps.index = port; + ps.flags = 0; + if(ioctl(fd, VHCI_HCD_IOCPORTSTAT, &ps) == -1) + return -1; + return 0; +} diff --git a/uisimulator/common/libusb_vhci/libusb_vhci.h b/uisimulator/common/libusb_vhci/libusb_vhci.h new file mode 100644 index 0000000..326c77e --- /dev/null +++ b/uisimulator/common/libusb_vhci/libusb_vhci.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2009 Michael Singer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LIBUSB_VHCI_H +#define _LIBUSB_VHCI_H 1 + +#include +#include + +#define USB_VHCI_DEVICE_FILE "/dev/vhci-ctrl" + +#ifdef _LIB_USB_VHCI_NOTHROW +#undef _LIB_USB_VHCI_NOTHROW +#endif + +#define _LIB_USB_VHCI_NOTHROW + +struct usb_vhci_iso_packet +{ + uint32_t offset; + int32_t packet_length, packet_actual; + int32_t status; +}; + +struct usb_vhci_urb +{ + uint64_t handle; + uint8_t *buffer; + struct usb_vhci_iso_packet *iso_packets; + int32_t buffer_length, buffer_actual; + int32_t packet_count, error_count; + int32_t status, interval; + uint16_t flags; +#define USB_VHCI_URB_FLAGS_SHORT_NOT_OK 0x0001 +#define USB_VHCI_URB_FLAGS_ISO_ASAP 0x0002 +#define USB_VHCI_URB_FLAGS_ZERO_PACKET 0x0040 + uint16_t wValue, wIndex, wLength; + uint8_t bmRequestType, bRequest; + uint8_t devadr, epadr; + uint8_t type; +#define USB_VHCI_URB_TYPE_ISO 0 +#define USB_VHCI_URB_TYPE_INT 1 +#define USB_VHCI_URB_TYPE_CONTROL 2 +#define USB_VHCI_URB_TYPE_BULK 3 +}; + +struct usb_vhci_port_stat +{ + uint16_t status, change; +#define USB_VHCI_PORT_STAT_CONNECTION 0x0001 +#define USB_VHCI_PORT_STAT_ENABLE 0x0002 +#define USB_VHCI_PORT_STAT_SUSPEND 0x0004 +#define USB_VHCI_PORT_STAT_OVERCURRENT 0x0008 +#define USB_VHCI_PORT_STAT_RESET 0x0010 +#define USB_VHCI_PORT_STAT_POWER 0x0100 +#define USB_VHCI_PORT_STAT_LOW_SPEED 0x0200 +#define USB_VHCI_PORT_STAT_HIGH_SPEED 0x0400 +#define USB_VHCI_PORT_STAT_C_CONNECTION 0x0001 +#define USB_VHCI_PORT_STAT_C_ENABLE 0x0002 +#define USB_VHCI_PORT_STAT_C_SUSPEND 0x0004 +#define USB_VHCI_PORT_STAT_C_OVERCURRENT 0x0008 +#define USB_VHCI_PORT_STAT_C_RESET 0x0010 + uint8_t index, flags; +#define USB_VHCI_PORT_STAT_FLAG_RESUMING 0x01 +}; +#define USB_VHCI_DATA_RATE_FULL 0 +#define USB_VHCI_DATA_RATE_LOW 1 +#define USB_VHCI_DATA_RATE_HIGH 2 + +struct usb_vhci_work +{ + union + { + uint64_t handle; + struct usb_vhci_urb urb; + struct usb_vhci_port_stat port_stat; + } work; + + int type; +#define USB_VHCI_WORK_TYPE_PORT_STAT 0 +#define USB_VHCI_WORK_TYPE_PROCESS_URB 1 +#define USB_VHCI_WORK_TYPE_CANCEL_URB 2 +}; + +int usb_vhci_open(uint8_t port_count, + int32_t *id, + int32_t *usb_busnum, + char **bus_id) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_close(int fd) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_fetch_work(int fd, struct usb_vhci_work *work) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_fetch_data(int fd, const struct usb_vhci_urb *urb) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_giveback(int fd, const struct usb_vhci_urb *urb) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_port_connect(int fd, uint8_t port, uint8_t data_rate) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_port_disconnect(int fd, uint8_t port) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_port_disable(int fd, uint8_t port) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_port_resumed(int fd, uint8_t port) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_port_overcurrent(int fd, uint8_t port, uint8_t set) _LIB_USB_VHCI_NOTHROW; +int usb_vhci_port_reset_done(int fd, uint8_t port, uint8_t enable) _LIB_USB_VHCI_NOTHROW; + +#define usb_vhci_is_out(epadr) !((epadr) & 0x80) +#define usb_vhci_is_in(epadr) !!((epadr) & 0x80) +#define usb_vhci_is_iso(type) ((type) == USB_VHCI_URB_TYPE_ISO) +#define usb_vhci_is_int(type) ((type) == USB_VHCI_URB_TYPE_INT) +#define usb_vhci_is_control(type) ((type) == USB_VHCI_URB_TYPE_CONTROL) +#define usb_vhci_is_bulk(type) ((type) == USB_VHCI_URB_TYPE_BULK) + +#endif // _LIBUSB_VHCI_H + diff --git a/uisimulator/common/libusb_vhci/vhci-hcd.h b/uisimulator/common/libusb_vhci/vhci-hcd.h new file mode 100644 index 0000000..2271d2a --- /dev/null +++ b/uisimulator/common/libusb_vhci/vhci-hcd.h @@ -0,0 +1,222 @@ +/* + * vhci_hcd.h -- VHCI USB host controller driver header. + * + * Copyright (C) 2007-2008 Conemis AG Karlsruhe Germany + * Copyright (C) 2007-2009 Michael Singer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _VHCI_HCD_H +#define _VHCI_HCD_H + +#ifdef __KERNEL__ +# include +#else +# include +# define __u8 uint8_t +# define __s8 int8_t +# define __u16 uint16_t +# define __s16 int16_t +# define __u32 uint32_t +# define __s32 int32_t +# define __u64 uint64_t +# define __s64 int64_t +#endif +#include + +#ifndef __KERNEL__ + +// wPortStatus bit field +// See USB 2.0 spec Table 11-21 +#define USB_PORT_STAT_CONNECTION 0x0001 +#define USB_PORT_STAT_ENABLE 0x0002 +#define USB_PORT_STAT_SUSPEND 0x0004 +#define USB_PORT_STAT_OVERCURRENT 0x0008 +#define USB_PORT_STAT_RESET 0x0010 +#define USB_PORT_STAT_POWER 0x0100 +#define USB_PORT_STAT_LOW_SPEED 0x0200 +#define USB_PORT_STAT_HIGH_SPEED 0x0400 +//#define USB_PORT_STAT_TEST 0x0800 +//#define USB_PORT_STAT_INDICATOR 0x1000 + +// wPortChange bit field +// See USB 2.0 spec Table 11-22 +#define USB_PORT_STAT_C_CONNECTION 0x0001 +#define USB_PORT_STAT_C_ENABLE 0x0002 +#define USB_PORT_STAT_C_SUSPEND 0x0004 +#define USB_PORT_STAT_C_OVERCURRENT 0x0008 +#define USB_PORT_STAT_C_RESET 0x0010 + +#endif + +// structure for the VHCI_HCD_IOCREGISTER ioctl +struct vhci_ioc_register +{ + __s32 id; // [out] identifier which was assigned by the kernel + __s32 usb_busnum; // [out] assigned USB bus number + char bus_id[20]; // [out] null-terminated bus-id of the controller + // (something similar to vhci_hcd.) + __u8 port_count; // [in] number of ports the controller should have +}; + +struct vhci_ioc_port_stat +{ + __u16 status; // state of the port + __u16 change; // indicates changed status bits + __u8 index; // index of port + __u8 flags; // additional information from kernel to user space: +#define VHCI_IOC_PORT_STAT_FLAGS_RESUMING 0 // indicates resuming + __u8 reserved1, reserved2; // size of the struct should be dividable by four +}; + +struct vhci_ioc_setup_packet +{ + __u8 bmRequestType; + __u8 bRequest; + __u16 wValue; + __u16 wIndex; + __u16 wLength; +}; + +struct vhci_ioc_urb +{ + struct vhci_ioc_setup_packet setup_packet; // only for control urbs + __s32 buffer_length; // number of bytes which were + // allocated for the buffer + __s32 interval; + __s32 packet_count; // number of iso packets + __u16 flags; // flags: +#define VHCI_IOC_URB_FLAGS_SHORT_NOT_OK 0x0001 // IN: treat incomming short + // packets as an error +#define VHCI_IOC_URB_FLAGS_ISO_ASAP 0x0002 // ISO: schedule as soon as + // possible +#define VHCI_IOC_URB_FLAGS_ZERO_PACKET 0x0040 // BULK OUT: always send a + // short packet at the end + // (send a zero length packet + // if necessary) + __u8 address; // address of the usb device + // for which this urb is for + __u8 endpoint; // endpoint incl. direction + __u8 type; +#define VHCI_IOC_URB_TYPE_ISO 0 +#define VHCI_IOC_URB_TYPE_INT 1 +#define VHCI_IOC_URB_TYPE_CONTROL 2 +#define VHCI_IOC_URB_TYPE_BULK 3 +}; + +union vhci_ioc_work_union +{ + struct vhci_ioc_urb urb; // for VHCI_IOC_WORK_TYPE_PROCESS_URB + struct vhci_ioc_port_stat port; // for VHCI_IOC_WORK_TYPE_PORT_STAT +}; + +struct vhci_ioc_work +{ + __u64 handle; // for VHCI_IOC_WORK_TYPE_PROCESS_URB + // and VHCI_IOC_WORK_TYPE_CANCEL_URB; + // handle which identifies the urb + // (it is just a pointer to the urb + // in kernel space) + union vhci_ioc_work_union work; + __u8 type; +#define VHCI_IOC_WORK_TYPE_PORT_STAT 0 // the state of a port has changed +#define VHCI_IOC_WORK_TYPE_PROCESS_URB 1 // hand an urb to the (virtual) + // hardware +#define VHCI_IOC_WORK_TYPE_CANCEL_URB 2 // cancel urb if it isn't processed + // already +}; + +struct vhci_ioc_iso_packet_data +{ + __u32 offset; + __u32 packet_length; +}; + +struct vhci_ioc_urb_data +{ + __u64 handle; // handle which identifies the urb + void *buffer; // points to the beginning of the data buffer + struct vhci_ioc_iso_packet_data *iso_packets; // points to the beginning of + // the iso packet array + __s32 buffer_length; // number of bytes which were allocated for the buffer + __s32 packet_count; // number of iso packets +}; + +struct vhci_ioc_iso_packet_giveback +{ + __u32 packet_actual; + __s32 status; +}; + +struct vhci_ioc_giveback +{ + __u64 handle; + void *buffer; // only for IN URBs: the received data (for OUT URBs + // always a null pointer) + struct vhci_ioc_iso_packet_giveback *iso_packets; // for ISO + __s32 status; // (ignored for ISO URBs) + __s32 buffer_actual; // number of bytes which were actually transfered + // (for IN-ISOs buffer_actual has to be equal to + // buffer_length; for OUT-ISOs this value will be + // ignored) + __s32 packet_count; // for ISO (has to match with the value from the urb) + __s32 error_count; // for ISO +}; + +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +#include +struct vhci_ioc_urb_data32 +{ + __u64 handle; + compat_caddr_t buffer; + compat_caddr_t iso_packets; + __s32 buffer_length; + __s32 packet_count; +}; + +struct vhci_ioc_giveback32 +{ + __u64 handle; + compat_caddr_t buffer; + compat_caddr_t iso_packets; + __s32 status; + __s32 buffer_actual; + __s32 packet_count; + __s32 error_count; +}; +#endif +#endif + +#define VHCI_HCD_IOC_MAGIC 138 +#define VHCI_HCD_IOCREGISTER _IOWR(VHCI_HCD_IOC_MAGIC, 0, \ + struct vhci_ioc_register) +#define VHCI_HCD_IOCPORTSTAT _IOW (VHCI_HCD_IOC_MAGIC, 1, \ + struct vhci_ioc_port_stat) +#define VHCI_HCD_IOCFETCHWORK _IOR (VHCI_HCD_IOC_MAGIC, 2, \ + struct vhci_ioc_work) +#define VHCI_HCD_IOCGIVEBACK _IOW (VHCI_HCD_IOC_MAGIC, 3, \ + struct vhci_ioc_giveback) +#define VHCI_HCD_IOCGIVEBACK32 _IOW (VHCI_HCD_IOC_MAGIC, 3, \ + struct vhci_ioc_giveback32) +#define VHCI_HCD_IOCFETCHDATA _IOW (VHCI_HCD_IOC_MAGIC, 4, \ + struct vhci_ioc_urb_data) +#define VHCI_HCD_IOCFETCHDATA32 _IOW (VHCI_HCD_IOC_MAGIC, 4, \ + struct vhci_ioc_urb_data32) +#define VHCI_HCD_IOC_MAXNR 4 + +#endif + diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c index d1ec4ec..72c50a2 100644 --- a/uisimulator/common/stubs.c +++ b/uisimulator/common/stubs.c @@ -35,6 +35,8 @@ #include "ata.h" /* for volume definitions */ +#include "usb.h" /* for usb_detect and USB_EXTRACTED */ + extern char having_new_lcd; static bool storage_spinning = false; @@ -56,12 +58,25 @@ bool fat_ismounted(int volume) return true; } +void fat_init(void) +{ +} + +int fat_mount(IF_MV2(int volume,) IF_MD2(int drive,) long startsector) +{ + IF_MV2((void)volume,); + IF_MD2((void)drive,); + (void)startsector; + /* fails nicely */ + return -1; +} + int storage_init(void) { return 1; } -int storage_write_sectors(IF_MV2(int drive,) +int storage_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) @@ -83,7 +98,7 @@ int storage_write_sectors(IF_MV2(int drive,) return 1; } -int storage_read_sectors(IF_MV2(int drive,) +int storage_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) @@ -212,11 +227,6 @@ bool is_new_player(void) } #ifdef HAVE_USB_POWER -bool usb_powered(void) -{ - return false; -} - bool usb_charging_enable(bool on) { (void)on; @@ -250,13 +260,6 @@ bool charging_state(void) } #endif /* CONFIG_CHARGING */ -#ifndef USB_NONE -bool usb_inserted(void) -{ - return false; -} -#endif - #ifdef HAVE_REMOTE_LCD_TICKING void lcd_remote_emireduce(bool state) { @@ -336,3 +339,42 @@ void system_reboot(void) thread_sdl_exception_wait(); } +#ifdef USB_FIREWIRE_HANDLING +bool firewire_detect(void) +{ + return false; +} +#endif + +#ifdef HAVE_DISK_STORAGE +void storage_sleepnow(void) +{ +} +#endif + +#ifndef HAVE_USBSTACK +/* these are only called in usb.c is usb slave mode which is not handled by the simulator usb drive, so stub them */ +int storage_soft_reset(void) +{ + return 0; +} + +void storage_enable(bool on) +{ + (void)on; +} + +void usb_enable(bool on) +{ + (void)on; +} + +void usb_init_device(void) +{ +} + +int usb_detect(void) +{ + return USB_EXTRACTED; +} +#endif diff --git a/uisimulator/common/usb-drv.c b/uisimulator/common/usb-drv.c new file mode 100644 index 0000000..38f6088 --- /dev/null +++ b/uisimulator/common/usb-drv.c @@ -0,0 +1,854 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * USB driver for the simulator + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* parts of this driver are based on the usb-arc driver */ +/*#define USB_VHCI_DRIVER_DEBUG*/ + +#include "errno.h" +#include "libusb_vhci/libusb_vhci.h" + +#include "debug.h" +#include "kernel.h" +#include "string.h" +#include "usb_ch9.h" +#include "usb_core.h" +#include "usb_drv.h" + +#ifdef USB_VHCI_DRIVER_DEBUG +#define USB_DEBUGF DEBUGF +#else +#define USB_DEBUGF(...) ({}) +#endif + +/* endpoint direction */ +/* if an endpoint is a control endpoint, is must be bidirectional so only the [0] + * is used regardeless of the endpoint direction */ +struct usb_endpoint_t +{ + int type[2];/* type of endpoint, must be the same on both directions */ + bool allocated[2];/* is the endpoint allocated ? */ + bool has_urb[2];/* is there an pending URB ? */ + struct usb_vhci_urb urb[2];/* copy of the URB */ + void *buffer[2];/* is there a pending buffer ? NULL if no, address otherwise */ + int buffer_length[2];/* length of the buffer */ + struct usb_ctrlrequest setup_data;/* copy of setup data sent to core */ + struct mutex mutex[2];/* mutex for buffer/buffer_length/has_urb/urb */ + struct wakeup xfer_completion[2];/* wakeup for blocking transfers (see drv_send) */ + int xfer_status[2];/* status of the transfer (used for blocking transfers) */ + bool stalled[2];/* is endpoint stalled ? */ +}; + +static int vhci_hcd_fd = -1;/* handle of the vhci control device */ +static int usb_status = USB_UNPOWERED; +static const int vhci_hcd_port = 1; + +static const char vhci_hcd_thread_name[] = "vhci-hcd"; +static unsigned int vhci_hcd_thread_entry = 0; + +static struct usb_endpoint_t endpoints[USB_NUM_ENDPOINTS]; + +#define usb_vhci_ep_num(epadr) (epadr & 0x07) + +#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT") +#define XFER_TYPE_STR(type) \ + ((type) == USB_ENDPOINT_XFER_CONTROL ? "CTRL" : \ + ((type) == USB_ENDPOINT_XFER_ISOC ? "ISOC" : \ + ((type) == USB_ENDPOINT_XFER_BULK ? "BULK" : \ + ((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL")))) + +#define usb_vhci_type_str(type) \ + ((type) == USB_VHCI_URB_TYPE_CONTROL ? "CTRL" : \ + ((type) == USB_VHCI_URB_TYPE_ISO ? "ISOC" : \ + ((type) == USB_VHCI_URB_TYPE_BULK ? "BULK" : \ + ((type) == USB_VHCI_URB_TYPE_INT ? "INTR" : "INVL")))) + +#define usb_vhci_type_to_usb_xfr_type(type) \ + ((type) == USB_VHCI_URB_TYPE_CONTROL ? USB_ENDPOINT_XFER_CONTROL : \ + ((type) == USB_VHCI_URB_TYPE_ISO ? USB_ENDPOINT_XFER_ISOC : \ + ((type) == USB_VHCI_URB_TYPE_BULK ? USB_ENDPOINT_XFER_BULK : \ + ((type) == USB_VHCI_URB_TYPE_INT ? USB_ENDPOINT_XFER_INT : 4)))) + +static void bus_reset(void); + +/* general part */ +static void change_usb_status(int status) +{ + usb_status = status; + usb_status_event(status); +} + +void usb_attach(void) +{ + USB_DEBUGF("usb_attach\n"); + usb_drv_init(); +} + +int usb_detect(void) +{ + return usb_status; +} + +void usb_enable(bool on) +{ + USB_DEBUGF("usb_enable(%d)\n", on); + if(on) + { + usb_core_init(); + USB_DEBUGF("change usb status\n"); + change_usb_status(USB_INSERTED); + USB_DEBUGF("done\n"); + } + else + { + usb_core_exit(); + } +} + +static int stall_urb(struct usb_vhci_urb *urb) +{ + if(urb == NULL) + { + USB_DEBUGF("vhci-hcd: hey, I can't stall a NULL urb !\n"); + return -1; + } + urb->status = -EPIPE; + + USB_DEBUGF("vhci-hcd: stall urb on EP%d %s\n", usb_vhci_ep_num(urb->epadr), + XFER_DIR_STR(usb_vhci_is_in(urb->epadr))); + int ret= usb_vhci_giveback(vhci_hcd_fd, urb); + if(ret < 0) + USB_DEBUGF("vhci-hcd: giveback failed (ret=%d)!\n", ret); + return ret; +} + +static int complete_urb(struct usb_vhci_urb *urb) +{ + if(urb == NULL) + { + USB_DEBUGF("vhci-hcd: hey, I can't complete a NULL urb !\n"); + return -1; + } + urb->status = 0; + + USB_DEBUGF("vhci-hcd: complete urb on EP%d %s\n", usb_vhci_ep_num(urb->epadr), + XFER_DIR_STR(usb_vhci_is_in(urb->epadr))); + int ret= usb_vhci_giveback(vhci_hcd_fd, urb); + if(ret < 0) + USB_DEBUGF("vhci-hcd: giveback failed (ret=%d)!\n", ret); + return ret; +} + +static void clear_endpoint(int ep_num, bool ep_in) +{ + endpoints[ep_num].buffer[ep_in] = NULL; + endpoints[ep_num].buffer_length[ep_in] = 0; + endpoints[ep_num].has_urb[ep_in] = false; + memset(&endpoints[ep_num].urb[ep_in], 0, sizeof(struct usb_vhci_urb)); +} + +static int cancel_endpoint_urb(int ep_num, bool ep_in) +{ + /* FIXME seynchro issue here */ + if(!endpoints[ep_num].has_urb[ep_in]) + { + USB_DEBUGF("vhci-hcd: hey I can't meet up a NULL urb on EP%d %s !\n", ep_num, XFER_DIR_STR(ep_in)); + return -1; + } + + stall_urb(&endpoints[ep_num].urb[ep_in]); + clear_endpoint(ep_num, ep_in); + /* notify the core that the transfer failed */ + usb_core_transfer_complete(ep_num, ep_in ? USB_DIR_IN : USB_DIR_OUT, 1, 0); + + endpoints[ep_num].xfer_status[ep_in] = -1; + wakeup_signal(&endpoints[ep_num].xfer_completion[ep_in]); + + return 0; +} + +static int usb_meet_up(int ep_num, bool ep_in) +{ + /* WARNING: for control endpoints, ep_in=false because of ^^^^ */ + /* But, the real direction is still available in the urb */ + if(!endpoints[ep_num].has_urb[ep_in]) + { + USB_DEBUGF("vhci-hcd: hey I can't meet up a NULL urb on EP%d %s !\n", ep_num, XFER_DIR_STR(ep_in)); + return -1; + } + + if(endpoints[ep_num].buffer[ep_in] == NULL) + { + USB_DEBUGF("vhci-hcd: hey I can't meet up a NULL buffer EP%d %s\n", ep_num, XFER_DIR_STR(ep_in)); + return -1; + } + + struct usb_vhci_urb *urb = &endpoints[ep_num].urb[ep_in]; + void *buffer = endpoints[ep_num].buffer[ep_in]; + int buffer_length = endpoints[ep_num].buffer_length[ep_in]; + + if(ep_num != usb_vhci_ep_num(urb->epadr)) + { + USB_DEBUGF("vhci-hcd: WARNING: there is a problem, I complete on EP%d %s but the urb says it's on EP%d %s\n", + ep_num, XFER_DIR_STR(ep_in), usb_vhci_ep_num(urb->epadr), + XFER_DIR_STR(usb_vhci_is_in(urb->epadr))); + return -1; + } + + USB_DEBUGF("vhci-hcd: On EP%d %s, urb: buffer_length=%d buffer_actual=%d\n", ep_num, XFER_DIR_STR(ep_in), + urb->buffer_length, urb->buffer_actual); + USB_DEBUGF("vhci-hcd: buffer: ptr=%p buffer_length=%d\n", buffer, buffer_length); + + if(usb_vhci_is_in(urb->epadr)) + { + urb->buffer = buffer; + /* NOTE: for send(aka IN) transfers, buffer_actual is used ! */ + urb->buffer_actual = buffer_length; + + int ret = complete_urb(urb); + if(ret < 0) + USB_DEBUGF("vhci-hcd: meet up failed !\n"); + + USB_DEBUGF("vhci-hcd: transfer complete on EP%d IN, %d bytes transfered\n", ep_num, urb->buffer_actual); + usb_core_transfer_complete(ep_num, USB_DIR_IN, ret < 0 ? 1 : 0, urb->buffer_actual); + + clear_endpoint(ep_num, ep_in); + + endpoints[ep_num].xfer_status[ep_in] = ret; + wakeup_signal(&endpoints[ep_num].xfer_completion[ep_in]); + + return ret; + } + else + { + urb->buffer = buffer; + /* NOTE: for recv(aka OUT) transfers, buffer_length is used ! */ + urb->buffer_length = buffer_length; + + int ret = usb_vhci_fetch_data(vhci_hcd_fd, urb); + if(ret < 0) + USB_DEBUGF("vhci-hcd: fetch data failed (ret=%d)!\n", ret); + + USB_DEBUGF("vhci-hcd: transfer complete on EP%d OUT, %d bytes transfered\n", ep_num, urb->buffer_length); + usb_core_transfer_complete(ep_num, USB_DIR_OUT, ret < 0 ? 1 : 0, urb->buffer_length); + + if(ret < 0) + stall_urb(urb); + else + complete_urb(urb); + + clear_endpoint(ep_num, ep_in); + + endpoints[ep_num].xfer_status[ep_in] = ret; + wakeup_signal(&endpoints[ep_num].xfer_completion[ep_in]); + + return ret; + } +} + +static void dump_pending_urbs(void) +{ + #ifdef USB_VHCI_DRIVER_DEBUG + int ep_num; + int ep_in; + + USB_DEBUGF("[-----------pending URBs------------]\n"); + for(ep_num=0;ep_numtype), + usb_vhci_ep_num(urb->epadr), XFER_DIR_STR(usb_vhci_is_in(urb->epadr))); + } + } + } + USB_DEBUGF("[-----------------------------------]\n"); + #endif +} + +static void process_urb(struct usb_vhci_urb *urb) +{ + int ep_num = usb_vhci_ep_num(urb->epadr); + bool ep_in = usb_vhci_is_in(urb->epadr); + + dump_pending_urbs(); + + switch(urb->type) + { + case USB_VHCI_URB_TYPE_ISO: + USB_DEBUGF("Rockbox doesn't handle isochronous transfers !\n"); + stall_urb(urb); + break; + case USB_VHCI_URB_TYPE_INT: + case USB_VHCI_URB_TYPE_BULK: + { + USB_DEBUGF("vhci-hcd: %s transfer on EP%d %s\n", usb_vhci_type_str(urb->type), ep_num, XFER_DIR_STR(ep_in)); + + /* check that: + * -endpoint is allocated + * -urb type match endpoint type + * -endpoint is not stalled + * -endpoint has no pending urb + */ + if(!endpoints[ep_num].allocated[ep_in] || + endpoints[ep_num].type[ep_in] != usb_vhci_type_to_usb_xfr_type(urb->type) || + endpoints[ep_num].stalled[ep_in] || + endpoints[ep_num].has_urb[ep_in]) + { + /* */ + if(!endpoints[ep_num].allocated[ep_in]) + USB_DEBUGF("vhci-hcd: endpoint EP%d %s is not allocated\n", ep_num, XFER_DIR_STR(ep_in)); + else if(endpoints[ep_num].type[ep_in] != usb_vhci_type_to_usb_xfr_type(urb->type)) + USB_DEBUGF("vhci-hcd: endpoint EP%d %s is not a(n) %s endpoint\n", ep_num, XFER_DIR_STR(ep_in), + usb_vhci_type_str(urb->type)); + else if(endpoints[ep_num].stalled[ep_in]) + USB_DEBUGF("vhci-hcd: endpoint EP%d %s is stalled\n", ep_num, XFER_DIR_STR(ep_in)); + else if(endpoints[ep_num].has_urb[ep_in]) + USB_DEBUGF("vhci-hcd: endpoint EP%d %s is already busy with an urb\n", ep_num, XFER_DIR_STR(ep_in)); + /* */ + stall_urb(urb); + return; + } + + mutex_lock(&endpoints[ep_num].mutex[ep_in]); + /* endpoint is busy starting from now */ + endpoints[ep_num].has_urb[ep_in] = true; + /* copy urb */ + memcpy(&endpoints[ep_num].urb[ep_in], urb, sizeof(struct usb_vhci_urb)); + USB_DEBUGF("vhci-hcd: length=%d\n", urb->buffer_length); + + /* check if there is a pending buffer */ + /* FIXME there a synchronisation problem here */ + + if(endpoints[ep_num].buffer[ep_in] != NULL) + { + USB_DEBUGF("vhci-hcd: interrupt transfer with pending buffer, immediate handling\n"); + usb_meet_up(ep_num, ep_in); + } + else + { + USB_DEBUGF("vhci-hcd: interrupt transfer with no pending buffer, delayed handling\n"); + } + mutex_unlock(&endpoints[ep_num].mutex[ep_in]); + } + break; + case USB_VHCI_URB_TYPE_CONTROL: + { + struct usb_ctrlrequest *req = &endpoints[ep_num].setup_data; + /* control transfers use [0] instead of [ep_on] for urb and buffer */ + + USB_DEBUGF("vhci-hcd: control transfer\n"); + /* check that: + * -endpoint is allocated + * -urb type match endpoint type + * -endpoint is not stalled + * -endpoint has no pending urb + */ + if(!endpoints[ep_num].allocated[0] || + endpoints[ep_num].type[0] != usb_vhci_type_to_usb_xfr_type(urb->type) || + endpoints[ep_num].stalled[ep_in] || + endpoints[ep_num].has_urb[0]) + { + /* */ + if(!endpoints[ep_num].allocated[0]) + USB_DEBUGF("vhci-hcd: endpoint EP%d is not allocated\n", ep_num); + else if(endpoints[ep_num].type[0] != usb_vhci_type_to_usb_xfr_type(urb->type)) + USB_DEBUGF("vhci-hcd: endpoint EP%d is not a control endpoint\n", ep_num); + else if(endpoints[ep_num].stalled[ep_in]) + USB_DEBUGF("vhci-hcd: endpoint EP%d is stalled\n", ep_num); + else if(endpoints[ep_num].has_urb[0]) + USB_DEBUGF("vhci-hcd: endpoint EP%d is already busy with an urb\n", ep_num); + /* */ + stall_urb(urb); + return; + } + + /* endpoint is busy starting from now */ + endpoints[ep_num].has_urb[0] = true; + memcpy(&endpoints[ep_num].urb[0], urb, sizeof(struct usb_vhci_urb)); + + USB_DEBUGF("vhci-hcd: bmRequestType=0x%02x bRequest=0x%02x wValue=0x%04x\n", urb->bmRequestType, urb->bRequest, + urb->wValue); + USB_DEBUGF("vhci-hcd: wIndex=0x%04x wLength=0x%04x epadr=0x%02x urb_length=0x%x\n", urb->wIndex, + urb->wLength, urb->epadr, urb->buffer_length); + + req->bRequestType = urb->bmRequestType; + req->bRequest = urb->bRequest; + req->wValue = urb->wValue; + req->wIndex = urb->wIndex; + req->wLength = urb->wLength; + + if(ep_num == 0) + usb_core_control_request(req); + + /* FIXME should call usb_core_transfer_complete at some point ? */ + /* FIXME should handle no data control transfers only ? */ + USB_DEBUGF("vhci-hcd: Not sending a transfer complete message for now !\n"); + } + break; + default: + break; + } + + dump_pending_urbs(); +} + +#define USB_VHCI_PORT_STAT_TRIGGER_DISABLE 0x01 +#define USB_VHCI_PORT_STAT_TRIGGER_SUSPEND 0x02 +#define USB_VHCI_PORT_STAT_TRIGGER_RESUMING 0x04 +#define USB_VHCI_PORT_STAT_TRIGGER_RESET 0x08 +#define USB_VHCI_PORT_STAT_TRIGGER_POWER_ON 0x10 +#define USB_VHCI_PORT_STAT_TRIGGER_POWER_OFF 0x20 + +static uint16_t compute_trigger(uint16_t prev, uint16_t cur) +{ + uint16_t trigger = 0; + #define CHECK_GAIN(val, trig_val) if(!(prev & val) && (cur & val)) trigger |= trig_val; + #define CHECK_LOSS(val, trig_val) if((prev & val) && !(cur & val)) trigger |= trig_val; + + CHECK_LOSS(USB_VHCI_PORT_STAT_CONNECTION, USB_VHCI_PORT_STAT_TRIGGER_DISABLE) + CHECK_GAIN(USB_VHCI_PORT_STAT_SUSPEND, USB_VHCI_PORT_STAT_TRIGGER_SUSPEND) + CHECK_LOSS(USB_VHCI_PORT_STAT_SUSPEND, USB_VHCI_PORT_STAT_TRIGGER_RESUMING) + CHECK_GAIN(USB_VHCI_PORT_STAT_RESET, USB_VHCI_PORT_STAT_TRIGGER_RESET) + CHECK_GAIN(USB_VHCI_PORT_STAT_POWER, USB_VHCI_PORT_STAT_TRIGGER_POWER_ON) + CHECK_LOSS(USB_VHCI_PORT_STAT_POWER, USB_VHCI_PORT_STAT_TRIGGER_POWER_OFF) + + return trigger; +} + +static void vhci_hcd_thread(void) +{ + struct usb_vhci_work work; + uint16_t last_status = 0; + + while(1) + { + if(usb_vhci_fetch_work(vhci_hcd_fd, &work) < 0) + { + /* in case of repeat error, avoid using 100% cpu */ + sleep(HZ/10); + continue; + } + + if(work.type == USB_VHCI_WORK_TYPE_PORT_STAT) + { + uint16_t trigger = compute_trigger(last_status, work.work.port_stat.status); + last_status = work.work.port_stat.status; + + USB_DEBUGF("vhci-hcd: port: status:"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_CONNECTION) USB_DEBUGF(" connected"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_ENABLE) USB_DEBUGF(" enabled"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_SUSPEND) USB_DEBUGF(" suspended"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_OVERCURRENT) USB_DEBUGF(" overcurrent"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_RESET) USB_DEBUGF(" reset"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_POWER) USB_DEBUGF(" powered"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_LOW_SPEED) USB_DEBUGF(" low-speed"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_HIGH_SPEED) USB_DEBUGF(" high-speed"); + USB_DEBUGF("\n"); + USB_DEBUGF("vhci-hcd: port: change:"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_C_CONNECTION) USB_DEBUGF(" connected"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_C_ENABLE) USB_DEBUGF(" enabled"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_C_SUSPEND) USB_DEBUGF(" suspended"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_C_OVERCURRENT) USB_DEBUGF(" overcurrent"); + if(work.work.port_stat.status & USB_VHCI_PORT_STAT_C_RESET) USB_DEBUGF(" reset"); + USB_DEBUGF("\n"); + USB_DEBUGF("vhci-hcd: port: triggers:"); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_DISABLE) USB_DEBUGF(" disable"); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_SUSPEND) USB_DEBUGF(" suspend"); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_RESUMING) USB_DEBUGF(" resume"); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_RESET) USB_DEBUGF(" reset"); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_POWER_ON) USB_DEBUGF(" power-on"); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_POWER_OFF) USB_DEBUGF(" power-off"); + USB_DEBUGF("\n"); + + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_POWER_ON) + change_usb_status(USB_POWERED); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_POWER_OFF) + change_usb_status(USB_UNPOWERED); + if(trigger & USB_VHCI_PORT_STAT_TRIGGER_RESET) + bus_reset(); + } + else if(work.type == USB_VHCI_WORK_TYPE_PROCESS_URB) + { + /*USB_DEBUGF("vhci-hcd: process urb\n");*/ + process_urb(&work.work.urb); + } + else if(work.type == USB_VHCI_WORK_TYPE_CANCEL_URB) + { + USB_DEBUGF("vhci-hcd: cancel urb\n"); + /* Search for urb + * Note that during the search, the usb thread could complete the urb but that's not a problem */ + int ep_num, ep_in; + for(ep_num = 0; ep_num < USB_NUM_ENDPOINTS; ep_num++) + for(ep_in = 0; ep_in <= 1; ep_in++) + { + /* FIXME synchro issue here */ + if(endpoints[ep_num].has_urb[ep_in] && + endpoints[ep_num].urb[ep_in].handle == work.work.handle) + { + USB_DEBUGF("vhci-hcd: cancel urb on EP%d %s\n", ep_num, XFER_DIR_STR(ep_in)); + stall_urb(&endpoints[ep_num].urb[ep_in]); + clear_endpoint(ep_num, ep_in); + } + } + } + else + { + USB_DEBUGF("vhci-hcd: unknown work type\n"); + } + } +} + +static void usb_simulate_power() +{ + int32_t id,usb_busnum; + char *bus_id; + /* one port only */ + vhci_hcd_fd = usb_vhci_open(1, &id, &usb_busnum, &bus_id); + + if(vhci_hcd_fd >= 0) + { + USB_DEBUGF("usb-vhci: host controller at %d:%d (%s)\n", usb_busnum, id, bus_id); + vhci_hcd_thread_entry = create_thread(vhci_hcd_thread, NULL, 0, 0, vhci_hcd_thread_name); + } + else + USB_DEBUGF("usb-vhci: couldn't add host controller\n"); +} + +static void usb_simulate_unpower() +{ + change_usb_status(USB_UNPOWERED); +} + +void usb_ask(unsigned int what) +{ + USB_DEBUGF("usb_ask(%d)\n", what); + + switch(what) + { + case USB_ASK_SIMULATE_INSERTION: + usb_simulate_power(); + break; + case USB_ASK_SIMULATE_EXTRACTION: + usb_simulate_unpower(); + break; + default: + USB_DEBUGF(" unknown usb_ask request\n"); + } +} + +/* driver part */ +void usb_init_device(void) +{ + int ep_num, ep_dir; + USB_DEBUGF("usb_init_device\n"); + /* preallocate EP0 (to avoid special cases)*/ + endpoints[0].allocated[0] = endpoints[0].allocated[1] = true, + endpoints[0].type[0] = endpoints[0].type[1] = USB_ENDPOINT_XFER_CONTROL; + + /* init mutexes and wakeups */ + for(ep_num = 0; ep_num < USB_NUM_ENDPOINTS; ep_num++) + for(ep_dir = 0; ep_dir <= 1; ep_dir++) + { + mutex_init(&endpoints[ep_num].mutex[ep_dir]); + wakeup_init(&endpoints[ep_num].xfer_completion[ep_dir]); + } +} + +void usb_drv_init(void) +{ + USB_DEBUGF("usb_drv_init\n"); + + if(usb_vhci_port_connect(vhci_hcd_fd, vhci_hcd_port, USB_VHCI_DATA_RATE_HIGH) < 0) + { + USB_DEBUGF("usb: vhci-hcd: couldn't connect port !"); + return; + } +} + +void usb_drv_exit(void) +{ + USB_DEBUGF("usb_drv_exit\n"); + + usb_vhci_port_disconnect(vhci_hcd_fd, vhci_hcd_port); + usb_vhci_close(vhci_hcd_fd); +} + +static void bus_reset(void) +{ + int ep_num; + USB_DEBUGF("usb: bus reset\n"); + usb_core_bus_reset(); + usb_drv_cancel_all_transfers(); + + for(ep_num = 0; ep_num < USB_NUM_ENDPOINTS; ep_num++) + endpoints[ep_num].stalled[0] = endpoints[ep_num].stalled[1] = false; + + usb_vhci_port_reset_done(vhci_hcd_fd, vhci_hcd_port, 1); /* enable */ +} + +void usb_drv_stall(int endpoint, bool stall,bool in) +{ + USB_DEBUGF("usb: stall endpoint=%d stall=%d in=%d\n", endpoint, stall, in); + + endpoints[endpoint].stalled[in] = stall; + + if(endpoints[endpoint].type[in] == USB_ENDPOINT_XFER_CONTROL) + in = false; + + if(stall && endpoints[endpoint].has_urb[in]) + { + cancel_endpoint_urb(endpoint,in); + } +} + +bool usb_drv_stalled(int endpoint,bool in) +{ + USB_DEBUGF("usb: ask_stalled endpoint=%d in=%d\n", endpoint, in); + return endpoints[endpoint].stalled[in]; +} + +static int usb_drv_ack_send_recv(int num, bool in) +{ + if(num != 0 && !endpoints[num].allocated[in]) + { + USB_DEBUGF("usb: oops, endpoint EP%d %s is not allocated !\n", num, XFER_DIR_STR(in)); + return -1; + } + if(num != 0 && endpoints[num].type[in] != USB_ENDPOINT_XFER_CONTROL) + { + USB_DEBUGF("usb: oops, endpoint EP%d is not a control endpoint !\n", num); + return -1; + } + + /* ack can be used for two things: + * -ack the reception of a data packet and say that we're ready to read/write data + * -ack the reception of a nodata packet and say w've done + * + * The first kind of ack is useless here because there's no bus so we ignore it */ + + /* use [0], see previous comments */ + if(!endpoints[num].has_urb[0]) + { + USB_DEBUGF("usb: no pending urb to ack on EP%d\n", num); + return -1; + } + else + { + if(endpoints[num].urb[0].buffer_length != 0) + { + USB_DEBUGF("usb: ignore ack for data control message on EP%d\n", num); + return 0; + } + else + { + USB_DEBUGF("usb: ack urb on EP%d\n", num); + complete_urb(&endpoints[num].urb[0]); + clear_endpoint(num, 0); + return 0; + } + } +} + +static int usb_drv_send_recv(int epadr, bool send, void *ptr, int length, bool wait) +{ + /* check epadr */ + int ep_num = EP_NUM(epadr); + bool ep_in = (EP_DIR(epadr) == DIR_IN); + + /* EP0 is special */ + if(ep_num != 0 && ep_in != send) + { + USB_DEBUGF("usb: oops, I can't %s on EP%d %s !\n", send ? "send" : "recv", ep_num, XFER_DIR_STR(ep_in)); + return -1; + } + if(ep_num !=0 && !endpoints[ep_num].allocated[ep_in]) + { + USB_DEBUGF("usb: oops, EP%d %s is not allocated !\n", ep_num, XFER_DIR_STR(ep_in)); + return -1; + } + /* if control endpoint, set ep_in to false */ + if(endpoints[ep_num].type[ep_in] == USB_ENDPOINT_XFER_CONTROL) + ep_in = false; + + if(endpoints[ep_num].buffer[ep_in] != NULL) + { + USB_DEBUGF("usb: oops, send/recv on EP%d %s with already set buffer, overwrite !\n", + ep_num, XFER_DIR_STR(ep_in)); + } + + mutex_lock(&endpoints[ep_num].mutex[ep_in]); + endpoints[ep_num].buffer[ep_in] = ptr; + endpoints[ep_num].buffer_length[ep_in] = length; + + if(!endpoints[ep_num].has_urb[ep_in]) + { + mutex_unlock(&endpoints[ep_num].mutex[ep_in]); + USB_DEBUGF("usb: send/recv on EP%d %s with no urb: add pending buffer\n", ep_num, XFER_DIR_STR(ep_in)); + + if(wait) + { + /* wait for transfer completion */ + USB_DEBUGF("usb: wait for transfer completion...\n"); + + wakeup_wait(&endpoints[ep_num].xfer_completion[ep_in], TIMEOUT_BLOCK); + + USB_DEBUGF("usb: Back again on EP%d %s: wait finished, result is %d !\n", + ep_num, XFER_DIR_STR(ep_in), endpoints[ep_num].xfer_status[ep_in]); + return endpoints[ep_num].xfer_status[ep_in]; + } + else + return 0; + } + else + { + mutex_unlock(&endpoints[ep_num].mutex[ep_in]); + USB_DEBUGF("usb: send/recv on EP%d %s with urb: meet up !\n", ep_num, XFER_DIR_STR(ep_in)); + return usb_meet_up(ep_num, ep_in); + } + +} + +int usb_drv_send(int endpoint, void* ptr, int length) +{ + /* check for ack */ + if(ptr == NULL && length == 0) + return usb_drv_ack_send_recv(endpoint, false); + else + return usb_drv_send_recv(endpoint, true, ptr, length, true); +} + +int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) +{ + /* check for ack */ + if(ptr == NULL && length == 0) + return usb_drv_ack_send_recv(endpoint, false); + else + return usb_drv_send_recv(endpoint, true, ptr, length, false); +} + +int usb_drv_recv(int endpoint, void* ptr, int length) +{ + /* check for ack */ + if(ptr == NULL && length == 0) + return usb_drv_ack_send_recv(endpoint, true); + else + return usb_drv_send_recv(endpoint, false, ptr, length, false); +} + +void usb_drv_set_address(int address) +{ + USB_DEBUGF("usb: set_address addr=%d\n", address); + (void)address; +} + +int usb_drv_port_speed(void) +{ + USB_DEBUGF("usb: ask_port_speed\n"); + return 1; /* FIXME: 1 for high speed ? */ +} + +void usb_drv_cancel_all_transfers(void) +{ + USB_DEBUGF("usb: cancel_all_transfers\n"); + dump_pending_urbs(); + /* FIXME not sure it does the right thing */ + int ep_num, ep_in; + for(ep_num = 0; ep_num < USB_NUM_ENDPOINTS; ep_num++) + for(ep_in = 0; ep_in <= 1; ep_in++) + { + /* FIXME synchro issue here */ + if(!endpoints[ep_num].has_urb[ep_in]) + continue; + + cancel_endpoint_urb(ep_num, ep_in); + } +} + +void usb_drv_set_test_mode(int mode) +{ + USB_DEBUGF("usb: set_test_mode mode=%d, stub\n", mode); + (void)mode; +} + +bool usb_drv_connected(void) +{ + USB_DEBUGF("usb: ask_connected\n"); + return usb_status == USB_INSERTED; +} + +int usb_drv_request_endpoint(int type, int dir) +{ + int ep_num, ep_dir; + short ep_type; + + /* Safety */ + ep_dir = EP_DIR(dir); + ep_type = type & USB_ENDPOINT_XFERTYPE_MASK; + + USB_DEBUGF("usb: request %s %s\n", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type)); + + /* Find an available ep/dir pair */ + for(ep_num=1;ep_numallocated[ep_dir]) + continue; + + if(endpoint->allocated[other_dir] && + endpoint->type[other_dir] != ep_type) + /* different type */ + continue; + + endpoint->allocated[ep_dir] = true; + endpoint->type[ep_dir] = ep_type; + + /* clear everything */ + clear_endpoint(ep_num, ep_dir); + USB_DEBUGF("usb: allocate EP%d %s\n", ep_num, XFER_DIR_STR(ep_dir)); + return (ep_num | (dir & USB_ENDPOINT_DIR_MASK)); + } + + USB_DEBUGF("usb: fail to allocate\n"); + return -1; +} + +void usb_drv_release_endpoint(int ep) +{ + int ep_num = EP_NUM(ep); + int ep_dir = EP_DIR(ep); + + USB_DEBUGF("usb: release EP%d %s\n", ep_num, XFER_DIR_STR(ep_dir)); + /* don't release EP0 for technical reasons */ + if(ep_num != 0) + endpoints[ep_num].allocated[ep_dir] = false; +} + + diff --git a/uisimulator/sdl/button.c b/uisimulator/sdl/button.c index 2fbc41e..c888408 100644 --- a/uisimulator/sdl/button.c +++ b/uisimulator/sdl/button.c @@ -29,6 +29,7 @@ #include "misc.h" #include "sim_tasks.h" #include "button-sdl.h" +#include "usb.h" #include "debug.h" @@ -76,8 +77,10 @@ void button_event(int key, bool pressed) { int new_btn = 0; static bool usb_connected = false; + /* if (usb_connected && key != SDLK_u) return; + */ switch (key) { @@ -142,10 +145,13 @@ void button_event(int key, bool pressed) if (!pressed) { usb_connected = !usb_connected; +#if defined(HAVE_USBSTACK) + /* Broadcast because we don't have access to usb_queue. Only usb thread will treat the message */ if (usb_connected) - queue_post(&button_queue, SYS_USB_CONNECTED, 0); + queue_broadcast(USB_ASK, USB_ASK_SIMULATE_INSERTION); else - queue_post(&button_queue, SYS_USB_DISCONNECTED, 0); + queue_broadcast(USB_ASK, USB_ASK_SIMULATE_EXTRACTION); +#endif /* defined(HAVE_USBSTACK) */ } return; diff --git a/uisimulator/sdl/system-sdl.h b/uisimulator/sdl/system-sdl.h index 04e033e..905b2e4 100644 --- a/uisimulator/sdl/system-sdl.h +++ b/uisimulator/sdl/system-sdl.h @@ -39,6 +39,9 @@ int set_irq_level(int level); #define restore_irq(level) \ ((void)set_irq_level(level)) +#define cpu_idle_mode(on_off) + +void system_reboot(void); void sim_enter_irq_handler(void); void sim_exit_irq_handler(void); bool sim_kernel_init(void);