source: mainline/uspace/drv/ohci/root_hub.c@ b330b309

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b330b309 was 0368669c, checked in by Matus Dekanek <smekideki@…>, 14 years ago

ohci root hub codelifting

  • Property mode set to 100644
File size: 20.2 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/** @addtogroup drvusbohci
29 * @{
30 */
31/** @file
32 * @brief OHCI driver
33 */
34#include <assert.h>
35#include <errno.h>
36#include <str_error.h>
37
38#include <usb/debug.h>
39
40#include "root_hub.h"
41#include "usb/classes/classes.h"
42#include <usb/request.h>
43#include <usb/classes/hub.h>
44
45/**
46 * standart device descriptor for ohci root hub
47 */
48static const usb_standard_device_descriptor_t ohci_rh_device_descriptor =
49{
50 .configuration_count = 1,
51 .descriptor_type = USB_DESCTYPE_DEVICE,
52 .device_class = USB_CLASS_HUB,
53 .device_protocol = 0,
54 .device_subclass = 0,
55 .device_version = 0,
56 .length = sizeof(usb_standard_device_descriptor_t),
57 /// \TODO this value is guessed
58 .max_packet_size = 8,
59 .vendor_id = 0x16db,
60 .product_id = 0x0001,
61 /// \TODO these values migt be different
62 .str_serial_number = 0,
63 .usb_spec_version = 0,
64};
65
66/**
67 * standart configuration descriptor with filled common values
68 * for ohci root hubs
69 */
70static const usb_standard_configuration_descriptor_t ohci_rh_conf_descriptor =
71{
72 /// \TODO some values are default or guessed
73 .attributes = 1<<7,
74 .configuration_number = 1,
75 .descriptor_type = USB_DESCTYPE_CONFIGURATION,
76 .interface_count = 1,
77 .length = sizeof(usb_standard_configuration_descriptor_t),
78 .max_power = 100,
79 .str_configuration = 0,
80};
81
82/**
83 * standart ohci root hub interface descriptor
84 */
85static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor =
86{
87 .alternate_setting = 0,
88 .descriptor_type = USB_DESCTYPE_INTERFACE,
89 .endpoint_count = 1,
90 .interface_class = USB_CLASS_HUB,
91 /// \TODO is this correct?
92 .interface_number = 1,
93 .interface_protocol = 0,
94 .interface_subclass = 0,
95 .length = sizeof(usb_standard_interface_descriptor_t),
96 .str_interface = 0,
97};
98
99/**
100 * standart ohci root hub endpoint descriptor
101 */
102static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor =
103{
104 .attributes = USB_TRANSFER_INTERRUPT,
105 .descriptor_type = USB_DESCTYPE_ENDPOINT,
106 .endpoint_address = 1 + (1<<7),
107 .length = sizeof(usb_standard_endpoint_descriptor_t),
108 .max_packet_size = 8,
109 .poll_interval = 255,
110};
111
112/** Root hub initialization
113 * @return Error code.
114 */
115int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs)
116{
117 assert(instance);
118 instance->address = -1;
119 instance->registers = regs;
120 instance->device = dev;
121
122
123 usb_log_info("OHCI root hub with %d ports.\n", regs->rh_desc_a & 0xff);
124
125 //start generic usb hub driver
126
127 /* TODO: implement */
128 return EOK;
129}
130/*----------------------------------------------------------------------------*/
131
132/**
133 * create answer to port status_request
134 *
135 * Copy content of corresponding port status register to answer buffer.
136 *
137 * @param instance root hub instance
138 * @param port port number, counted from 1
139 * @param request structure containing both request and response information
140 * @return error code
141 */
142static int process_get_port_status_request(rh_t *instance, uint16_t port,
143 usb_transfer_batch_t * request){
144 if(port<1 || port>instance->port_count)
145 return EINVAL;
146 uint32_t * uint32_buffer = (uint32_t*)request->buffer;
147 request->transfered_size = 4;
148 uint32_buffer[0] = instance->registers->rh_port_status[port -1];
149 return EOK;
150}
151
152/**
153 * create answer to port status_request
154 *
155 * Copy content of hub status register to answer buffer.
156 *
157 * @param instance root hub instance
158 * @param request structure containing both request and response information
159 * @return error code
160 */
161static int process_get_hub_status_request(rh_t *instance,
162 usb_transfer_batch_t * request){
163 uint32_t * uint32_buffer = (uint32_t*)request->buffer;
164 //bits, 0,1,16,17
165 request->transfered_size = 4;
166 uint32_t mask = 1 & (1<<1) & (1<<16) & (1<<17);
167 uint32_buffer[0] = mask & instance->registers->rh_status;
168 return EOK;
169
170}
171
172/**
173 * Create hub descriptor used in hub-driver <-> hub communication
174 *
175 * This means creating byt array from data in root hub registers. For more
176 * info see usb hub specification.
177 *
178 * @param instance root hub instance
179 * @param@out out_result pointer to resultant serialized descriptor
180 * @param@out out_size size of serialized descriptor
181 */
182static void usb_create_serialized_hub_descriptor(rh_t *instance,
183 uint8_t ** out_result,
184 size_t * out_size) {
185 //base size
186 size_t size = 7;
187 //variable size according to port count
188 size_t var_size = instance->port_count / 8 +
189 ((instance->port_count % 8 > 0) ? 1 : 0);
190 size += 2 * var_size;
191 uint8_t * result = (uint8_t*) malloc(size);
192 bzero(result,size);
193 //size
194 result[0] = size;
195 //descriptor type
196 result[1] = USB_DESCTYPE_HUB;
197 result[2] = instance->port_count;
198 uint32_t hub_desc_reg = instance->registers->rh_desc_a;
199 result[3] =
200 ((hub_desc_reg >> 8) %2) +
201 (((hub_desc_reg >> 9) %2) << 1) +
202 (((hub_desc_reg >> 10) %2) << 2) +
203 (((hub_desc_reg >> 11) %2) << 3) +
204 (((hub_desc_reg >> 12) %2) << 4);
205 result[4] = 0;
206 result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
207 result[6] = 50;
208
209 int port;
210 for (port = 1; port <= instance->port_count; ++port) {
211 result[7 + port/8] +=
212 ((instance->registers->rh_desc_b >> port)%2) << (port%8);
213 }
214 size_t i;
215 for (i = 0; i < var_size; ++i) {
216 result[7 + var_size + i] = 255;
217 }
218 (*out_result) = result;
219 (*out_size) = size;
220}
221
222
223/**
224 * create answer to status request
225 *
226 * This might be either hub status or port status request. If neither,
227 * ENOTSUP is returned.
228 * @param instance root hub instance
229 * @param request structure containing both request and response information
230 * @return error code
231 */
232static int process_get_status_request(rh_t *instance,
233 usb_transfer_batch_t * request)
234{
235 size_t buffer_size = request->buffer_size;
236 usb_device_request_setup_packet_t * request_packet =
237 (usb_device_request_setup_packet_t*)
238 request->setup_buffer;
239
240 usb_hub_bm_request_type_t request_type = request_packet->request_type;
241 if(buffer_size<4/*request_packet->length*/){///\TODO
242 usb_log_warning("requested more data than buffer size\n");
243 return EINVAL;
244 }
245
246 if(request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
247 return process_get_hub_status_request(instance, request);
248 if(request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
249 return process_get_port_status_request(instance, request_packet->index,
250 request);
251 return ENOTSUP;
252}
253
254/**
255 * create answer to status interrupt consisting of change bitmap
256 *
257 * Result contains bitmap where bit 0 indicates change on hub and
258 * bit i indicates change on i`th port (i>0). For more info see
259 * Hub and Port status bitmap specification in USB specification.
260 * @param instance root hub instance
261 * @param@out buffer pointer to created interrupt mas
262 * @param@out buffer_size size of created interrupt mask
263 */
264static void create_interrupt_mask(rh_t *instance, void ** buffer,
265 size_t * buffer_size){
266 int bit_count = instance->port_count + 1;
267 (*buffer_size) = (bit_count / 8) + (bit_count%8==0)?0:1;
268 (*buffer) = malloc(*buffer_size);
269 uint8_t * bitmap = (uint8_t*)(*buffer);
270 uint32_t mask = (1<<16) + (1<<17);
271 bzero(bitmap,(*buffer_size));
272 if(instance->registers->rh_status & mask){
273 bitmap[0] = 1;
274 }
275 int port;
276 mask = 0;
277 int i;
278 for(i=16;i<=20;++i)
279 mask += 1<<i;
280 for(port = 1; port<=instance->port_count;++port){
281 if(mask & instance->registers->rh_port_status[port-1]){
282 bitmap[(port+1)/8] += 1<<(port%8);
283 }
284 }
285}
286
287/**
288 * create standart configuration descriptor for the root hub instance
289 * @param instance root hub instance
290 * @return newly allocated descriptor
291 */
292static usb_standard_configuration_descriptor_t *
293usb_ohci_rh_create_standart_configuration_descriptor(rh_t *instance){
294 usb_standard_configuration_descriptor_t * descriptor =
295 malloc(sizeof(usb_standard_configuration_descriptor_t));
296 memcpy(descriptor, &ohci_rh_conf_descriptor,
297 sizeof(usb_standard_configuration_descriptor_t));
298 /// \TODO should this include device descriptor?
299 const size_t hub_descriptor_size = 7 +
300 2* (instance->port_count / 8 +
301 ((instance->port_count % 8 > 0) ? 1 : 0));
302 descriptor->total_length =
303 sizeof(usb_standard_configuration_descriptor_t)+
304 sizeof(usb_standard_endpoint_descriptor_t)+
305 sizeof(usb_standard_interface_descriptor_t)+
306 hub_descriptor_size;
307 return descriptor;
308}
309
310/**
311 * create answer to a descriptor request
312 *
313 * This might be a request for standard (configuration, device, endpoint or
314 * interface) or device specific (hub) descriptor.
315 * @param instance root hub instance
316 * @param request structure containing both request and response information
317 * @return error code
318 */
319static int process_get_descriptor_request(rh_t *instance,
320 usb_transfer_batch_t *request){
321 usb_device_request_setup_packet_t * setup_request =
322 (usb_device_request_setup_packet_t*)request->setup_buffer;
323 size_t size;
324 const void * result_descriptor = NULL;
325 const uint16_t setup_request_value = setup_request->value_high;
326 //(setup_request->value_low << 8);
327 bool del = false;
328 switch (setup_request_value)
329 {
330 case USB_DESCTYPE_HUB: {
331 uint8_t * descriptor;
332 usb_create_serialized_hub_descriptor(
333 instance, &descriptor, &size);
334 result_descriptor = descriptor;
335 if(result_descriptor) del = true;
336 break;
337 }
338 case USB_DESCTYPE_DEVICE: {
339 usb_log_debug("USB_DESCTYPE_DEVICE\n");
340 result_descriptor = &ohci_rh_device_descriptor;
341 size = sizeof(ohci_rh_device_descriptor);
342 break;
343 }
344 case USB_DESCTYPE_CONFIGURATION: {
345 usb_log_debug("USB_DESCTYPE_CONFIGURATION\n");
346 usb_standard_configuration_descriptor_t * descriptor =
347 usb_ohci_rh_create_standart_configuration_descriptor(
348 instance);
349 result_descriptor = descriptor;
350 size = sizeof(usb_standard_configuration_descriptor_t);
351 del = true;
352 break;
353 }
354 case USB_DESCTYPE_INTERFACE: {
355 usb_log_debug("USB_DESCTYPE_INTERFACE\n");
356 result_descriptor = &ohci_rh_iface_descriptor;
357 size = sizeof(ohci_rh_iface_descriptor);
358 break;
359 }
360 case USB_DESCTYPE_ENDPOINT: {
361 usb_log_debug("USB_DESCTYPE_ENDPOINT\n");
362 result_descriptor = &ohci_rh_ep_descriptor;
363 size = sizeof(ohci_rh_ep_descriptor);
364 break;
365 }
366 default: {
367 usb_log_debug("USB_DESCTYPE_EINVAL %d \n",setup_request->value);
368 usb_log_debug("\ttype %d\n\trequest %d\n\tvalue %d\n\tindex %d\n\tlen %d\n ",
369 setup_request->request_type,
370 setup_request->request,
371 setup_request_value,
372 setup_request->index,
373 setup_request->length
374 );
375 return EINVAL;
376 }
377 }
378 if(request->buffer_size < size){
379 size = request->buffer_size;
380 }
381 request->transfered_size = size;
382 memcpy(request->buffer,result_descriptor,size);
383 if (del)
384 free(result_descriptor);
385 return EOK;
386}
387
388/**
389 * answer to get configuration request
390 *
391 * Root hub works independently on the configuration.
392 * @param instance root hub instance
393 * @param request structure containing both request and response information
394 * @return error code
395 */
396static int process_get_configuration_request(rh_t *instance,
397 usb_transfer_batch_t *request){
398 //set and get configuration requests do not have any meaning, only dummy
399 //values are returned
400 if(request->buffer_size != 1)
401 return EINVAL;
402 request->buffer[0] = 1;
403 request->transfered_size = 1;
404 return EOK;
405}
406
407/**
408 * process feature-enabling/disabling request on hub
409 *
410 * @param instance root hub instance
411 * @param feature feature selector
412 * @param enable enable or disable specified feature
413 * @return error code
414 */
415static int process_hub_feature_set_request(rh_t *instance,
416 uint16_t feature, bool enable){
417 if(feature > USB_HUB_FEATURE_C_HUB_OVER_CURRENT)
418 return EINVAL;
419 instance->registers->rh_status =
420 enable ?
421 (instance->registers->rh_status | (1<<feature))
422 :
423 (instance->registers->rh_status & (~(1<<feature)));
424 /// \TODO any error?
425 return EOK;
426}
427
428/**
429 * process feature-enabling/disabling request on hub
430 *
431 * @param instance root hub instance
432 * @param feature feature selector
433 * @param port port number, counted from 1
434 * @param enable enable or disable the specified feature
435 * @return error code
436 */
437static int process_port_feature_set_request(rh_t *instance,
438 uint16_t feature, uint16_t port, bool enable){
439 if(feature > USB_HUB_FEATURE_C_PORT_RESET)
440 return EINVAL;
441 if(port<1 || port>instance->port_count)
442 return EINVAL;
443 instance->registers->rh_port_status[port - 1] =
444 enable ?
445 (instance->registers->rh_port_status[port - 1] | (1<<feature))
446 :
447 (instance->registers->rh_port_status[port - 1] & (~(1<<feature)));
448 /// \TODO any error?
449 return EOK;
450}
451
452/**
453 * register address to this device
454 *
455 * @param instance root hub instance
456 * @param address new address
457 * @return error code
458 */
459static int process_address_set_request(rh_t *instance,
460 uint16_t address){
461 instance->address = address;
462 return EOK;
463}
464
465/**
466 * process one of requests that requere output data
467 *
468 * Request can be one of USB_DEVREQ_GET_STATUS, USB_DEVREQ_GET_DESCRIPTOR or
469 * USB_DEVREQ_GET_CONFIGURATION.
470 * @param instance root hub instance
471 * @param request structure containing both request and response information
472 * @return error code
473 */
474static int process_request_with_output(rh_t *instance,
475 usb_transfer_batch_t *request){
476 usb_device_request_setup_packet_t * setup_request =
477 (usb_device_request_setup_packet_t*)request->setup_buffer;
478 if(setup_request->request == USB_DEVREQ_GET_STATUS){
479 usb_log_debug("USB_DEVREQ_GET_STATUS\n");
480 return process_get_status_request(instance, request);
481 }
482 if(setup_request->request == USB_DEVREQ_GET_DESCRIPTOR){
483 usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
484 return process_get_descriptor_request(instance, request);
485 }
486 if(setup_request->request == USB_DEVREQ_GET_CONFIGURATION){
487 usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
488 return process_get_configuration_request(instance, request);
489 }
490 return ENOTSUP;
491}
492
493/**
494 * process one of requests that carry input data
495 *
496 * Request can be one of USB_DEVREQ_SET_DESCRIPTOR or
497 * USB_DEVREQ_SET_CONFIGURATION.
498 * @param instance root hub instance
499 * @param request structure containing both request and response information
500 * @return error code
501 */
502static int process_request_with_input(rh_t *instance,
503 usb_transfer_batch_t *request){
504 usb_device_request_setup_packet_t * setup_request =
505 (usb_device_request_setup_packet_t*)request->setup_buffer;
506 request->transfered_size = 0;
507 if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR){
508 return ENOTSUP;
509 }
510 if(setup_request->request == USB_DEVREQ_SET_CONFIGURATION){
511 //set and get configuration requests do not have any meaning,
512 //only dummy values are returned
513 return EOK;
514 }
515 return ENOTSUP;
516}
517
518/**
519 * process one of requests that do not request nor carry additional data
520 *
521 * Request can be one of USB_DEVREQ_CLEAR_FEATURE, USB_DEVREQ_SET_FEATURE or
522 * USB_DEVREQ_SET_ADDRESS.
523 * @param instance root hub instance
524 * @param request structure containing both request and response information
525 * @return error code
526 */
527static int process_request_without_data(rh_t *instance,
528 usb_transfer_batch_t *request){
529 usb_device_request_setup_packet_t * setup_request =
530 (usb_device_request_setup_packet_t*)request->setup_buffer;
531 request->transfered_size = 0;
532 if(setup_request->request == USB_DEVREQ_CLEAR_FEATURE
533 || setup_request->request == USB_DEVREQ_SET_FEATURE){
534 if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE){
535 usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
536 return process_hub_feature_set_request(instance, setup_request->value,
537 setup_request->request == USB_DEVREQ_SET_FEATURE);
538 }
539 if(setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE){
540 usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
541 return process_port_feature_set_request(instance, setup_request->value,
542 setup_request->index,
543 setup_request->request == USB_DEVREQ_SET_FEATURE);
544 }
545 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",setup_request->request_type);
546 return EINVAL;
547 }
548 if(setup_request->request == USB_DEVREQ_SET_ADDRESS){
549 usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
550 return process_address_set_request(instance, setup_request->value);
551 }
552 usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",setup_request->request_type);
553 return ENOTSUP;
554}
555
556/**
557 * process hub control request
558 *
559 * If needed, writes answer into the request structure.
560 * Request can be one of
561 * USB_DEVREQ_GET_STATUS,
562 * USB_DEVREQ_GET_DESCRIPTOR,
563 * USB_DEVREQ_GET_CONFIGURATION,
564 * USB_DEVREQ_CLEAR_FEATURE,
565 * USB_DEVREQ_SET_FEATURE,
566 * USB_DEVREQ_SET_ADDRESS,
567 * USB_DEVREQ_SET_DESCRIPTOR or
568 * USB_DEVREQ_SET_CONFIGURATION.
569 *
570 * @param instance root hub instance
571 * @param request structure containing both request and response information
572 * @return error code
573 */
574static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request){
575 int opResult;
576 if (request->setup_buffer) {
577 if(sizeof(usb_device_request_setup_packet_t)>request->setup_size){
578 usb_log_error("setup packet too small\n");
579 return EINVAL;
580 }
581 usb_log_info("CTRL packet: %s.\n",
582 usb_debug_str_buffer((const uint8_t *)request->setup_buffer, 8, 8));
583 usb_device_request_setup_packet_t * setup_request =
584 (usb_device_request_setup_packet_t*)request->setup_buffer;
585 if(
586 setup_request->request == USB_DEVREQ_GET_STATUS
587 || setup_request->request == USB_DEVREQ_GET_DESCRIPTOR
588 || setup_request->request == USB_DEVREQ_GET_CONFIGURATION
589 ){
590 usb_log_debug("processing request with output\n");
591 opResult = process_request_with_output(instance,request);
592 }else if(
593 setup_request->request == USB_DEVREQ_CLEAR_FEATURE
594 || setup_request->request == USB_DEVREQ_SET_FEATURE
595 || setup_request->request == USB_DEVREQ_SET_ADDRESS
596 ){
597 usb_log_debug("processing request without additional data\n");
598 opResult = process_request_without_data(instance,request);
599 }else if(setup_request->request == USB_DEVREQ_SET_DESCRIPTOR
600 || setup_request->request == USB_DEVREQ_SET_CONFIGURATION
601 ){
602 usb_log_debug("processing request with input\n");
603 opResult = process_request_with_input(instance,request);
604 }else{
605 usb_log_warning("received unsuported request: %d\n",
606 setup_request->request
607 );
608 opResult = ENOTSUP;
609 }
610 }else{
611 usb_log_error("root hub received empty transaction?");
612 opResult = EINVAL;
613 }
614 return opResult;
615}
616
617/**
618 * process root hub request
619 *
620 * @param instance root hub instance
621 * @param request structure containing both request and response information
622 * @return error code
623 */
624int rh_request(rh_t *instance, usb_transfer_batch_t *request)
625{
626 assert(instance);
627 assert(request);
628 int opResult;
629 if(request->transfer_type == USB_TRANSFER_CONTROL){
630 usb_log_info("Root hub got CONTROL packet\n");
631 opResult = process_ctrl_request(instance,request);
632 }else if(request->transfer_type == USB_TRANSFER_INTERRUPT){
633 usb_log_info("Root hub got INTERRUPT packet\n");
634 void * buffer;
635 create_interrupt_mask(instance, &buffer,
636 &(request->transfered_size));
637 memcpy(request->transport_buffer,buffer, request->transfered_size);
638 opResult = EOK;
639 }else{
640 opResult = EINVAL;
641 }
642 usb_transfer_batch_finish(request, opResult);
643 return EOK;
644}
645/*----------------------------------------------------------------------------*/
646
647
648void rh_interrupt(rh_t *instance)
649{
650 usb_log_info("Whoa whoa wait, I`m not supposed to receive any interrupts, am I?\n");
651 /* TODO: implement? */
652}
653/**
654 * @}
655 */
Note: See TracBrowser for help on using the repository browser.