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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c4fb5ecd was c4fb5ecd, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

Less logging in USB host controller drivers

Many of the debug messages were degraded to debug2 level or
completely removed. Also added formatting string for unified
dump of USB transfer batches.

Warnings in EHCI stub use debug level now.

  • Property mode set to 100644
File size: 29.1 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/dev/driver.h>
43#include "ohci_regs.h"
44
45#include <usb/dev/request.h>
46#include <usb/classes/hub.h>
47
48/**
49 * standart device descriptor for ohci root hub
50 */
51static const usb_standard_device_descriptor_t ohci_rh_device_descriptor = {
52 .configuration_count = 1,
53 .descriptor_type = USB_DESCTYPE_DEVICE,
54 .device_class = USB_CLASS_HUB,
55 .device_protocol = 0,
56 .device_subclass = 0,
57 .device_version = 0,
58 .length = sizeof (usb_standard_device_descriptor_t),
59 .max_packet_size = 8,
60 .vendor_id = 0x16db,
61 .product_id = 0x0001,
62 .str_serial_number = 0,
63 .usb_spec_version = 0x110,
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 .attributes = 1 << 7,
72 .configuration_number = 1,
73 .descriptor_type = USB_DESCTYPE_CONFIGURATION,
74 .interface_count = 1,
75 .length = sizeof (usb_standard_configuration_descriptor_t),
76 .max_power = 100,
77 .str_configuration = 0,
78};
79
80/**
81 * standart ohci root hub interface descriptor
82 */
83static const usb_standard_interface_descriptor_t ohci_rh_iface_descriptor = {
84 .alternate_setting = 0,
85 .descriptor_type = USB_DESCTYPE_INTERFACE,
86 .endpoint_count = 1,
87 .interface_class = USB_CLASS_HUB,
88 .interface_number = 1,
89 .interface_protocol = 0,
90 .interface_subclass = 0,
91 .length = sizeof (usb_standard_interface_descriptor_t),
92 .str_interface = 0,
93};
94
95/**
96 * standart ohci root hub endpoint descriptor
97 */
98static const usb_standard_endpoint_descriptor_t ohci_rh_ep_descriptor = {
99 .attributes = USB_TRANSFER_INTERRUPT,
100 .descriptor_type = USB_DESCTYPE_ENDPOINT,
101 .endpoint_address = 1 + (1 << 7),
102 .length = sizeof (usb_standard_endpoint_descriptor_t),
103 .max_packet_size = 8,
104 .poll_interval = 255,
105};
106
107/**
108 * bitmask of hub features that are valid to be cleared
109 */
110static const uint32_t hub_clear_feature_valid_mask =
111 RHS_OCIC_FLAG |
112 RHS_CLEAR_PORT_POWER;
113
114/**
115 * bitmask of hub features that are cleared by writing 1 (and not 0)
116 */
117static const uint32_t hub_clear_feature_by_writing_one_mask =
118 RHS_CLEAR_PORT_POWER;
119
120/**
121 * bitmask of hub features that are valid to be set
122 */
123static const uint32_t hub_set_feature_valid_mask =
124 RHS_LPSC_FLAG |
125 RHS_OCIC_FLAG;
126
127/**
128 * bitmask of hub features that are set by writing 1 and cleared by writing 0
129 */
130static const uint32_t hub_set_feature_direct_mask =
131 RHS_SET_PORT_POWER;
132
133/**
134 * bitmask of port features that are valid to be set
135 */
136static const uint32_t port_set_feature_valid_mask =
137 RHPS_SET_PORT_ENABLE |
138 RHPS_SET_PORT_SUSPEND |
139 RHPS_SET_PORT_RESET |
140 RHPS_SET_PORT_POWER;
141
142/**
143 * bitmask of port features that can be cleared
144 */
145static const uint32_t port_clear_feature_valid_mask =
146 RHPS_CCS_FLAG |
147 RHPS_SET_PORT_SUSPEND |
148 RHPS_POCI_FLAG |
149 RHPS_SET_PORT_POWER |
150 RHPS_CSC_FLAG |
151 RHPS_PESC_FLAG |
152 RHPS_PSSC_FLAG |
153 RHPS_OCIC_FLAG |
154 RHPS_PRSC_FLAG;
155
156//note that USB_HUB_FEATURE_PORT_POWER bit is translated into
157//USB_HUB_FEATURE_PORT_LOW_SPEED for port set feature request
158
159/**
160 * bitmask with port status changes
161 */
162static const uint32_t port_status_change_mask = RHPS_CHANGE_WC_MASK;
163
164static int create_serialized_hub_descriptor(rh_t *instance);
165
166static int rh_init_descriptors(rh_t *instance);
167
168static int process_get_port_status_request(rh_t *instance, uint16_t port,
169 usb_transfer_batch_t * request);
170
171static int process_get_hub_status_request(rh_t *instance,
172 usb_transfer_batch_t * request);
173
174static int process_get_status_request(rh_t *instance,
175 usb_transfer_batch_t * request);
176
177static void create_interrupt_mask_in_instance(rh_t *instance);
178
179static int process_get_descriptor_request(rh_t *instance,
180 usb_transfer_batch_t *request);
181
182static int process_get_configuration_request(rh_t *instance,
183 usb_transfer_batch_t *request);
184
185static int process_hub_feature_set_request(rh_t *instance, uint16_t feature);
186
187static int process_hub_feature_clear_request(rh_t *instance,
188 uint16_t feature);
189
190static int process_port_feature_set_request(rh_t *instance,
191 uint16_t feature, uint16_t port);
192
193static int process_port_feature_clear_request(rh_t *instance,
194 uint16_t feature, uint16_t port);
195
196static int process_address_set_request(rh_t *instance,
197 uint16_t address);
198
199static int process_request_with_output(rh_t *instance,
200 usb_transfer_batch_t *request);
201
202static int process_request_with_input(rh_t *instance,
203 usb_transfer_batch_t *request);
204
205static int process_request_without_data(rh_t *instance,
206 usb_transfer_batch_t *request);
207
208static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
209
210static int process_interrupt_mask_in_instance(rh_t *instance, usb_transfer_batch_t * request);
211
212static bool is_zeros(void * buffer, size_t size);
213
214/** Root hub initialization
215 * @return Error code.
216 */
217int rh_init(rh_t *instance, ohci_regs_t *regs) {
218 assert(instance);
219 instance->registers = regs;
220 instance->port_count =
221 (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;
222 int opResult = rh_init_descriptors(instance);
223 if (opResult != EOK) {
224 return opResult;
225 }
226 // set port power mode to no-power-switching
227 instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
228 instance->unfinished_interrupt_transfer = NULL;
229 instance->interrupt_mask_size = (instance->port_count + 8) / 8;
230 instance->interrupt_buffer = malloc(instance->interrupt_mask_size);
231 if (!instance->interrupt_buffer)
232 return ENOMEM;
233
234 usb_log_info("Root hub (%zu ports) initialized.\n",
235 instance->port_count);
236
237 return EOK;
238}
239/*----------------------------------------------------------------------------*/
240
241/**
242 * process root hub request
243 *
244 * @param instance root hub instance
245 * @param request structure containing both request and response information
246 * @return error code
247 */
248int rh_request(rh_t *instance, usb_transfer_batch_t *request) {
249 assert(instance);
250 assert(request);
251 int opResult;
252 if (request->ep->transfer_type == USB_TRANSFER_CONTROL) {
253 usb_log_debug("Root hub got CONTROL packet\n");
254 opResult = process_ctrl_request(instance, request);
255 usb_transfer_batch_finish_error(request, opResult);
256 } else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) {
257 usb_log_debug("Root hub got INTERRUPT packet\n");
258 create_interrupt_mask_in_instance(instance);
259 if (is_zeros(instance->interrupt_buffer,
260 instance->interrupt_mask_size)) {
261 usb_log_debug("No changes..\n");
262 instance->unfinished_interrupt_transfer = request;
263 //will be finished later
264 } else {
265 usb_log_debug("Processing changes..\n");
266 process_interrupt_mask_in_instance(instance, request);
267 }
268 opResult = EOK;
269 } else {
270
271 opResult = EINVAL;
272 usb_transfer_batch_finish_error(request, opResult);
273 }
274 return EOK;
275}
276
277/*----------------------------------------------------------------------------*/
278
279/**
280 * process interrupt on a hub
281 *
282 * If there is no pending interrupt transfer, nothing happens.
283 * @param instance
284 */
285void rh_interrupt(rh_t *instance) {
286 if (!instance->unfinished_interrupt_transfer) {
287 return;
288 }
289 usb_log_debug("Finalizing interrupt transfer\n");
290 create_interrupt_mask_in_instance(instance);
291 process_interrupt_mask_in_instance(instance,
292 instance->unfinished_interrupt_transfer);
293}
294/*----------------------------------------------------------------------------*/
295
296/**
297 * Create hub descriptor used in hub-driver <-> hub communication
298 *
299 * This means creating byt array from data in root hub registers. For more
300 * info see usb hub specification.
301 *
302 * @param instance root hub instance
303 * @return error code
304 */
305static int create_serialized_hub_descriptor(rh_t *instance) {
306 size_t size = 7 +
307 ((instance->port_count + 7) / 8) * 2;
308 size_t var_size = (instance->port_count + 7) / 8;
309 uint8_t * result = (uint8_t*) malloc(size);
310 if (!result) return ENOMEM;
311
312 bzero(result, size);
313 //size
314 result[0] = size;
315 //descriptor type
316 result[1] = USB_DESCTYPE_HUB;
317 result[2] = instance->port_count;
318 uint32_t hub_desc_reg = instance->registers->rh_desc_a;
319 result[3] =
320 ((hub_desc_reg >> 8) % 2) +
321 (((hub_desc_reg >> 9) % 2) << 1) +
322 (((hub_desc_reg >> 10) % 2) << 2) +
323 (((hub_desc_reg >> 11) % 2) << 3) +
324 (((hub_desc_reg >> 12) % 2) << 4);
325 result[4] = 0;
326 result[5] = /*descriptor->pwr_on_2_good_time*/ 50;
327 result[6] = 50;
328
329 size_t port;
330 for (port = 1; port <= instance->port_count; ++port) {
331 uint8_t is_non_removable =
332 instance->registers->rh_desc_b >> port % 2;
333 result[7 + port / 8] +=
334 is_non_removable << (port % 8);
335 }
336 size_t i;
337 for (i = 0; i < var_size; ++i) {
338 result[7 + var_size + i] = 255;
339 }
340 instance->hub_descriptor = result;
341 instance->descriptor_size = size;
342
343 return EOK;
344}
345/*----------------------------------------------------------------------------*/
346
347/** initialize hub descriptors
348 *
349 * Initialized are device and full configuration descriptor. These need to
350 * be initialized only once per hub.
351 * @instance root hub instance
352 * @return error code
353 */
354static int rh_init_descriptors(rh_t *instance) {
355 memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
356 sizeof (ohci_rh_device_descriptor)
357 );
358 usb_standard_configuration_descriptor_t descriptor;
359 memcpy(&descriptor, &ohci_rh_conf_descriptor,
360 sizeof (ohci_rh_conf_descriptor));
361
362 int opResult = create_serialized_hub_descriptor(instance);
363 if (opResult != EOK) {
364 return opResult;
365 }
366 descriptor.total_length =
367 sizeof (usb_standard_configuration_descriptor_t) +
368 sizeof (usb_standard_endpoint_descriptor_t) +
369 sizeof (usb_standard_interface_descriptor_t) +
370 instance->descriptor_size;
371
372 uint8_t * full_config_descriptor =
373 (uint8_t*) malloc(descriptor.total_length);
374 if (!full_config_descriptor) {
375 return ENOMEM;
376 }
377 memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
378 memcpy(full_config_descriptor + sizeof (descriptor),
379 &ohci_rh_iface_descriptor, sizeof (ohci_rh_iface_descriptor));
380 memcpy(full_config_descriptor + sizeof (descriptor) +
381 sizeof (ohci_rh_iface_descriptor),
382 &ohci_rh_ep_descriptor, sizeof (ohci_rh_ep_descriptor));
383 memcpy(full_config_descriptor + sizeof (descriptor) +
384 sizeof (ohci_rh_iface_descriptor) +
385 sizeof (ohci_rh_ep_descriptor),
386 instance->hub_descriptor, instance->descriptor_size);
387
388 instance->descriptors.configuration = full_config_descriptor;
389 instance->descriptors.configuration_size = descriptor.total_length;
390
391 return EOK;
392}
393/*----------------------------------------------------------------------------*/
394
395/**
396 * create answer to port status_request
397 *
398 * Copy content of corresponding port status register to answer buffer. The
399 * format of the port status register and port status data is the same (
400 * see OHCI root hub and USB hub documentation).
401 *
402 * @param instance root hub instance
403 * @param port port number, counted from 1
404 * @param request structure containing both request and response information
405 * @return error code
406 */
407static int process_get_port_status_request(rh_t *instance, uint16_t port,
408 usb_transfer_batch_t * request) {
409 if (port < 1 || port > instance->port_count)
410 return EINVAL;
411 request->transfered_size = 4;
412 uint32_t data = instance->registers->rh_port_status[port - 1];
413 memcpy(request->data_buffer, &data, 4);
414 return EOK;
415}
416/*----------------------------------------------------------------------------*/
417
418/**
419 * create answer to port status_request
420 *
421 * This copies flags in hub status register into the buffer. The format of the
422 * status register and status message is the same, according to USB hub
423 * specification and OHCI root hub specification.
424 *
425 * @param instance root hub instance
426 * @param request structure containing both request and response information
427 * @return error code
428 */
429static int process_get_hub_status_request(rh_t *instance,
430 usb_transfer_batch_t * request) {
431 request->transfered_size = 4;
432 //bits, 0,1,16,17
433 uint32_t mask = 1 | (1 << 1) | (1 << 16) | (1 << 17);
434 uint32_t data = mask & instance->registers->rh_status;
435 memcpy(request->data_buffer, &data, 4);
436
437 return EOK;
438}
439/*----------------------------------------------------------------------------*/
440
441/**
442 * create answer to status request
443 *
444 * This might be either hub status or port status request. If neither,
445 * ENOTSUP is returned.
446 * @param instance root hub instance
447 * @param request structure containing both request and response information
448 * @return error code
449 */
450static int process_get_status_request(rh_t *instance,
451 usb_transfer_batch_t * request) {
452 size_t buffer_size = request->buffer_size;
453 usb_device_request_setup_packet_t * request_packet =
454 (usb_device_request_setup_packet_t*)
455 request->setup_buffer;
456
457 usb_hub_bm_request_type_t request_type = request_packet->request_type;
458 if (buffer_size < 4) {
459 usb_log_warning("Requested more data than buffer size\n");
460 return EINVAL;
461 }
462
463 if (request_type == USB_HUB_REQ_TYPE_GET_HUB_STATUS)
464 return process_get_hub_status_request(instance, request);
465 if (request_type == USB_HUB_REQ_TYPE_GET_PORT_STATUS)
466 return process_get_port_status_request(instance,
467 request_packet->index,
468 request);
469
470 return ENOTSUP;
471}
472/*----------------------------------------------------------------------------*/
473
474/**
475 * create answer to status interrupt consisting of change bitmap
476 *
477 * Result contains bitmap where bit 0 indicates change on hub and
478 * bit i indicates change on i`th port (i>0). For more info see
479 * Hub and Port status bitmap specification in USB specification
480 * (chapter 11.13.4).
481 * Uses instance`s interrupt buffer to store the interrupt information.
482 * @param instance root hub instance
483 */
484static void create_interrupt_mask_in_instance(rh_t * instance) {
485 uint8_t * bitmap = (uint8_t*) (instance->interrupt_buffer);
486 uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
487 | (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
488 bzero(bitmap, instance->interrupt_mask_size);
489 if ((instance->registers->rh_status & mask) != 0) {
490 bitmap[0] = 1;
491 }
492 size_t port;
493 mask = port_status_change_mask;
494 for (port = 1; port <= instance->port_count; ++port) {
495 if ((mask & instance->registers->rh_port_status[port - 1]) != 0) {
496
497 bitmap[(port) / 8] += 1 << (port % 8);
498 }
499 }
500}
501/*----------------------------------------------------------------------------*/
502
503/**
504 * create answer to a descriptor request
505 *
506 * This might be a request for standard (configuration, device, endpoint or
507 * interface) or device specific (hub) descriptor.
508 * @param instance root hub instance
509 * @param request structure containing both request and response information
510 * @return error code
511 */
512static int process_get_descriptor_request(rh_t *instance,
513 usb_transfer_batch_t *request) {
514 usb_device_request_setup_packet_t * setup_request =
515 (usb_device_request_setup_packet_t*) request->setup_buffer;
516 size_t size;
517 const void * result_descriptor = NULL;
518 const uint16_t setup_request_value = setup_request->value_high;
519 //(setup_request->value_low << 8);
520 switch (setup_request_value) {
521 case USB_DESCTYPE_HUB:
522 {
523 usb_log_debug2("USB_DESCTYPE_HUB\n");
524 result_descriptor = instance->hub_descriptor;
525 size = instance->descriptor_size;
526 break;
527 }
528 case USB_DESCTYPE_DEVICE:
529 {
530 usb_log_debug2("USB_DESCTYPE_DEVICE\n");
531 result_descriptor = &ohci_rh_device_descriptor;
532 size = sizeof (ohci_rh_device_descriptor);
533 break;
534 }
535 case USB_DESCTYPE_CONFIGURATION:
536 {
537 usb_log_debug2("USB_DESCTYPE_CONFIGURATION\n");
538 result_descriptor = instance->descriptors.configuration;
539 size = instance->descriptors.configuration_size;
540 break;
541 }
542 case USB_DESCTYPE_INTERFACE:
543 {
544 usb_log_debug2("USB_DESCTYPE_INTERFACE\n");
545 result_descriptor = &ohci_rh_iface_descriptor;
546 size = sizeof (ohci_rh_iface_descriptor);
547 break;
548 }
549 case USB_DESCTYPE_ENDPOINT:
550 {
551 usb_log_debug2("USB_DESCTYPE_ENDPOINT\n");
552 result_descriptor = &ohci_rh_ep_descriptor;
553 size = sizeof (ohci_rh_ep_descriptor);
554 break;
555 }
556 default:
557 {
558 usb_log_debug2("USB_DESCTYPE_EINVAL %d \n",
559 setup_request->value);
560 usb_log_debug2("\ttype %d\n\trequest %d\n\tvalue "
561 "%d\n\tindex %d\n\tlen %d\n ",
562 setup_request->request_type,
563 setup_request->request,
564 setup_request_value,
565 setup_request->index,
566 setup_request->length
567 );
568 return EINVAL;
569 }
570 }
571 if (request->buffer_size < size) {
572 size = request->buffer_size;
573 }
574 request->transfered_size = size;
575 memcpy(request->data_buffer, result_descriptor, size);
576
577 return EOK;
578}
579/*----------------------------------------------------------------------------*/
580
581/**
582 * answer to get configuration request
583 *
584 * Root hub works independently on the configuration.
585 * @param instance root hub instance
586 * @param request structure containing both request and response information
587 * @return error code
588 */
589static int process_get_configuration_request(rh_t *instance,
590 usb_transfer_batch_t *request) {
591 //set and get configuration requests do not have any meaning, only dummy
592 //values are returned
593 if (request->buffer_size != 1)
594 return EINVAL;
595 request->data_buffer[0] = 1;
596 request->transfered_size = 1;
597
598 return EOK;
599}
600/*----------------------------------------------------------------------------*/
601
602/**
603 * process feature-enabling request on hub
604 *
605 * @param instance root hub instance
606 * @param feature feature selector
607 * @return error code
608 */
609static int process_hub_feature_set_request(rh_t *instance,
610 uint16_t feature) {
611 if (!((1 << feature) & hub_set_feature_valid_mask))
612 return EINVAL;
613 if (feature == USB_HUB_FEATURE_C_HUB_LOCAL_POWER)
614 feature = USB_HUB_FEATURE_C_HUB_LOCAL_POWER << 16;
615 instance->registers->rh_status =
616 (instance->registers->rh_status | (1 << feature))
617 & (~hub_clear_feature_by_writing_one_mask);
618
619 return EOK;
620}
621/*----------------------------------------------------------------------------*/
622
623/**
624 * process feature-disabling request on hub
625 *
626 * @param instance root hub instance
627 * @param feature feature selector
628 * @return error code
629 */
630static int process_hub_feature_clear_request(rh_t *instance,
631 uint16_t feature) {
632 if (!((1 << feature) & hub_clear_feature_valid_mask))
633 return EINVAL;
634 //is the feature cleared directly?
635 if ((1 << feature) & hub_set_feature_direct_mask) {
636 instance->registers->rh_status =
637 (instance->registers->rh_status & (~(1 << feature)))
638 & (~hub_clear_feature_by_writing_one_mask);
639 } else {//the feature is cleared by writing '1'
640
641 instance->registers->rh_status =
642 (instance->registers->rh_status
643 & (~hub_clear_feature_by_writing_one_mask))
644 | (1 << feature);
645 }
646 return EOK;
647}
648/*----------------------------------------------------------------------------*/
649
650/**
651 * process feature-enabling request on hub
652 *
653 * @param instance root hub instance
654 * @param feature feature selector
655 * @param port port number, counted from 1
656 * @param enable enable or disable the specified feature
657 * @return error code
658 */
659static int process_port_feature_set_request(rh_t *instance,
660 uint16_t feature, uint16_t port) {
661 if (!((1 << feature) & port_set_feature_valid_mask))
662 return EINVAL;
663 if (port < 1 || port > instance->port_count)
664 return EINVAL;
665 instance->registers->rh_port_status[port - 1] =
666 (instance->registers->rh_port_status[port - 1] | (1 << feature))
667 & (~port_clear_feature_valid_mask);
668 return EOK;
669}
670/*----------------------------------------------------------------------------*/
671
672/**
673 * process feature-disabling request on hub
674 *
675 * @param instance root hub instance
676 * @param feature feature selector
677 * @param port port number, counted from 1
678 * @param enable enable or disable the specified feature
679 * @return error code
680 */
681static int process_port_feature_clear_request(rh_t *instance,
682 uint16_t feature, uint16_t port) {
683 if (!((1 << feature) & port_clear_feature_valid_mask))
684 return EINVAL;
685 if (port < 1 || port > instance->port_count)
686 return EINVAL;
687 if (feature == USB_HUB_FEATURE_PORT_POWER)
688 feature = USB_HUB_FEATURE_PORT_LOW_SPEED;
689 if (feature == USB_HUB_FEATURE_PORT_SUSPEND)
690 feature = USB_HUB_FEATURE_PORT_OVER_CURRENT;
691 instance->registers->rh_port_status[port - 1] =
692 (instance->registers->rh_port_status[port - 1]
693 & (~port_clear_feature_valid_mask))
694 | (1 << feature);
695
696 return EOK;
697}
698/*----------------------------------------------------------------------------*/
699
700/**
701 * register address to this device
702 *
703 * @param instance root hub instance
704 * @param address new address
705 * @return error code
706 */
707static int process_address_set_request(rh_t *instance,
708 uint16_t address) {
709 return ENOTSUP;
710}
711/*----------------------------------------------------------------------------*/
712
713/**
714 * process one of requests that requere output data
715 *
716 * Request can be one of USB_DEVREQ_GET_STATUS, USB_DEVREQ_GET_DESCRIPTOR or
717 * USB_DEVREQ_GET_CONFIGURATION.
718 * @param instance root hub instance
719 * @param request structure containing both request and response information
720 * @return error code
721 */
722static int process_request_with_output(rh_t *instance,
723 usb_transfer_batch_t *request) {
724 usb_device_request_setup_packet_t * setup_request =
725 (usb_device_request_setup_packet_t*) request->setup_buffer;
726 if (setup_request->request == USB_DEVREQ_GET_STATUS) {
727 usb_log_debug("USB_DEVREQ_GET_STATUS\n");
728 return process_get_status_request(instance, request);
729 }
730 if (setup_request->request == USB_DEVREQ_GET_DESCRIPTOR) {
731 usb_log_debug("USB_DEVREQ_GET_DESCRIPTOR\n");
732 return process_get_descriptor_request(instance, request);
733 }
734 if (setup_request->request == USB_DEVREQ_GET_CONFIGURATION) {
735 usb_log_debug("USB_DEVREQ_GET_CONFIGURATION\n");
736
737 return process_get_configuration_request(instance, request);
738 }
739 return ENOTSUP;
740}
741/*----------------------------------------------------------------------------*/
742
743/**
744 * process one of requests that carry input data
745 *
746 * Request can be one of USB_DEVREQ_SET_DESCRIPTOR or
747 * USB_DEVREQ_SET_CONFIGURATION.
748 * @param instance root hub instance
749 * @param request structure containing both request and response information
750 * @return error code
751 */
752static int process_request_with_input(rh_t *instance,
753 usb_transfer_batch_t *request) {
754 usb_device_request_setup_packet_t * setup_request =
755 (usb_device_request_setup_packet_t*) request->setup_buffer;
756 request->transfered_size = 0;
757 if (setup_request->request == USB_DEVREQ_SET_DESCRIPTOR) {
758 return ENOTSUP;
759 }
760 if (setup_request->request == USB_DEVREQ_SET_CONFIGURATION) {
761 //set and get configuration requests do not have any meaning,
762 //only dummy values are returned
763
764 return EOK;
765 }
766 return ENOTSUP;
767}
768/*----------------------------------------------------------------------------*/
769
770/**
771 * process one of requests that do not request nor carry additional data
772 *
773 * Request can be one of USB_DEVREQ_CLEAR_FEATURE, USB_DEVREQ_SET_FEATURE or
774 * USB_DEVREQ_SET_ADDRESS.
775 * @param instance root hub instance
776 * @param request structure containing both request and response information
777 * @return error code
778 */
779static int process_request_without_data(rh_t *instance,
780 usb_transfer_batch_t *request) {
781 usb_device_request_setup_packet_t * setup_request =
782 (usb_device_request_setup_packet_t*) request->setup_buffer;
783 request->transfered_size = 0;
784 if (setup_request->request == USB_DEVREQ_CLEAR_FEATURE) {
785 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
786 usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
787 return process_hub_feature_clear_request(instance,
788 setup_request->value);
789 }
790 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
791 usb_log_debug2("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
792 return process_port_feature_clear_request(instance,
793 setup_request->value,
794 setup_request->index);
795 }
796 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
797 setup_request->request_type);
798 return EINVAL;
799 }
800 if (setup_request->request == USB_DEVREQ_SET_FEATURE) {
801 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_HUB_FEATURE) {
802 usb_log_debug("USB_HUB_REQ_TYPE_SET_HUB_FEATURE\n");
803 return process_hub_feature_set_request(instance,
804 setup_request->value);
805 }
806 if (setup_request->request_type == USB_HUB_REQ_TYPE_SET_PORT_FEATURE) {
807 usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n");
808 return process_port_feature_set_request(instance,
809 setup_request->value,
810 setup_request->index);
811 }
812 usb_log_debug("USB_HUB_REQ_TYPE_INVALID %d\n",
813 setup_request->request_type);
814 return EINVAL;
815 }
816 if (setup_request->request == USB_DEVREQ_SET_ADDRESS) {
817 usb_log_debug("USB_DEVREQ_SET_ADDRESS\n");
818 return process_address_set_request(instance,
819 setup_request->value);
820 }
821 usb_log_debug("USB_DEVREQ_SET_ENOTSUP %d\n",
822 setup_request->request_type);
823
824 return ENOTSUP;
825}
826/*----------------------------------------------------------------------------*/
827
828/**
829 * process hub control request
830 *
831 * If needed, writes answer into the request structure.
832 * Request can be one of
833 * USB_DEVREQ_GET_STATUS,
834 * USB_DEVREQ_GET_DESCRIPTOR,
835 * USB_DEVREQ_GET_CONFIGURATION,
836 * USB_DEVREQ_CLEAR_FEATURE,
837 * USB_DEVREQ_SET_FEATURE,
838 * USB_DEVREQ_SET_ADDRESS,
839 * USB_DEVREQ_SET_DESCRIPTOR or
840 * USB_DEVREQ_SET_CONFIGURATION.
841 *
842 * @param instance root hub instance
843 * @param request structure containing both request and response information
844 * @return error code
845 */
846static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request) {
847 if (!request->setup_buffer) {
848 usb_log_error("root hub received empty transaction?");
849 return EINVAL;
850 }
851 int opResult;
852 if (sizeof (usb_device_request_setup_packet_t) > request->setup_size) {
853 usb_log_error("Setup packet too small\n");
854 return EINVAL;
855 }
856 usb_log_debug("CTRL packet: %s.\n",
857 usb_debug_str_buffer(
858 (const uint8_t *) request->setup_buffer, 8, 8));
859 usb_device_request_setup_packet_t * setup_request =
860 (usb_device_request_setup_packet_t*)
861 request->setup_buffer;
862 switch (setup_request->request) {
863 case USB_DEVREQ_GET_STATUS:
864 case USB_DEVREQ_GET_DESCRIPTOR:
865 case USB_DEVREQ_GET_CONFIGURATION:
866 usb_log_debug2("Processing request with output\n");
867 opResult = process_request_with_output(
868 instance, request);
869 break;
870 case USB_DEVREQ_CLEAR_FEATURE:
871 case USB_DEVREQ_SET_FEATURE:
872 case USB_DEVREQ_SET_ADDRESS:
873 usb_log_debug2("Processing request without "
874 "additional data\n");
875 opResult = process_request_without_data(
876 instance, request);
877 break;
878 case USB_DEVREQ_SET_DESCRIPTOR:
879 case USB_DEVREQ_SET_CONFIGURATION:
880 usb_log_debug2("Processing request with input\n");
881 opResult = process_request_with_input(
882 instance, request);
883
884 break;
885 default:
886 usb_log_warning("Received unsupported request: %d.\n",
887 setup_request->request);
888 opResult = ENOTSUP;
889 }
890 return opResult;
891}
892/*----------------------------------------------------------------------------*/
893
894/**
895 * process hanging interrupt request
896 *
897 * If an interrupt transfer has been received and there was no change,
898 * the driver stores the transfer information and waits for change to occcur.
899 * This routine is called when that happens and it finalizes the interrupt
900 * transfer.
901 *
902 * @param instance hub instance
903 * @param request batch request to be processed
904 *
905 * @return
906 */
907static int process_interrupt_mask_in_instance(rh_t *instance,
908 usb_transfer_batch_t * request) {
909 memcpy(request->data_buffer, instance->interrupt_buffer,
910 instance->interrupt_mask_size);
911 request->transfered_size = instance->interrupt_mask_size;
912 instance->unfinished_interrupt_transfer = NULL;
913 usb_transfer_batch_finish_error(request, EOK);
914
915 return EOK;
916}
917
918/*----------------------------------------------------------------------------*/
919
920/**
921 * return whether the buffer is full of zeros
922 *
923 * Convenience function.
924 * @param buffer
925 * @param size
926 * @return
927 */
928static bool is_zeros(void *buffer, size_t size) {
929 if (!buffer) return true;
930 if (!size) return true;
931 size_t i;
932 for (i = 0; i < size; ++i) {
933 if (((char*) buffer)[i])
934 return false;
935 }
936 return true;
937}
938
939/**
940 * @}
941 */
Note: See TracBrowser for help on using the repository browser.