1 /* Copyright (c) 2011,2012 Simon Schubert <2@0x2c.org>.
2 * Modifications by Jacob Alexander 2014 <haata@kiibohd.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // ----- Compiler Includes -----
20 #include <sys/types.h>
25 // ----- Local Includes -----
28 #include "usb-internal.h"
32 // ----- Variables -----
34 static uint8_t ep0_buf[2][EP0_BUFSIZE] __attribute__((aligned(4)));
39 // ----- Functions -----
42 * Returns: 0 when this is was the last transfer, 1 if there is still
45 /* Defaults to EP0 for now */
46 static int usb_tx_next(struct usbd_ep_pipe_state_t *s)
50 * Us being here means the previous transfer just completed
51 * successfully. That means the host just toggled its data
52 * sync bit, and so do we.
56 if (s->transfer_size > 0) {
57 size_t thislen = s->transfer_size;
59 if (thislen > s->ep_maxsize)
60 thislen = s->ep_maxsize;
62 void *addr = s->data_buf + s->pos;
65 /* Bounce buffer mode */
67 memcpy(addr, s->copy_source + s->pos, thislen);
70 s->transfer_size -= thislen;
72 usb_queue_next(s, addr, thislen);
79 * All data has been shipped. Do we need to send a short
82 if (s->short_transfer) {
83 s->short_transfer = 0;
84 usb_queue_next(s, NULL, 0);
90 s->callback(s->data_buf, s->pos, s->callback_data);
95 static void setup_tx(struct usbd_ep_pipe_state_t *s, const void *buf, size_t len, size_t reqlen, ep_callback_t cb, void *cb_data)
97 s->data_buf = (void *)buf;
98 s->copy_source = NULL;
99 s->transfer_size = len;
102 s->callback_data = cb_data;
103 if (s->transfer_size > reqlen)
104 s->transfer_size = reqlen;
105 if (s->transfer_size < reqlen && s->transfer_size % s->ep_maxsize == 0)
106 s->short_transfer = 1;
108 s->short_transfer = 0;
111 static void submit_tx(struct usbd_ep_pipe_state_t *s)
113 /* usb_tx_next() flips the data toggle, so invert this here. */
119 * send USB data (IN device transaction)
121 * So far this function is specialized for EP 0 only.
123 * Returns: size to be transfered, or -1 on error.
125 int usb_tx(struct usbd_ep_pipe_state_t *s, const void *buf, size_t len, size_t reqlen, ep_callback_t cb, void *cb_data)
127 setup_tx(s, buf, len, reqlen, cb, cb_data);
129 return (s->transfer_size);
134 * Returns: 0 when this is was the last transfer, 1 if there is still
137 /* Defaults to EP0 for now */
138 /* XXX pass usb_stat to validate pingpong */
139 static int usb_rx_next(struct usbd_ep_pipe_state_t *s)
142 * Us being here means the previous transfer just completed
143 * successfully. That means the host just toggled its data
144 * sync bit, and so do we.
148 size_t thislen = usb_ep_get_transfer_size(s);
150 s->transfer_size -= thislen;
154 * We're done with this buffer now. Switch the pingpong now
155 * before we might have to receive the next piece of data.
160 * If this is a short transfer, or we received what we
161 * expected, we're done.
163 if (thislen < s->ep_maxsize || s->transfer_size == 0) {
165 s->callback(s->data_buf, s->pos, s->callback_data);
170 * Otherwise we still need to receive more data.
172 size_t nextlen = s->transfer_size;
174 if (nextlen > s->ep_maxsize)
175 nextlen = s->ep_maxsize;
177 void *addr = s->data_buf + s->pos;
178 usb_queue_next(s, addr, nextlen);
184 * Receive USB data (OUT device transaction)
186 * Returns: size to be received, or -1 on error.
188 int usb_rx(struct usbd_ep_pipe_state_t *s, void *buf, size_t len, ep_callback_t cb, void *cb_data)
191 s->transfer_size = len;
194 s->callback_data = cb_data;
196 size_t thislen = s->transfer_size;
197 if (thislen > s->ep_maxsize)
198 thislen = s->ep_maxsize;
200 usb_queue_next(s, s->data_buf, thislen);
204 int usb_ep0_tx_cp(const void *buf, size_t len, size_t reqlen, ep_callback_t cb, void *cb_data)
206 struct usbd_ep_pipe_state_t *s = &usb.ep_state[0].tx;
207 enum usb_ep_pingpong pp = s->pingpong;
209 setup_tx(s, ep0_buf[pp], len, reqlen, cb, cb_data);
210 s->copy_source = buf;
212 return (s->transfer_size);
215 void *usb_ep0_tx_inplace_prepare(size_t len)
217 enum usb_ep_pingpong pp = usb.ep_state[0].tx.pingpong;
219 if (len > EP0_BUFSIZE)
222 return (ep0_buf[pp]);
225 int usb_ep0_tx(void *buf, size_t len, size_t reqlen, ep_callback_t cb, void *cb_data)
227 return (usb_tx(&usb.ep_state[0].tx, buf, len, reqlen, cb, cb_data));
230 int usb_ep0_rx(void *buf, size_t len, ep_callback_t cb, void *cb_data)
232 return (usb_rx(&usb.ep_state[0].rx, buf, len, cb, cb_data));
236 const struct usbd_config *
237 usb_get_config_data(int config)
243 return (usb.identity->configs[config - 1]);
248 static int usb_set_config(int config)
250 const struct usbd_config *config_data;
252 if (usb.config != 0) {
253 config_data = usb_get_config_data(-1);
254 if (config_data != NULL && config_data->init != NULL)
255 config_data->init(0);
260 config_data = usb_get_config_data(config);
261 if (config_data != NULL && config_data->init != NULL)
262 config_data->init(1);
268 static int usb_set_interface(int iface, int altsetting)
272 for (struct usbd_function_ctx_header *fh = &usb.functions;
274 fh = fh->next, iface_count += fh->function->interface_count) {
275 if (iface - iface_count < fh->function->interface_count) {
276 if (fh->function->configure != NULL)
277 return (fh->function->configure(iface,
282 /* Default to a single altsetting */
293 static int usb_tx_config_desc(int idx, int reqlen)
295 const struct usb_desc_config_t *d = usb.identity->configs[idx]->desc;
297 usb_ep0_tx_cp(d, d->wTotalLength, reqlen, NULL, NULL);
301 static int usb_tx_string_desc(int idx, int reqlen)
303 const struct usb_desc_string_t * const *d;
305 for (d = usb.identity->string_descs; idx != 0 && *d != NULL; ++d)
307 switch ((uintptr_t)*d) {
308 case (uintptr_t)NULL:
310 case (uintptr_t)USB_DESC_STRING_SERIALNO:
311 return (usb_tx_serialno(reqlen));
313 usb_ep0_tx_cp(*d, (*d)->bLength, reqlen, NULL, NULL);
319 static void usb_handle_control_done(void *data, ssize_t len, void *cbdata)
321 if (usb.state == USBD_STATE_SETTING_ADDRESS) {
322 usb.state = USBD_STATE_ADDRESS;
323 usb_set_addr(usb.address);
328 void usb_handle_control_status_cb(ep_callback_t cb)
330 /* empty status transfer */
331 switch (usb.ctrl_dir) {
332 case USB_CTRL_REQ_IN:
333 usb.ep_state[0].rx.data01 = USB_DATA01_DATA1;
334 usb_rx(&usb.ep_state[0].rx, NULL, 0, cb, NULL);
338 usb.ep_state[0].tx.data01 = USB_DATA01_DATA1;
339 usb_ep0_tx_cp(NULL, 0, 1 /* short packet */, cb, NULL);
344 void usb_handle_control_status(int fail)
347 usb_pipe_stall(&usb.ep_state[0].rx);
348 usb_pipe_stall(&usb.ep_state[0].tx);
350 usb_handle_control_status_cb(usb_handle_control_done);
356 * Dispatch non-standard request to registered USB functions.
358 static void usb_handle_control_nonstd(struct usb_ctrl_req_t *req)
360 /* XXX filter by interface/endpoint? */
361 for (struct usbd_function_ctx_header *fh = &usb.functions; fh != NULL; fh = fh->next) {
362 /* ->control() returns != 0 if it handled the request */
363 if (fh->function->control != NULL &&
364 fh->function->control(req, fh))
368 usb_handle_control_status(-1);
374 * Great resource: http://wiki.osdev.org/Universal_Serial_Bus
379 * A control transfer consists of a SETUP transaction (1), zero or
380 * more data transactions (IN or OUT) (2), and a final status
383 * Token sequence (data toggle):
385 * (2a. OUT (1) ... (toggling))
390 * 2b. IN (1) ... (toggling)
393 * Report errors by STALLing the control EP after (1) or (2), so that
394 * (3) will STALL. Seems we need to clear the STALL after that so
395 * that the next SETUP can make it through.
401 * The following code is not written defensively, but instead only
402 * asserts values that are essential for correct execution. It
403 * accepts a superset of the protocol defined by the standard. We do
404 * this to save space.
407 static void usb_handle_control(void *data, ssize_t len, void *cbdata)
409 struct usb_ctrl_req_t *req = data;
413 usb.ctrl_dir = req->in;
415 if (req->type != USB_CTRL_REQ_STD) {
416 usb_handle_control_nonstd(req);
420 /* Only STD requests here */
421 switch (req->bRequest) {
422 case USB_CTRL_REQ_GET_STATUS:
424 * Because we don't support remote wakeup or
425 * self-powered operation, and we are specialized to
426 * only EP 0 so far, all GET_STATUS replies are just
429 usb_ep0_tx_cp(&zero16, sizeof(zero16), req->wLength, NULL, NULL);
432 case USB_CTRL_REQ_CLEAR_FEATURE:
433 case USB_CTRL_REQ_SET_FEATURE:
435 * Nothing to do. Maybe return STALLs on illegal
440 case USB_CTRL_REQ_SET_ADDRESS:
442 * We must keep our previous address until the end of
443 * the status stage; therefore we can't set the
444 * address right now. Since this is a special case,
445 * the EP 0 handler will take care of this later on.
447 usb.address = req->wValue & 0x7f;
448 usb.state = USBD_STATE_SETTING_ADDRESS;
451 case USB_CTRL_REQ_GET_DESCRIPTOR:
452 switch (req->wValue >> 8) {
454 usb_ep0_tx_cp(usb.identity->dev_desc, usb.identity->dev_desc->bLength,
455 req->wLength, NULL, NULL);
458 case USB_DESC_CONFIG:
459 fail = usb_tx_config_desc(req->wValue & 0xff, req->wLength);
461 case USB_DESC_STRING:
462 fail = usb_tx_string_desc(req->wValue & 0xff, req->wLength);
468 /* we set fail already, so we can go directly to `err' */
471 case USB_CTRL_REQ_GET_CONFIGURATION:
472 usb_ep0_tx_cp(&usb.config, 1, req->wLength, NULL, NULL); /* XXX implicit LE */
475 case USB_CTRL_REQ_SET_CONFIGURATION:
476 if (usb_set_config(req->wValue) < 0)
480 case USB_CTRL_REQ_GET_INTERFACE:
481 /* We only support iface setting 0 */
482 usb_ep0_tx_cp(&zero16, 1, req->wLength, NULL, NULL);
485 case USB_CTRL_REQ_SET_INTERFACE:
486 if (usb_set_interface(req->wIndex, req->wValue) < 0)
497 usb_handle_control_status(fail);
500 void usb_setup_control(void)
502 void *buf = ep0_buf[usb.ep_state[0].rx.pingpong];
504 usb.ep_state[0].rx.data01 = USB_DATA01_DATA0;
505 usb.ep_state[0].tx.data01 = USB_DATA01_DATA1;
506 usb_rx(&usb.ep_state[0].rx, buf, EP0_BUFSIZE, usb_handle_control, NULL);
511 * This is called by the interrupt handler
513 void usb_handle_transaction(struct usb_xfer_info *info)
515 enum usb_tok_pid pid = usb_get_xfer_pid(info);
516 struct usbd_ep_state_t *eps = &usb.ep_state[usb_get_xfer_ep(info)];
517 struct usbd_ep_pipe_state_t *s = &eps->pipe[usb_get_xfer_dir(info)];
523 * If we receive a SETUP transaction, but don't expect
524 * it (callback set to somewhere else), stall the EP.
526 if (pid == USB_PID_SETUP && s->callback != usb_handle_control)
527 usb_handle_control_status(1);
530 if (pid == USB_PID_SETUP)
541 struct usbd_ep_pipe_state_t *usb_init_ep(struct usbd_function_ctx_header *ctx, int ep, enum usb_ep_dir dir, size_t size)
543 struct usbd_ep_pipe_state_t *s;
545 if (dir == USB_EP_RX)
546 s = &usb.ep_state[ctx->ep_rx_offset + ep].rx;
548 s = &usb.ep_state[ctx->ep_tx_offset + ep].tx;
550 memset(s, 0, sizeof(*s));
551 s->ep_maxsize = size;
558 void usb_restart(void)
560 const struct usbd_device *identity = usb.identity;
561 /* XXX reset existing functions? */
562 memset(&usb, 0, sizeof(usb));
563 usb.functions.function = &usb.control_function;
564 usb.identity = identity;
565 usb_init_ep(&usb.functions, 0, USB_EP_RX, EP0_BUFSIZE);
566 usb_init_ep(&usb.functions, 0, USB_EP_TX, EP0_BUFSIZE);
570 void usb_attach_function(const struct usbd_function *function, struct usbd_function_ctx_header *ctx)
572 /* XXX right now this requires a sequential initialization */
573 struct usbd_function_ctx_header *prev = &usb.functions;
575 while (prev->next != NULL)
578 ctx->function = function;
579 ctx->interface_offset = prev->interface_offset + prev->function->interface_count;
580 ctx->ep_rx_offset = prev->ep_rx_offset + prev->function->ep_rx_count;
581 ctx->ep_tx_offset = prev->ep_tx_offset + prev->function->ep_tx_count;
585 void usb_init(const struct usbd_device *identity)
587 usb.identity = identity;