You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

262 lines
7.7 KiB

#include "enumerate.h"
#include "enumerate_hub.h"
#include "enumerate_storage.h"
#include "protocol.h"
#include "work-area.h"
#include <string.h>
#include "print.h"
usb_error op_id_class_drv(_working *const working) __sdcccall(1);
usb_error op_parse_endpoint(_working *const working) __sdcccall(1);
static usb_error adv_to_next_desc(_working *const working, const uint8_t descriptor_type) __sdcccall(1) {
usb_descriptor_t *d;
const uint8_t *buffer_end = working->config.buffer + MAX_CONFIG_SIZE;
if (working->ptr >= buffer_end)
return USB_ERR_BUFF_TO_LARGE;
d = (usb_descriptor_t *)working->ptr;
do {
working->ptr += d->bLength;
if (working->ptr >= buffer_end)
return USB_ERR_BUFF_TO_LARGE;
d = (usb_descriptor_t *)working->ptr;
} while (d->bDescriptorType != descriptor_type);
if (working->ptr + d->bLength >= buffer_end)
return USB_ERR_BUFF_TO_LARGE;
return USB_ERR_OK;
}
void parse_endpoint_keyboard(device_config_keyboard *const keyboard_config, const endpoint_descriptor const *pEndpoint)
__sdcccall(1) {
endpoint_param *const ep = &keyboard_config->endpoints[0];
ep->number = pEndpoint->bEndpointAddress;
ep->toggle = 0;
ep->max_packet_sizex = calc_max_packet_sizex(pEndpoint->wMaxPacketSize);
}
usb_device_type identify_class_driver(_working *const working) {
const interface_descriptor *const p = (const interface_descriptor *)working->ptr;
if (p->bInterfaceClass == 2)
return USB_IS_CDC;
if (p->bInterfaceClass == 8 && (p->bInterfaceSubClass == 6 || p->bInterfaceSubClass == 5) && p->bInterfaceProtocol == 80)
return USB_IS_MASS_STORAGE;
if (p->bInterfaceClass == 8 && p->bInterfaceSubClass == 4 && p->bInterfaceProtocol == 0)
return USB_IS_FLOPPY;
if (p->bInterfaceClass == 9 && p->bInterfaceSubClass == 0 && p->bInterfaceProtocol == 0)
return USB_IS_HUB;
if (p->bInterfaceClass == 3)
return USB_IS_KEYBOARD;
return USB_IS_UNKNOWN;
}
usb_error op_interface_next(_working *const working) __z88dk_fastcall {
uint8_t result;
if (--working->interface_count == 0)
return USB_ERR_OK;
CHECK(adv_to_next_desc(working, USB_DESCR_INTERFACE));
return op_id_class_drv(working);
done:
return result;
}
usb_error op_endpoint_next(_working *const working) __sdcccall(1) {
usb_error result;
if (working->endpoint_count != 0 && --working->endpoint_count > 0) {
CHECK(adv_to_next_desc(working, USB_DESCR_ENDPOINT));
return op_parse_endpoint(working);
}
return op_interface_next(working);
done:
return result;
}
usb_error op_parse_endpoint(_working *const working) __sdcccall(1) {
const endpoint_descriptor *endpoint = (endpoint_descriptor *)working->ptr;
device_config *const device = working->p_current_device;
switch (working->usb_device) {
case USB_IS_FLOPPY:
case USB_IS_MASS_STORAGE: {
parse_endpoints((device_config_storage *)device, endpoint);
break;
}
case USB_IS_KEYBOARD: {
parse_endpoint_keyboard((device_config_keyboard *)device, endpoint);
break;
}
}
return op_endpoint_next(working);
}
usb_error
configure_device(const _working *const working, const interface_descriptor *const interface, device_config *const dev_cfg) {
dev_cfg->interface_number = interface->bInterfaceNumber;
dev_cfg->max_packet_size = working->desc.bMaxPacketSize0;
dev_cfg->address = working->current_device_address;
dev_cfg->type = working->usb_device;
return usbtrn_set_config(dev_cfg->address, dev_cfg->max_packet_size, working->config.desc.bConfigurationvalue);
}
usb_error op_cap_hub_drv_intf(_working *const working) __sdcccall(1) {
const interface_descriptor *const interface = (interface_descriptor *)working->ptr;
usb_error result;
device_config_hub hub_config;
working->hub_config = &hub_config;
hub_config.type = USB_IS_HUB;
CHECK(configure_device(working, interface, (device_config *const)&hub_config));
RETURN_CHECK(configure_usb_hub(working));
done:
return result;
}
usb_error op_cap_drv_intf(_working *const working) __z88dk_fastcall {
usb_error result;
_usb_state *const work_area = get_usb_work_area();
const interface_descriptor *const interface = (interface_descriptor *)working->ptr;
working->endpoint_count = interface->bNumEndpoints;
if (working->endpoint_count > 0)
CHECK(adv_to_next_desc(working, USB_DESCR_ENDPOINT));
working->p_current_device = NULL;
switch (working->usb_device) {
case USB_IS_HUB: {
CHECK(op_cap_hub_drv_intf(working))
break;
}
case USB_IS_UNKNOWN: {
device_config unkown_dev_cfg;
memset(&unkown_dev_cfg, 0, sizeof(device_config));
working->p_current_device = &unkown_dev_cfg;
CHECK(configure_device(working, interface, &unkown_dev_cfg));
break;
}
default: {
device_config *dev_cfg = find_first_free();
if (dev_cfg == NULL)
return USB_ERR_OUT_OF_MEMORY;
working->p_current_device = dev_cfg;
CHECK(configure_device(working, interface, dev_cfg));
break;
}
}
return op_parse_endpoint(working);
done:
return result;
}
usb_error op_id_class_drv(_working *const working) __sdcccall(1) {
const interface_descriptor *const ptr = (const interface_descriptor *)working->ptr;
if (ptr->bDescriptorType != USB_DESCR_INTERFACE)
return USB_ERR_FAIL;
working->usb_device = identify_class_driver(working);
return op_cap_drv_intf(working);
}
usb_error op_get_cfg_desc(_working *const working) __sdcccall(1) {
usb_error result;
const uint8_t max_packet_size = working->desc.bMaxPacketSize0;
memset(working->config.buffer, 0, MAX_CONFIG_SIZE);
working->ptr = working->config.buffer;
CHECK(usbtrn_gfull_cfg_desc(working->config_index, working->current_device_address, max_packet_size, MAX_CONFIG_SIZE,
working->config.buffer));
CHECK(adv_to_next_desc(working, USB_DESCR_INTERFACE));
working->interface_count = working->config.desc.bNumInterfaces;
return op_id_class_drv(working);
done:
return result;
}
usb_error read_all_configs(enumeration_state *const state) {
uint8_t result;
_usb_state *const work_area = get_usb_work_area();
_working working;
memset(&working, 0, sizeof(_working));
working.state = state;
CHECK(usbtrn_get_descriptor(&working.desc));
state->next_device_address++;
working.current_device_address = state->next_device_address;
CHECK(usbtrn_set_address(working.current_device_address));
for (uint8_t config_index = 0; config_index < working.desc.bNumConfigurations; config_index++) {
working.config_index = config_index;
CHECK(op_get_cfg_desc(&working));
}
return USB_ERR_OK;
done:
return result;
}
usb_error enumerate_all_devices(void) {
_usb_state *const work_area = get_usb_work_area();
enumeration_state state;
memset(&state, 0, sizeof(enumeration_state));
usb_error result = read_all_configs(&state);
work_area->count_of_detected_usb_devices = state.next_device_address;
done:
return result;
}
/*
enumerate_all_devices
-> read_all_configs
-> parse_config
-> op_get_cfg_desc
-> op_id_class_drv
-> op_cap_drv_intf (increment index)
-> op_parse_endpoint
-> parse_endpoints
-> parse_endpoint_hub
-> op_endpoint_next
-> op_parse_endpoint -^ (install driver endpoint)
-> op_interface_next
-> return
-> op_id_class_drv -^
*/