X-Git-Url: https://jxself.org/git/?p=linux-libre-firmware.git;a=blobdiff_plain;f=atusb%2Fusb%2Fusb.c;fp=atusb%2Fusb%2Fusb.c;h=543d8c286288ed94992ea7859e65c47ace066597;hp=0000000000000000000000000000000000000000;hb=dd4bc9ff49b9a7075e579fdd62fd930d27a9a7df;hpb=c164bf7f87f9081fee7e1a186dd7a87a9a020b9e diff --git a/atusb/usb/usb.c b/atusb/usb/usb.c new file mode 100644 index 0000000..543d8c2 --- /dev/null +++ b/atusb/usb/usb.c @@ -0,0 +1,181 @@ +/* + * fw/usb/usb.c - USB hardware setup and standard device requests + * + * Written 2008-2011, 2013, 2015 by Werner Almesberger + * Copyright 2008-2011, 2013, 2015 Werner Almesberger + * + * 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. + */ + +/* + * Known issues: + * - no suspend/resume + * - should support EP clearing and stalling + */ + +#include +#include + +#include "usb.h" +#include "board.h" + + +#ifndef NULL +#define NULL 0 +#endif + +#if 1 +extern void panic(void); +#define BUG_ON(cond) do { if (cond) panic(); } while (0) +#else +#define BUG_ON(cond) +#endif + +bool (*user_setup)(const struct setup_request *setup); +void (*user_set_interface)(int nth); +bool (*user_get_descriptor)(uint8_t type, uint8_t index, + const uint8_t **reply, uint8_t *size); +void (*user_reset)(void); + + +void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf, + uint8_t size, void (*callback)(void *user), void *user) +{ + BUG_ON(ep->state); + ep->state = state; + ep->buf = buf; + ep->end = buf+size; + ep->callback = callback; + ep->user = user; + usb_ep_change(ep); +} + + +static bool get_descriptor(uint8_t type, uint8_t index, uint16_t length) +{ + const uint8_t *reply; + uint8_t size; + + switch (type) { + case USB_DT_DEVICE: + reply = device_descriptor; + size = reply[0]; + break; + case USB_DT_CONFIG: + if (index) + return 0; + reply = config_descriptor; + size = reply[2]; + break; + default: + if (!user_get_descriptor) + return 0; + if (!user_get_descriptor(type, index, &reply, &size)) + return 0; + } + if (length < size) + size = length; + usb_send(&eps[0], reply, size, NULL, NULL); + return 1; +} + + +bool handle_setup(const struct setup_request *setup) +{ + switch (setup->bmRequestType | setup->bRequest << 8) { + + /* + * Device request + * + * See http://www.beyondlogic.org/usbnutshell/usb6.htm + */ + + case FROM_DEVICE(GET_STATUS): + if (setup->wLength != 2) + return 0; + usb_send(&eps[0], "\000", 2, NULL, NULL); + break; + case TO_DEVICE(CLEAR_FEATURE): + break; + case TO_DEVICE(SET_FEATURE): + return 0; + case TO_DEVICE(SET_ADDRESS): + set_addr(setup->wValue); + break; + case FROM_DEVICE(GET_DESCRIPTOR): + case FROM_INTERFACE(GET_DESCRIPTOR): + if (!get_descriptor(setup->wValue >> 8, setup->wValue, + setup->wLength)) + return 0; + break; + case TO_DEVICE(SET_DESCRIPTOR): + return 0; + case FROM_DEVICE(GET_CONFIGURATION): + usb_send(&eps[0], "", 1, NULL, NULL); + break; + case TO_DEVICE(SET_CONFIGURATION): + if (setup->wValue != config_descriptor[5]) + return 0; + break; + + /* + * Interface request + */ + + case FROM_INTERFACE(GET_STATUS): + return 0; + case TO_INTERFACE(CLEAR_FEATURE): + return 0; + case TO_INTERFACE(SET_FEATURE): + return 0; + case FROM_INTERFACE(GET_INTERFACE): + return 0; + case TO_INTERFACE(SET_INTERFACE): + { + const uint8_t *interface_descriptor = + config_descriptor+9; + const uint8_t *p; + int i; + + i = 0; + for (p = interface_descriptor; + p != config_descriptor+config_descriptor[2]; + p += p[0]) { + if (p[1] != USB_DT_INTERFACE) + continue; + if (p[2] == setup->wIndex && + p[3] == setup->wValue) { + if (user_set_interface) + user_set_interface(i); + return 1; + } + i++; + } + return 0; + } + break; + + /* + * Endpoint request + */ + + case FROM_ENDPOINT(GET_STATUS): + return 0; + case TO_ENDPOINT(CLEAR_FEATURE): + return 0; + case TO_ENDPOINT(SET_FEATURE): + return 0; + case FROM_ENDPOINT(SYNCH_FRAME): + return 0; + + default: + if (user_setup) + return user_setup(setup); + return 0; + } + + return 1; +}