Changeset e1dbcbc in mainline for uspace/drv/ohci/root_hub.c


Ignore:
Timestamp:
2011-04-29T13:43:01Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
a81a1d09
Parents:
380e0364 (diff), f19f1b7 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge development/ changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/ohci/root_hub.c

    r380e0364 re1dbcbc  
    149149
    150150
    151 static void usb_create_serialized_hub_descriptor(rh_t *instance,
    152         uint8_t ** out_result,
    153         size_t * out_size);
    154 
    155 static void rh_init_descriptors(rh_t *instance);
     151static int create_serialized_hub_descriptor(rh_t *instance);
     152
     153static int rh_init_descriptors(rh_t *instance);
    156154
    157155static int process_get_port_status_request(rh_t *instance, uint16_t port,
     
    164162        usb_transfer_batch_t * request);
    165163
    166 static void create_interrupt_mask(rh_t *instance, void ** buffer,
    167         size_t * buffer_size);
     164static void create_interrupt_mask_in_instance(rh_t *instance);
    168165
    169166static int process_get_descriptor_request(rh_t *instance,
     
    198195static int process_ctrl_request(rh_t *instance, usb_transfer_batch_t *request);
    199196
    200 
     197static int process_interrupt_mask_in_instance(rh_t *instance, usb_transfer_batch_t * request);
     198
     199static bool is_zeros(void * buffer, size_t size);
    201200
    202201
     
    205204 * @return Error code.
    206205 */
    207 int rh_init(rh_t *instance, ddf_dev_t *dev, ohci_regs_t *regs) {
     206int rh_init(rh_t *instance, ohci_regs_t *regs) {
    208207        assert(instance);
    209         //instance->address = -1;
    210208        instance->registers = regs;
    211         instance->device = dev;
    212209        instance->port_count =
    213210            (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;
    214         rh_init_descriptors(instance);
     211        int opResult = rh_init_descriptors(instance);
     212        if(opResult != EOK){
     213                return opResult;
     214        }
    215215        // set port power mode to no-power-switching
    216         instance->registers->rh_desc_a =
    217                 instance->registers->rh_desc_a | (1<<9);
     216        instance->registers->rh_desc_a |= RHDA_NPS_FLAG;
     217        instance->unfinished_interrupt_transfer = NULL;
     218        instance->interrupt_mask_size = (instance->port_count + 8)/8;
     219        instance->interrupt_buffer = malloc(instance->interrupt_mask_size);
     220        if(!instance->interrupt_buffer)
     221                return ENOMEM;
     222       
    218223
    219224        usb_log_info("OHCI root hub with %d ports.\n", instance->port_count);
    220 
    221         //start generic usb hub driver
    222 
    223         /* TODO: implement */
    224225        return EOK;
    225226}
     
    237238        assert(request);
    238239        int opResult;
    239         if (request->transfer_type == USB_TRANSFER_CONTROL) {
     240        if (request->ep->transfer_type == USB_TRANSFER_CONTROL) {
    240241                usb_log_info("Root hub got CONTROL packet\n");
    241242                opResult = process_ctrl_request(instance, request);
    242         } else if (request->transfer_type == USB_TRANSFER_INTERRUPT) {
     243                usb_transfer_batch_finish_error(request, opResult);
     244        } else if (request->ep->transfer_type == USB_TRANSFER_INTERRUPT) {
    243245                usb_log_info("Root hub got INTERRUPT packet\n");
    244                 void * buffer;
    245                 create_interrupt_mask(instance, &buffer,
    246                         &(request->transfered_size));
    247                 memcpy(request->transport_buffer, buffer,
    248                         request->transfered_size);
     246                create_interrupt_mask_in_instance(instance);
     247                if(is_zeros(instance->interrupt_buffer,
     248                    instance->interrupt_mask_size)){
     249                        usb_log_debug("no changes..\n");
     250                        instance->unfinished_interrupt_transfer = request;
     251                        //will be finished later
     252                }else{
     253                        usb_log_debug("processing changes..\n");
     254                        process_interrupt_mask_in_instance(instance, request);
     255                }
    249256                opResult = EOK;
    250257        } else {
    251258                opResult = EINVAL;
    252         }
    253         usb_transfer_batch_finish_error(request, opResult);
    254         return EOK;
    255 }
    256 
    257 /*----------------------------------------------------------------------------*/
    258 
    259 
     259                usb_transfer_batch_finish_error(request, opResult);
     260        }
     261        return EOK;
     262}
     263
     264/*----------------------------------------------------------------------------*/
     265
     266/**
     267 * process interrupt on a hub
     268 *
     269 * If there is no pending interrupt transfer, nothing happens.
     270 * @param instance
     271 */
    260272void rh_interrupt(rh_t *instance) {
    261         usb_log_info("Whoa whoa wait, I`m not supposed to receive any "
    262                 "interrupts, am I?\n");
    263         /* TODO: implement? */
     273        if(!instance->unfinished_interrupt_transfer){
     274                return;
     275        }
     276        usb_log_debug("finalizing interrupt transfer\n");
     277        create_interrupt_mask_in_instance(instance);
     278        process_interrupt_mask_in_instance(instance,
     279            instance->unfinished_interrupt_transfer);
    264280}
    265281/*----------------------------------------------------------------------------*/
     
    272288 *
    273289 * @param instance root hub instance
    274  * @param@out out_result pointer to resultant serialized descriptor
    275  * @param@out out_size size of serialized descriptor
    276  */
    277 static void usb_create_serialized_hub_descriptor(rh_t *instance,
    278         uint8_t ** out_result,
    279         size_t * out_size) {
    280         //base size
    281         size_t size = 7;
    282         //variable size according to port count
    283         size_t var_size = instance->port_count / 8 +
    284                 ((instance->port_count % 8 > 0) ? 1 : 0);
    285         size += 2 * var_size;
     290 * @return error code
     291 */
     292static int create_serialized_hub_descriptor(rh_t *instance) {
     293        size_t size = 7 +
     294            ((instance->port_count +7 )/ 8) * 2;
     295        size_t var_size = (instance->port_count +7 )/ 8;
    286296        uint8_t * result = (uint8_t*) malloc(size);
     297        if(!result) return ENOMEM;
     298
    287299        bzero(result, size);
    288300        //size
     
    313325                result[7 + var_size + i] = 255;
    314326        }
    315         (*out_result) = result;
    316         (*out_size) = size;
     327        instance->hub_descriptor = result;
     328        instance->descriptor_size = size;
     329        return EOK;
    317330}
    318331/*----------------------------------------------------------------------------*/
     
    323336 * be initialized only once per hub.
    324337 * @instance root hub instance
    325  */
    326 static void rh_init_descriptors(rh_t *instance) {
     338 * @return error code
     339 */
     340static int rh_init_descriptors(rh_t *instance) {
    327341        memcpy(&instance->descriptors.device, &ohci_rh_device_descriptor,
    328342                sizeof (ohci_rh_device_descriptor)
     
    331345        memcpy(&descriptor, &ohci_rh_conf_descriptor,
    332346                sizeof (ohci_rh_conf_descriptor));
    333         uint8_t * hub_descriptor;
    334         size_t hub_desc_size;
    335         usb_create_serialized_hub_descriptor(instance, &hub_descriptor,
    336                 &hub_desc_size);
    337 
     347
     348        int opResult = create_serialized_hub_descriptor(instance);
     349        if(opResult != EOK){
     350                return opResult;
     351        }
    338352        descriptor.total_length =
    339353                sizeof (usb_standard_configuration_descriptor_t) +
    340354                sizeof (usb_standard_endpoint_descriptor_t) +
    341355                sizeof (usb_standard_interface_descriptor_t) +
    342                 hub_desc_size;
     356                instance->descriptor_size;
    343357
    344358        uint8_t * full_config_descriptor =
    345359                (uint8_t*) malloc(descriptor.total_length);
     360        if(!full_config_descriptor){
     361                return ENOMEM;
     362        }
    346363        memcpy(full_config_descriptor, &descriptor, sizeof (descriptor));
    347364        memcpy(full_config_descriptor + sizeof (descriptor),
     
    353370                sizeof (ohci_rh_iface_descriptor) +
    354371                sizeof (ohci_rh_ep_descriptor),
    355                 hub_descriptor, hub_desc_size);
    356 
     372                instance->hub_descriptor, instance->descriptor_size);
     373       
    357374        instance->descriptors.configuration = full_config_descriptor;
    358375        instance->descriptors.configuration_size = descriptor.total_length;
     376        return EOK;
    359377}
    360378/*----------------------------------------------------------------------------*/
     
    374392        if (port < 1 || port > instance->port_count)
    375393                return EINVAL;
    376         uint32_t * uint32_buffer = (uint32_t*) request->transport_buffer;
     394        uint32_t * uint32_buffer = (uint32_t*) request->data_buffer;
    377395        request->transfered_size = 4;
    378396        uint32_buffer[0] = instance->registers->rh_port_status[port - 1];
     
    400418static int process_get_hub_status_request(rh_t *instance,
    401419        usb_transfer_batch_t * request) {
    402         uint32_t * uint32_buffer = (uint32_t*) request->transport_buffer;
     420        uint32_t * uint32_buffer = (uint32_t*) request->data_buffer;
    403421        request->transfered_size = 4;
    404422        //bits, 0,1,16,17
     
    447465 * bit i indicates change on i`th port (i>0). For more info see
    448466 * Hub and Port status bitmap specification in USB specification
    449  * (chapter 11.13.4)
    450  * @param instance root hub instance
    451  * @param@out buffer pointer to created interrupt mas
    452  * @param@out buffer_size size of created interrupt mask
    453  */
    454 static void create_interrupt_mask(rh_t *instance, void ** buffer,
    455         size_t * buffer_size) {
    456         int bit_count = instance->port_count + 1;
    457         (*buffer_size) = (bit_count / 8) + ((bit_count % 8 == 0) ? 0 : 1);
    458 
    459         (*buffer) = malloc(*buffer_size);
    460         uint8_t * bitmap = (uint8_t*) (*buffer);
     467 * (chapter 11.13.4).
     468 * Uses instance`s interrupt buffer to store the interrupt information.
     469 * @param instance root hub instance
     470 */
     471static void create_interrupt_mask_in_instance(rh_t * instance) {
     472        uint8_t * bitmap = (uint8_t*) (instance->interrupt_buffer);
    461473        uint32_t mask = (1 << (USB_HUB_FEATURE_C_HUB_LOCAL_POWER + 16))
    462474                | (1 << (USB_HUB_FEATURE_C_HUB_OVER_CURRENT + 16));
    463         bzero(bitmap, (*buffer_size));
     475        bzero(bitmap, instance->interrupt_mask_size);
    464476        if (instance->registers->rh_status & mask) {
    465477                bitmap[0] = 1;
     
    492504        const uint16_t setup_request_value = setup_request->value_high;
    493505        //(setup_request->value_low << 8);
    494         bool del = false;
    495506        switch (setup_request_value) {
    496507                case USB_DESCTYPE_HUB:
    497508                {
    498                         uint8_t * descriptor;
    499                         usb_create_serialized_hub_descriptor(
    500                                 instance, &descriptor, &size);
    501                         result_descriptor = descriptor;
    502                         if (result_descriptor) del = true;
     509                        usb_log_debug("USB_DESCTYPE_HUB\n");
     510                        result_descriptor = instance->hub_descriptor;
     511                        size = instance->descriptor_size;
    503512                        break;
    504513                }
     
    550559        }
    551560        request->transfered_size = size;
    552         memcpy(request->transport_buffer, result_descriptor, size);
    553         if (del)
    554                 free(result_descriptor);
     561        memcpy(request->data_buffer, result_descriptor, size);
    555562        return EOK;
    556563}
     
    571578        if (request->buffer_size != 1)
    572579                return EINVAL;
    573         request->transport_buffer[0] = 1;
     580        request->data_buffer[0] = 1;
    574581        request->transfered_size = 1;
    575582        return EOK;
     
    866873        return opResult;
    867874}
     875/*----------------------------------------------------------------------------*/
     876
     877/**
     878 * process hanging interrupt request
     879 *
     880 * If an interrupt transfer has been received and there was no change,
     881 * the driver stores the transfer information and waits for change to occcur.
     882 * This routine is called when that happens and it finalizes the interrupt
     883 * transfer.
     884 *
     885 * @param instance hub instance
     886 * @param request batch request to be processed
     887 *
     888 * @return
     889 */
     890static int process_interrupt_mask_in_instance(rh_t *instance, usb_transfer_batch_t * request){
     891        memcpy(request->data_buffer, instance->interrupt_buffer,
     892            instance->interrupt_mask_size);
     893        request->transfered_size = instance->interrupt_mask_size;
     894        instance->unfinished_interrupt_transfer = NULL;
     895        usb_transfer_batch_finish_error(request, EOK);
     896        return EOK;
     897}
     898
     899/*----------------------------------------------------------------------------*/
     900
     901/**
     902 * return whether the buffer is full of zeros
     903 *
     904 * Convenience function.
     905 * @param buffer
     906 * @param size
     907 * @return
     908 */
     909static bool is_zeros(void * buffer, size_t size){
     910        if(!buffer) return true;
     911        if(!size) return true;
     912        size_t i;
     913        for(i=0;i<size;++i){
     914                if(((char*)buffer)[i])
     915                        return false;
     916        }
     917        return true;
     918}
    868919
    869920/**
Note: See TracChangeset for help on using the changeset viewer.