From f44cd059fb5d2b253d7eed24ff038f1d470f9fbb Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 14 Nov 2023 00:32:21 +0600 Subject: [PATCH] Commit as-is. Mouse funtional but very laggy for some odd reason --- src/chipset/via_pipc.c | 9 +- src/device/CMakeLists.txt | 2 +- src/device/mouse.c | 6 + src/device/mouse_usb.c | 396 ++++++++++++++++++++++++++++++++++++ src/include/86box/mouse.h | 1 + src/include/86box/usb.h | 14 ++ src/machine/machine_table.c | 38 ++-- src/usb.c | 244 +++++++++++++++++++++- src/usb_uhci_new.c | 21 +- 9 files changed, 698 insertions(+), 33 deletions(-) create mode 100644 src/device/mouse_usb.c diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 58f03b369f..ffd19da86c 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -1629,10 +1629,14 @@ static void * pipc_init(const device_t *info) { pipc_t *dev = (pipc_t *) malloc(sizeof(pipc_t)); + usb_params_t params; memset(dev, 0, sizeof(pipc_t)); pipc_log("PIPC: init()\n"); + params.pci_slot = dev->pci_slot; + params.pci_regs = dev->usb_regs[0]; + dev->local = info->local; pci_add_card(PCI_ADD_SOUTHBRIDGE, pipc_read, pipc_write, dev, &dev->pci_slot); @@ -1659,9 +1663,10 @@ pipc_init(const device_t *info) acpi_set_trap_update(dev->acpi, pipc_trap_update_586, dev); } - dev->usb[0] = device_add_inst(&usb_device, 1); + dev->usb[0] = device_add_inst_parameters(&usb_device, 1, ¶ms); if (dev->local >= VIA_PIPC_686A) { - dev->usb[1] = device_add_inst(&usb_device, 2); + params.pci_regs = dev->usb_regs[1]; + dev->usb[1] = device_add_inst_parameters(&usb_device, 2, ¶ms); dev->ac97 = device_add(&ac97_via_device); diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index 2988152c12..74c307bad2 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -21,7 +21,7 @@ add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c h smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c kbc_at.c kbc_at_dev.c keyboard_at.c - mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c + mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c mouse_usb.c phoenix_486_jumper.c serial_passthrough.c) if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") diff --git a/src/device/mouse.c b/src/device/mouse.c index 193149bc8b..300cf35563 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -94,6 +94,7 @@ static mouse_t mouse_devices[] = { { &mouse_msserial_device }, { &mouse_ltserial_device }, { &mouse_ps2_device }, + { &mouse_usb_device }, #ifdef USE_WACOM { &mouse_wacom_device }, { &mouse_wacom_artpad_device }, @@ -508,6 +509,8 @@ mouse_set_sample_rate(double new_rate) sample_rate = new_rate; if (mouse_timed) timer_on_auto(&mouse_timer, 1000000.0 / sample_rate); + + pclog("New sample rate is %f\n", new_rate); } /* Callback from the hardware driver. */ @@ -645,6 +648,9 @@ mouse_reset(void) if ((mouse_type > 1) && (mouse_curr != NULL)) mouse_priv = device_add(mouse_curr); + + if (mouse_priv == NULL) + mouse_curr = NULL; } void diff --git a/src/device/mouse_usb.c b/src/device/mouse_usb.c new file mode 100644 index 0000000000..5cdb4a81c9 --- /dev/null +++ b/src/device/mouse_usb.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/mouse.h> +#include <86box/serial.h> +#include <86box/plat.h> +#include <86box/fifo8.h> +#include <86box/mem.h> +#include <86box/usb.h> + +typedef struct usb_mouse_t +{ + int dx, dy, dz, buttons_state; + uint8_t idle; + uint16_t port; + uint16_t protocol; + int changed; + + usb_device_t device_instance; +} usb_mouse_t; + +static const usb_desc_string_t str_manufacturer = { + .base = { + .bDescriptorType = 0x03, + .bLength = 0x02 + ((sizeof("QEMU") - 1) * 2), + }, + .bString = { 'Q', 'E', 'M', 'U' } +}; + +static const usb_desc_string_t str_product = { + .base = { + .bDescriptorType = 0x03, + .bLength = sizeof(usb_desc_base_t) + ((sizeof("USB Mouse") - 1) * 2), + }, + .bString = { 'U', 'S', 'B', ' ', 'M', 'o', 'u', 's', 'e' } +}; + +static const usb_desc_string_t str_serialnumber = { + .base = { + .bDescriptorType = 0x03, + .bLength = 0x04, + }, + .bString = { '1' } +}; + +static const usb_desc_string_t str_langid = { + .base = { + .bDescriptorType = 0x03, + .bLength = 0x04, + }, + .bString = { 0x0409 } +}; + +static const uint8_t qemu_mouse_hid_report_descriptor[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xa1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (1) */ + 0x29, 0x05, /* Usage Maximum (5) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x05, /* Report Count (5) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data, Variable, Absolute) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x03, /* Report Size (3) */ + 0x81, 0x01, /* Input (Constant) */ + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x15, 0x81, /* Logical Minimum (-0x7f) */ + 0x25, 0x7f, /* Logical Maximum (0x7f) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x03, /* Report Count (3) */ + 0x81, 0x06, /* Input (Data, Variable, Relative) */ + 0xc0, /* End Collection */ + 0xc0, /* End Collection */ +}; + +static const usb_desc_endpoint_t usb_mouse_endpoint_desc = +{ + .base = { + .bLength = sizeof(usb_desc_endpoint_t), + .bDescriptorType = 0x05 + }, + + .bEndpointAddress = 0x81, + .bmAttributes = 0x03, + .wMaxPacketSize = 4, + .bInterval = 0xa +}; + +static const usb_desc_hid_t usb_mouse_hid_desc = +{ + .base = { + .bLength = sizeof(usb_desc_hid_t), + .bDescriptorType = 0x22 + }, + .bcdHID = 0x111, + .bCountryCode = 0x00, + .bNumDescriptors = 1, + .bDescriptorType = 0x22, + .wDescriptorLength = sizeof(qemu_mouse_hid_report_descriptor) +}; + +static const usb_desc_interface_t usb_mouse_interface_desc = +{ + .base = { + .bLength = sizeof(usb_desc_interface_t), + .bDescriptorType = 0x04 + }, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = 0x03, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x02, + .iInterface = 0 +}; + +static const usb_desc_conf_t usb_mouse_conf_desc = +{ + .base.bLength = sizeof(usb_desc_conf_t), + .base.bDescriptorType = 0x02, + .wTotalLength = sizeof(usb_desc_conf_t) + sizeof(usb_desc_interface_t) + sizeof(usb_desc_endpoint_t) + sizeof(usb_desc_hid_t), + + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80 | (1 << 5), + .bMaxPower = 50 +}; + +enum { + STR_MANUFACTURER = 1, + STR_PRODUCT, + STR_SERIALNUMBER, +}; + +static const usb_desc_device_t usb_mouse_device_desc = +{ + .base.bLength = sizeof(usb_desc_device_t), + .base.bDescriptorType = 0x01, /* Device descriptor. */ + + .bcdUSB = 0x0110, /* USB 1.1 */ + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize = 8, + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIALNUMBER, + .bNumConfigurations = 1, +}; + +static int +usb_mouse_poll(void *priv); + +static inline int int_clamp(int val, int vmin, int vmax) +{ + if (val < vmin) + return vmin; + else if (val > vmax) + return vmax; + else + return val; +} + +static int usb_mouse_poll_hid(usb_mouse_t *s, uint8_t *buf, int len) +{ + int dx, dy, dz, b, l; + + dx = int_clamp(s->dx, -128, 127); + dy = int_clamp(s->dy, -128, 127); + dz = int_clamp(s->dz, -128, 127); + + s->dx -= dx; + s->dy -= dy; + s->dz -= dz; + + b = s->buttons_state; + + buf[0] = b; + buf[1] = dx; + buf[2] = dy; + l = 3; + if (len >= 4) { + buf[3] = dz; + l = 4; + } + return l; +} + +uint8_t +usb_mouse_process_transfer(void* priv, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed) +{ + usb_mouse_t* usb_mouse = (usb_mouse_t*)priv; + //pclog("USB Mouse: Transfer (PID = 0x%X, len = %d, endpoint = %d)\n", pid_token, *len, endpoint); + if (endpoint == 0) { + if (pid_token == USB_PID_SETUP) { + usb_desc_setup_t* setup_packet = (usb_desc_setup_t*)data; + if (*len != 8) { + return *len > 8 ? USB_ERROR_OVERRUN : USB_ERROR_UNDERRUN; + } + usb_mouse->device_instance.setup_desc = *setup_packet; + + if (!(setup_packet->bmRequestType & 0x80) && !usb_mouse->device_instance.data_phase) + { + usb_mouse->device_instance.data_phase = 1; + return USB_ERROR_NO_ERROR; + } else if (!(setup_packet->bmRequestType & 0x80)) + usb_mouse->device_instance.data_phase = 0; + + //pclog("bmRequestType = 0x%X, \n", usb_mouse->device_instance.setup_desc.bmRequestType); + //pclog("bRequest = 0x%X, \n", usb_mouse->device_instance.setup_desc.bRequest); + //pclog("wIndex = 0x%X, \n", usb_mouse->device_instance.setup_desc.wIndex); + //pclog("wLength = 0x%X, \n", usb_mouse->device_instance.setup_desc.wLength); + //pclog("wValue = 0x%X\n", usb_mouse->device_instance.setup_desc.wValue); + if (setup_packet->bmRequestType == (USB_SETUP_TYPE_INTERFACE | 0x80) + && setup_packet->bRequest == USB_SETUP_GET_DESCRIPTOR) { + switch (setup_packet->wValue >> 8) { + case 0x22: { + fifo8_push_all(&usb_mouse->device_instance.fifo, qemu_mouse_hid_report_descriptor, sizeof(qemu_mouse_hid_report_descriptor)); + break; + } + default: + return usb_parse_control_endpoint(&usb_mouse->device_instance, data, len, pid_token, endpoint, underrun_not_allowed); + } + } + /* This is a odd one... */ + if (setup_packet->bmRequestType == (USB_SETUP_TYPE_ENDPOINT | 0x80) + && setup_packet->bRequest == USB_SETUP_GET_DESCRIPTOR + && setup_packet->wIndex == 1) { + switch (setup_packet->wValue >> 8) { + case 0x22: { + fifo8_push_all(&usb_mouse->device_instance.fifo, qemu_mouse_hid_report_descriptor, sizeof(qemu_mouse_hid_report_descriptor)); + break; + } + default: + return USB_ERROR_STALL; + } + } + else if (setup_packet->bmRequestType == 0xA1) { + fifo8_reset(&usb_mouse->device_instance.fifo); + switch(setup_packet->bRequest) { + case USB_SETUP_HID_GET_IDLE: + fifo8_push(&usb_mouse->device_instance.fifo, 0); + break; + case USB_SETUP_HID_GET_REPORT: + { + uint8_t buf[4]; + usb_mouse_poll_hid(usb_mouse, buf, 4); + fifo8_push_all(&usb_mouse->device_instance.fifo, buf, 4); + break; + } + case USB_SETUP_HID_GET_PROTOCOL: + { + fifo8_push(&usb_mouse->device_instance.fifo, usb_mouse->protocol); + break; + } + default: + return usb_parse_control_endpoint(&usb_mouse->device_instance, data, len, pid_token, endpoint, underrun_not_allowed); + } + } else if (setup_packet->bmRequestType == 0x21) { + switch (setup_packet->bRequest) { + case USB_SETUP_HID_SET_REPORT: + return USB_ERROR_STALL; + case USB_SETUP_HID_SET_PROTOCOL: + { + usb_mouse->protocol = setup_packet->wValue; + break; + } + case USB_SETUP_HID_SET_IDLE: + { + usb_mouse->idle = setup_packet->wValue >> 8; + break; + } + } + } else { + return usb_parse_control_endpoint(&usb_mouse->device_instance, data, len, pid_token, endpoint, underrun_not_allowed); + } + return USB_ERROR_NO_ERROR; + } + return usb_parse_control_endpoint(&usb_mouse->device_instance, data, len, pid_token, endpoint, underrun_not_allowed); + } else if (endpoint == 1 && pid_token == USB_PID_IN) { + pclog("Polled at %llu\n", plat_timer_read()); + //if ((!mouse_capture && !video_fullscreen) || (!mouse_state_changed())) + // return USB_ERROR_NAK; + usb_mouse_poll(usb_mouse); + *len = usb_mouse_poll_hid(usb_mouse, data, *len); + return USB_ERROR_NO_ERROR; + } + return USB_ERROR_STALL; +} + +static int +usb_mouse_poll(void *priv) +{ + usb_mouse_t *usb_mouse = priv; + + usb_mouse->dx = usb_mouse->dy = 0; + mouse_subtract_coords(&usb_mouse->dx, &usb_mouse->dy, NULL, NULL, -128, 127, 0, 0); + mouse_subtract_z(&usb_mouse->dz, -8, 7, 1); + usb_mouse->buttons_state = mouse_get_buttons_ex(); + + return (!mouse_capture && !video_fullscreen) || (!mouse_state_changed()); +} + +static void usb_mouse_handle_reset(void *priv) +{ + usb_mouse_t *usb_mouse = (usb_mouse_t *) priv; + + usb_mouse->dx = 0; + usb_mouse->dy = 0; + usb_mouse->dz = 0; + usb_mouse->buttons_state = 0; + usb_mouse->device_instance.address = 0; + usb_mouse->device_instance.current_configuration = 0; + + fifo8_reset(&usb_mouse->device_instance.fifo); + memset(&usb_mouse->device_instance.setup_desc, 0, sizeof(usb_desc_setup_t)); +} + +extern void uhci_attach(UHCIState *s, usb_device_t* device, int index); + +void* +usb_mouse_init(const device_t* info) +{ + usb_mouse_t* usb_mouse = (usb_mouse_t*)calloc(1, sizeof(usb_mouse_t)); + + usb_mouse->device_instance.string_desc[0] = &str_langid; + usb_mouse->device_instance.string_desc[STR_MANUFACTURER] = &str_manufacturer; + usb_mouse->device_instance.string_desc[STR_PRODUCT] = &str_product; + usb_mouse->device_instance.string_desc[STR_SERIALNUMBER] = &str_serialnumber; + usb_mouse->device_instance.string_desc[STR_SERIALNUMBER + 1] = NULL; + + usb_mouse->device_instance.conf_desc_items.conf_desc = usb_mouse_conf_desc; + usb_mouse->device_instance.conf_desc_items.other_descs[0] = &usb_mouse_interface_desc.base; + usb_mouse->device_instance.conf_desc_items.other_descs[1] = &usb_mouse_endpoint_desc.base; + usb_mouse->device_instance.conf_desc_items.other_descs[2] = &usb_mouse_hid_desc.base; + usb_mouse->device_instance.conf_desc_items.other_descs[3] = NULL; + + usb_mouse->device_instance.device_desc = usb_mouse_device_desc; + usb_mouse->device_instance.priv = usb_mouse; + usb_mouse->device_instance.device_reset = usb_mouse_handle_reset; + usb_mouse->device_instance.device_process = usb_mouse_process_transfer; + + fifo8_create(&usb_mouse->device_instance.fifo, 4096); + + usb_mouse->port = usb_attach_device(&usb_mouse->device_instance, USB_BUS_UHCI); + if (usb_mouse->port == (uint16_t)-1) { + pclog("No available USB ports\n"); + fifo8_destroy(&usb_mouse->device_instance.fifo); + free(usb_mouse); + return NULL; + } + mouse_set_buttons(4); + mouse_set_sample_rate(0); + usb_mouse_handle_reset(usb_mouse); + return usb_mouse; +} + +void +usb_mouse_close(void* priv) +{ + usb_mouse_t* usb_mouse = priv; + + fifo8_destroy(&usb_mouse->device_instance.fifo); + free(usb_mouse); +} + +const device_t mouse_usb_device = { + .name = "USB Mouse", + .internal_name = "usb_mouse", + .flags = DEVICE_USB, + .local = 0, + .init = usb_mouse_init, + .close = usb_mouse_close, + .reset = NULL, + { .poll = usb_mouse_poll }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/include/86box/mouse.h b/src/include/86box/mouse.h index 3ed6b2126e..ae002bfd82 100644 --- a/src/include/86box/mouse.h +++ b/src/include/86box/mouse.h @@ -73,6 +73,7 @@ extern const device_t mouse_ltserial_device; extern const device_t mouse_ps2_device; extern const device_t mouse_wacom_device; extern const device_t mouse_wacom_artpad_device; +extern const device_t mouse_usb_device; #endif extern void mouse_clear_x(void); diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index c0ea74d1d9..723cc197f5 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -187,6 +187,9 @@ typedef struct usb_device_t { uint8_t control_endpoint_pid; uint8_t current_configuration; usb_desc_setup_t setup_desc; + + // Is there a pending data phase? + uint8_t data_phase; void* priv; } usb_device_t; @@ -231,15 +234,26 @@ typedef struct usb_t { int ohci_enable; uint32_t ohci_mem_base; mem_mapping_t ohci_mmio_mapping; + int inst_cnt; usb_params_t params; } usb_t; +enum usb_bus_types +{ + USB_BUS_OHCI = 0, + USB_BUS_UHCI = 1, + USB_BUS_MAX = 2 +}; + /* Global variables. */ extern const device_t usb_device; /* Functions. */ extern void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable); extern void ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, int enable); +extern uint16_t usb_attach_device(usb_device_t* device, uint8_t bus_type); +void usb_detach_device(uint16_t port); +extern uint8_t usb_parse_control_endpoint(usb_device_t* usb_device, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed); #ifdef __cplusplus } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 3a9bfa72a8..8559ae396c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11187,7 +11187,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11228,7 +11228,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11269,7 +11269,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_A97, + .bus_flags = MACHINE_PS2_A97 | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11310,7 +11310,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11395,7 +11395,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11435,7 +11435,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11476,7 +11476,7 @@ const machine_t machines[] = { .min_multi = 2.0, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11515,7 +11515,7 @@ const machine_t machines[] = { .min_multi = 2.0, .max_multi = 5.5 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11557,7 +11557,7 @@ const machine_t machines[] = { .min_multi = 2.0, .max_multi = 3.5 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11599,7 +11599,7 @@ const machine_t machines[] = { .min_multi = 2.0, .max_multi = 3.5 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11639,7 +11639,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11681,7 +11681,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11766,7 +11766,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -11807,7 +11807,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -12434,7 +12434,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -12475,7 +12475,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -12516,7 +12516,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -12557,7 +12557,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, @@ -12687,7 +12687,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 8.0 }, - .bus_flags = MACHINE_PS2_AGP, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI, .ram = { .min = 8192, diff --git a/src/usb.c b/src/usb.c index 4822df5eda..4ea06351eb 100644 --- a/src/usb.c +++ b/src/usb.c @@ -50,12 +50,16 @@ usb_log(const char *fmt, ...) # define usb_log(fmt, ...) #endif +static usb_t* usb_device_inst[128]; +static uint8_t usb_device_inst_cnt = 0; + extern uint8_t uhci_reg_read(uint16_t addr, void *priv); extern uint16_t uhci_reg_readw(uint16_t addr, void *priv); extern void uhci_reg_write(uint16_t addr, uint8_t val, void *priv); extern void uhci_reg_writew(uint16_t addr, uint16_t val, void *priv); extern void uhci_reset(usb_t *dev); extern void uhci_frame_timer(void *opaque); +extern void uhci_detach(UHCIState *s, int index); void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable) @@ -302,6 +306,192 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, mem_mapping_set_addr(&dev->ohci_mmio_mapping, dev->ohci_mem_base, 0x1000); } +uint8_t +usb_parse_control_endpoint(usb_device_t* usb_device, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed) +{ + usb_desc_setup_t* setup_packet = (usb_desc_setup_t*)data; + uint8_t ret = USB_ERROR_STALL; + + if (endpoint != 0) + return USB_ERROR_STALL; + + if (!usb_device->fifo.data) { + fifo8_create(&usb_device->fifo, 4096); + } + //pclog("Control endpoint of device 0x%08X: Transfer (PID = 0x%X, len = %d)\n", usb_device, pid_token, *len); + switch (pid_token) { + case USB_PID_SETUP: + { + if (*len != 8) { + return *len > 8 ? USB_ERROR_OVERRUN : USB_ERROR_UNDERRUN; + } + usb_device->setup_desc = *setup_packet; + if (setup_packet->bmRequestType & 0x80) fifo8_reset(&usb_device->fifo); + //pclog("bmRequestType = 0x%X, \n", usb_device->setup_desc.bmRequestType); + //pclog("bRequest = 0x%X, \n", usb_device->setup_desc.bRequest); + //pclog("wIndex = 0x%X, \n", usb_device->setup_desc.wIndex); + //pclog("wLength = 0x%X, \n", usb_device->setup_desc.wLength); + //pclog("wValue = 0x%X\n", usb_device->setup_desc.wValue); + switch (setup_packet->bmRequestType & 0x1f) { + case USB_SETUP_TYPE_INTERFACE: + { + if (setup_packet->bmRequestType & 0x80) { + switch (setup_packet->bRequest) { + case USB_SETUP_GET_STATUS: { + ret = 0; + fifo8_push(&usb_device->fifo, 0x00); + fifo8_push(&usb_device->fifo, 0x00); + break; + } + case USB_SETUP_GET_INTERFACE: { + ret = 0; + fifo8_push(&usb_device->fifo, usb_device->interface_altsetting[setup_packet->wIndex]); + break; + } + } + } else { + switch (setup_packet->bRequest) { + case USB_SETUP_SET_FEATURE: + case USB_SETUP_CLEAR_FEATURE: { + ret = 0; + break; + } + case USB_SETUP_SET_INTERFACE: { + ret = 0; + usb_device->interface_altsetting[setup_packet->wIndex] = setup_packet->wValue; + break; + } + } + } + break; + } + case USB_SETUP_TYPE_ENDPOINT: + /* Consider it all handled. */ + if (setup_packet->bRequest == USB_SETUP_GET_STATUS && (setup_packet->bmRequestType & 0x80)) { + fifo8_push(&usb_device->fifo, 0x00); + fifo8_push(&usb_device->fifo, 0x00); + } + return 0; + case USB_SETUP_TYPE_DEVICE: + { + if (setup_packet->bmRequestType & 0x80) { + switch (setup_packet->bRequest) { + case USB_SETUP_GET_STATUS: { + fifo8_push_all(&usb_device->fifo, (uint8_t*)&usb_device->status_bits, sizeof(uint16_t)); + ret = 0; + break; + } + case USB_SETUP_GET_CONFIGURATION: { + fifo8_push(&usb_device->fifo, usb_device->current_configuration); + ret = 0; + break; + } + case USB_SETUP_GET_DESCRIPTOR: { + switch (setup_packet->wValue >> 8) { + case 0x01: /* Device descriptor */ + { + fifo8_push_all(&usb_device->fifo, (uint8_t*)&usb_device->device_desc, sizeof(usb_device->device_desc)); + ret = 0; + break; + } + case 0x02: /* Configuration descriptor (with all associated descriptors) */ + { + int i = 0; + ret = 0; + fifo8_push_all(&usb_device->fifo, (uint8_t*)&usb_device->conf_desc_items.conf_desc, usb_device->conf_desc_items.conf_desc.base.bLength); + for (i = 0; i < 16; i++) { + if (usb_device->conf_desc_items.other_descs[i] == NULL) + break; + + if (usb_device->conf_desc_items.other_descs[i]->bDescriptorType == 0xFF) { + fifo8_push_all(&usb_device->fifo, ((usb_desc_ptr_t*)usb_device->conf_desc_items.other_descs[i])->ptr, usb_device->conf_desc_items.other_descs[i]->bLength); + } + else + fifo8_push_all(&usb_device->fifo, (uint8_t*)usb_device->conf_desc_items.other_descs[i], usb_device->conf_desc_items.other_descs[i]->bLength); + } + break; + } + case 0x03: /* String descriptor */ + { + ret = 0; + if (!usb_device->string_desc[setup_packet->wValue & 0xff]) { + return USB_ERROR_STALL; + } + fifo8_push_all(&usb_device->fifo, (uint8_t*)usb_device->string_desc[setup_packet->wValue & 0xff], usb_device->string_desc[setup_packet->wValue & 0xff]->base.bLength); + break; + } + default: + return USB_ERROR_STALL; + } + break; + } + } + } else { + switch (setup_packet->bRequest) { + case USB_SETUP_SET_FEATURE: { + usb_device->status_bits |= (setup_packet->wValue & 0x1); + ret = 0; + break; + } + case USB_SETUP_CLEAR_FEATURE: { + usb_device->status_bits &= ~(setup_packet->wValue & 0x1); + ret = 0; + break; + } + case USB_SETUP_SET_ADDRESS: { + usb_device->address = setup_packet->wValue & 0xFF; + pclog("Device address @ 0x%llX set to %d\n", (intptr_t)usb_device, usb_device->address); + ret = 0; + break; + } + case USB_SETUP_SET_CONFIGURATION: { + usb_device->current_configuration = setup_packet->wValue & 0xFF; + ret = 0; + break; + } + } + } + break; + } + } + break; + } + case USB_PID_IN: { + const uint8_t* buf = NULL; + uint32_t used = 0; + if (!(usb_device->setup_desc.bmRequestType & 0x80)) { + if ((usb_device->setup_desc.wLength && fifo8_num_used(&usb_device->fifo) >= usb_device->setup_desc.wLength) || !usb_device->setup_desc.wLength) { + uint32_t len = 8; + return usb_device->device_process(usb_device->priv, (uint8_t*)&usb_device->setup_desc, &len, USB_PID_SETUP, 0, underrun_not_allowed); + } + else if (*len == 0) + return USB_ERROR_NO_ERROR; + else + return USB_ERROR_STALL; + } + if (fifo8_num_used(&usb_device->fifo) == 0) { + *len = 0; + return USB_ERROR_NO_ERROR; + } + buf = fifo8_pop_buf(&usb_device->fifo, *len, len); + memcpy(data, buf, *len); + ret = 0; + break; + } + case USB_PID_OUT: { + if (!(usb_device->setup_desc.bmRequestType & 0x80)) { + if (*len) + fifo8_push_all(&usb_device->fifo, data, *len); + return 0; + } + if ((usb_device->setup_desc.bmRequestType & 0x80) && *len != 0) + return USB_ERROR_STALL; + return 0; + } + } + return ret; +} + static void usb_reset(void *priv) { @@ -326,24 +516,55 @@ usb_close(void *priv) { usb_t *dev = (usb_t *) priv; + usb_device_inst[dev->inst_cnt] = NULL; + usb_device_inst_cnt--; free(dev); } extern void uhci_attach(UHCIState *s, usb_device_t* device, int index); -void usb_device_reset_dummy(void* priv) {} -uint8_t usb_device_process(void* priv, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed) +uint16_t usb_attach_device(usb_device_t* device, uint8_t bus_type) { - pclog("USB NAK\n"); - return USB_ERROR_NAK; + if (!usb_device_inst[0]) + return (uint16_t)-1; + + switch (bus_type) { + case USB_BUS_UHCI: + { + uint8_t i = 0; + for (i = 0; i < 2; i++) + { + if (!usb_device_inst[0]->uhci_state.ports[i].dev) + { + uhci_attach(&usb_device_inst[0]->uhci_state, device, i); + return (i) | (bus_type) << 8; + } + } + break; + } + default: + return (uint16_t)-1; + } + return (uint16_t)-1; } -usb_device_t dummy = +void +usb_detach_device(uint16_t port) { - .device_reset = usb_device_reset_dummy, - .device_process = usb_device_process, - .address = 0 -}; + if (!usb_device_inst[0]) + return; + + switch (port >> 8) { + case USB_BUS_UHCI: + { + uhci_detach(&usb_device_inst[0]->uhci_state, port & 0xFF); + break; + } + default: + return; + } + return; +} static void * usb_init(UNUSED(const device_t *info), void* param) @@ -373,7 +594,10 @@ usb_init(UNUSED(const device_t *info), void* param) } dev->uhci_state.dev = dev; usb_reset(dev); - uhci_attach(&dev->uhci_state, &dummy, 0); + //uhci_attach(&dev->uhci_state, &dummy, 0); + usb_device_inst[usb_device_inst_cnt] = dev; + dev->inst_cnt = usb_device_inst_cnt; + usb_device_inst_cnt++; return dev; } diff --git a/src/usb_uhci_new.c b/src/usb_uhci_new.c index 9d26409e72..f6e700c1c4 100644 --- a/src/usb_uhci_new.c +++ b/src/usb_uhci_new.c @@ -118,6 +118,20 @@ static void uhci_update_irq(UHCIState *s) { pci_irq(dev->params.pci_slot, PCI_INTD, 0, level, &s->irq_state); } +static void uhci_resume (void *opaque) +{ + UHCIState *s = (UHCIState *)opaque; + + if (!s) + return; + + if (s->cmd & UHCI_CMD_EGSM) { + s->cmd |= UHCI_CMD_FGR; + s->status |= UHCI_STS_RD; + uhci_update_irq(s); + } +} + void uhci_reset(usb_t *dev) { UHCIState *s = &dev->uhci_state; int i = 0; @@ -389,6 +403,7 @@ static int uhci_handle_td_error(UHCIState *s, UHCI_TD *td, uint32_t td_addr, uint32_t queue_token = uhci_queue_token(td); int ret; + //pclog("UHCI ERROR %d\n", status); switch (status) { case USB_ERROR_NAK: td->ctrl |= TD_CTRL_NAK; @@ -458,6 +473,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, int status, static usb_device_t *uhci_find_device(UHCIState *s, uint8_t addr) { int i = 0; + //pclog("Looking for device with addr %d\n", addr); for (i = 0; i < 2; i++) { if (!(s->ports[i].ctrl & UHCI_PORT_EN)) continue; @@ -466,6 +482,7 @@ static usb_device_t *uhci_find_device(UHCIState *s, uint8_t addr) { if (s->ports[i].dev->address == addr) return s->ports[i].dev; } + //pclog("None found.\n"); return NULL; } @@ -640,9 +657,10 @@ void uhci_attach(UHCIState *s, usb_device_t* device, int index) /* update speed */ { - port->ctrl |= UHCI_PORT_LSDA; + //port->ctrl |= UHCI_PORT_LSDA; } port->dev = device; + uhci_resume(s); } void uhci_detach(UHCIState *s, int index) @@ -660,4 +678,5 @@ void uhci_detach(UHCIState *s, int index) port->ctrl |= UHCI_PORT_ENC; } port->dev = NULL; + uhci_resume(s); }