Changeset fa8f1f7 in mainline


Ignore:
Timestamp:
2011-03-20T23:00:30Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
2c1f24c
Parents:
8373f53 (diff), 33577f81 (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

Files:
14 added
15 edited

Legend:

Unmodified
Added
Removed
  • .bzrignore

    r8373f53 rfa8f1f7  
    8484./uspace/drv/test1/test1
    8585./uspace/drv/test2/test2
     86./uspace/drv/ohci/ohci
    8687./uspace/drv/ehci-hcd/ehci-hcd
    8788./uspace/drv/uhci-hcd/uhci-hcd
  • boot/arch/amd64/Makefile.inc

    r8373f53 rfa8f1f7  
    4444        ns8250 \
    4545        ehci-hcd \
     46        ohci \
    4647        uhci-hcd \
    4748        uhci-rhd \
  • uspace/Makefile

    r8373f53 rfa8f1f7  
    118118                srv/hw/irc/i8259 \
    119119                drv/ehci-hcd \
     120                drv/ohci \
    120121                drv/uhci-hcd \
    121122                drv/uhci-rhd \
     
    137138                srv/hw/irc/i8259 \
    138139                drv/ehci-hcd \
     140                drv/ohci \
    139141                drv/uhci-hcd \
    140142                drv/uhci-rhd \
  • uspace/drv/usbhid/hiddev.c

    r8373f53 rfa8f1f7  
    440440        if (rc != EOK) {
    441441                /* TODO: end session?? */
     442                usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
    442443                usb_log_error("Failed to process descriptors: %s.\n",
    443444                    str_error(rc));
  • uspace/drv/usbhid/hiddev.h

    r8373f53 rfa8f1f7  
    3232/** @file
    3333 * Generic USB HID device structure and API.
     34 *
     35 * @todo Add function for parsing report - this is generic HID function, not
     36 *       keyboard-specific, as the report parser is also generic.
     37 * @todo Add function for polling as that is also a generic HID process.
     38 * @todo Add interrupt in pipe to the structure.
    3439 */
    3540
  • uspace/drv/usbhid/kbddev.c

    r8373f53 rfa8f1f7  
    9494        .flags = 0
    9595};
     96
     97typedef enum usbhid_kbd_flags {
     98        USBHID_KBD_STATUS_UNINITIALIZED = 0,
     99        USBHID_KBD_STATUS_INITIALIZED = 1,
     100        USBHID_KBD_STATUS_TO_DESTROY = -1
     101} usbhid_kbd_flags;
    96102
    97103/*----------------------------------------------------------------------------*/
     
    232238       
    233239        assert(kbd_dev->hid_dev != NULL);
    234         assert(kbd_dev->hid_dev->initialized);
     240        assert(kbd_dev->hid_dev->initialized == USBHID_KBD_STATUS_INITIALIZED);
    235241        usbhid_req_set_report(kbd_dev->hid_dev, USB_HID_REPORT_TYPE_OUTPUT,
    236242            buffer, BOOTP_BUFFER_OUT_SIZE);
     
    565571                                    uint8_t *buffer, size_t actual_size)
    566572{
    567         assert(kbd_dev->initialized);
     573        assert(kbd_dev->initialized == USBHID_KBD_STATUS_INITIALIZED);
    568574        assert(kbd_dev->hid_dev->parser != NULL);
    569575       
     
    619625       
    620626        kbd_dev->console_phone = -1;
    621         kbd_dev->initialized = 0;
     627        kbd_dev->initialized = USBHID_KBD_STATUS_UNINITIALIZED;
    622628       
    623629        return kbd_dev;
     
    625631
    626632/*----------------------------------------------------------------------------*/
    627 /**
    628  * Properly destroys the USB/HID keyboard structure.
    629  *
    630  * @param kbd_dev Pointer to the structure to be destroyed.
    631  */
    632 static void usbhid_kbd_free(usbhid_kbd_t **kbd_dev)
    633 {
    634         if (kbd_dev == NULL || *kbd_dev == NULL) {
    635                 return;
    636         }
    637        
    638         // hangup phone to the console
    639         async_hangup((*kbd_dev)->console_phone);
    640        
    641         if ((*kbd_dev)->hid_dev != NULL) {
    642                 usbhid_dev_free(&(*kbd_dev)->hid_dev);
    643                 assert((*kbd_dev)->hid_dev == NULL);
    644         }
    645        
    646         if ((*kbd_dev)->repeat_mtx != NULL) {
    647                 /* TODO: replace by some check and wait */
    648                 assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
    649                 free((*kbd_dev)->repeat_mtx);
    650         }
    651 
    652         free(*kbd_dev);
    653         *kbd_dev = NULL;
     633
     634static void usbhid_kbd_mark_unusable(usbhid_kbd_t *kbd_dev)
     635{
     636        kbd_dev->initialized = USBHID_KBD_STATUS_TO_DESTROY;
    654637}
    655638
     
    693676        }
    694677       
    695         if (kbd_dev->initialized) {
     678        if (kbd_dev->initialized == USBHID_KBD_STATUS_INITIALIZED) {
    696679                usb_log_warning("Keyboard structure already initialized.\n");
    697680                return EINVAL;
     
    706689        }
    707690       
    708         assert(kbd_dev->hid_dev->initialized);
     691        assert(kbd_dev->hid_dev->initialized == USBHID_KBD_STATUS_INITIALIZED);
    709692       
    710693        // save the size of the report (boot protocol report by default)
     
    758741        usbhid_req_set_idle(kbd_dev->hid_dev, IDLE_RATE);
    759742       
    760         kbd_dev->initialized = 1;
     743        kbd_dev->initialized = USBHID_KBD_STATUS_INITIALIZED;
    761744        usb_log_info("HID/KBD device structure initialized.\n");
    762745       
     
    872855        usbhid_kbd_poll(kbd_dev);
    873856       
     857        // as there is another fibril using this device, so we must leave the
     858        // structure to it, but mark it for destroying.
     859        usbhid_kbd_mark_unusable(kbd_dev);
    874860        // at the end, properly destroy the KBD structure
    875         usbhid_kbd_free(&kbd_dev);
    876         assert(kbd_dev == NULL);
     861//      usbhid_kbd_free(&kbd_dev);
     862//      assert(kbd_dev == NULL);
    877863
    878864        return EOK;
     
    996982}
    997983
     984/*----------------------------------------------------------------------------*/
     985
     986int usbhid_kbd_is_usable(const usbhid_kbd_t *kbd_dev)
     987{
     988        return (kbd_dev->initialized == USBHID_KBD_STATUS_INITIALIZED);
     989}
     990
     991/*----------------------------------------------------------------------------*/
     992/**
     993 * Properly destroys the USB/HID keyboard structure.
     994 *
     995 * @param kbd_dev Pointer to the structure to be destroyed.
     996 */
     997void usbhid_kbd_free(usbhid_kbd_t **kbd_dev)
     998{
     999        if (kbd_dev == NULL || *kbd_dev == NULL) {
     1000                return;
     1001        }
     1002       
     1003        // hangup phone to the console
     1004        async_hangup((*kbd_dev)->console_phone);
     1005       
     1006        if ((*kbd_dev)->hid_dev != NULL) {
     1007                usbhid_dev_free(&(*kbd_dev)->hid_dev);
     1008                assert((*kbd_dev)->hid_dev == NULL);
     1009        }
     1010       
     1011        if ((*kbd_dev)->repeat_mtx != NULL) {
     1012                /* TODO: replace by some check and wait */
     1013                assert(!fibril_mutex_is_locked((*kbd_dev)->repeat_mtx));
     1014                free((*kbd_dev)->repeat_mtx);
     1015        }
     1016
     1017        free(*kbd_dev);
     1018        *kbd_dev = NULL;
     1019}
     1020
    9981021/**
    9991022 * @}
  • uspace/drv/usbhid/kbddev.h

    r8373f53 rfa8f1f7  
    101101        fibril_mutex_t *repeat_mtx;
    102102       
    103         /** State of the structure (for checking before use). */
     103        /** State of the structure (for checking before use).
     104         *
     105         * 0 - not initialized
     106         * 1 - initialized
     107         * -1 - ready for destroying
     108         */
    104109        int initialized;
    105110} usbhid_kbd_t;
     
    108113
    109114int usbhid_kbd_try_add_device(ddf_dev_t *dev);
     115
     116int usbhid_kbd_is_usable(const usbhid_kbd_t *kbd_dev);
     117
     118void usbhid_kbd_free(usbhid_kbd_t **kbd_dev);
    110119
    111120void usbhid_kbd_push_ev(usbhid_kbd_t *kbd_dev, int type, unsigned int key);
  • uspace/drv/usbhid/kbdrepeat.c

    r8373f53 rfa8f1f7  
    7777
    7878        while (true) {
     79                // check if the kbd structure is usable
     80                if (!usbhid_kbd_is_usable(kbd)) {
     81                        usbhid_kbd_free(&kbd);
     82                        assert(kbd == NULL);
     83                        return;
     84                }
     85               
    7986                fibril_mutex_lock(kbd->repeat_mtx);
    8087
  • uspace/drv/usbhub/main.c

    r8373f53 rfa8f1f7  
    3636#include <stdio.h>
    3737
     38#include <usb/devdrv.h>
     39#include <usb/classes/classes.h>
     40
    3841#include "usbhub.h"
    3942#include "usbhub_private.h"
    4043
    4144
    42 usb_general_list_t usb_hub_list;
    43 fibril_mutex_t usb_hub_list_lock;
    44 
    45 static driver_ops_t hub_driver_ops = {
    46         .add_device = usb_add_hub_device,
     45usb_endpoint_description_t hub_status_change_endpoint_description = {
     46        .transfer_type = USB_TRANSFER_INTERRUPT,
     47        .direction = USB_DIRECTION_IN,
     48        .interface_class = USB_CLASS_HUB,
     49        .interface_subclass = 0,
     50        .interface_protocol = 0,
     51        .flags = 0
    4752};
    4853
    49 static driver_t hub_driver = {
     54
     55static usb_driver_ops_t usb_hub_driver_ops = {
     56        .add_device = usb_hub_add_device
     57};
     58
     59static usb_driver_t usb_hub_driver = {
    5060        .name = "usbhub",
    51         .driver_ops = &hub_driver_ops
     61        .ops = &usb_hub_driver_ops
    5262};
     63
    5364
    5465int main(int argc, char *argv[])
    5566{
    5667        usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
    57         dprintf(USB_LOG_LEVEL_INFO, "starting hub driver");
     68        usb_log_info("starting hub driver\n");
    5869
    59         //this is probably not needed anymore
    60         fibril_mutex_initialize(&usb_hub_list_lock);
    61         fibril_mutex_lock(&usb_hub_list_lock);
    62         usb_lst_init(&usb_hub_list);
    63         fibril_mutex_unlock(&usb_hub_list_lock);
    6470       
    65         return ddf_driver_main(&hub_driver);
     71        usb_hub_driver.endpoints = (usb_endpoint_description_t**)
     72                        malloc(2 * sizeof(usb_endpoint_description_t*));
     73        usb_hub_driver.endpoints[0] = &hub_status_change_endpoint_description;
     74        usb_hub_driver.endpoints[1] = NULL;
     75
     76        return usb_driver_main(&usb_hub_driver);
    6677}
    6778
  • uspace/drv/usbhub/usbhub.c

    r8373f53 rfa8f1f7  
    5353#include "usb/classes/classes.h"
    5454
    55 static ddf_dev_ops_t hub_device_ops = {
    56         .interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
    57 };
    58 
    59 /** Hub status-change endpoint description
    60  *
    61  * For more see usb hub specification in 11.15.1 of
    62  */
    63 static usb_endpoint_description_t status_change_endpoint_description = {
    64         .transfer_type = USB_TRANSFER_INTERRUPT,
    65         .direction = USB_DIRECTION_IN,
    66         .interface_class = USB_CLASS_HUB,
    67         .interface_subclass = 0,
    68         .interface_protocol = 0,
    69         .flags = 0
    70 };
    71 
    7255int usb_hub_control_loop(void * hub_info_param){
    7356        usb_hub_info_t * hub_info = (usb_hub_info_t*)hub_info_param;
     
    7861                async_usleep(1000 * 1000 );/// \TODO proper number once
    7962        }
    80         usb_log_error("something in ctrl loop went wrong, errno %d",errorCode);
     63        usb_log_error("something in ctrl loop went wrong, errno %d\n",errorCode);
    8164
    8265        return 0;
     
    9174
    9275/**
    93  * Initialize connnections to host controller, device, and device
    94  * control endpoint
    95  * @param hub
    96  * @param device
     76 * create usb_hub_info_t structure
     77 *
     78 * Does only basic copying of known information into new structure.
     79 * @param usb_dev usb device structure
     80 * @return basic usb_hub_info_t structure
     81 */
     82static usb_hub_info_t * usb_hub_info_create(usb_device_t * usb_dev) {
     83        usb_hub_info_t * result = usb_new(usb_hub_info_t);
     84        if(!result) return NULL;
     85        result->usb_device = usb_dev;
     86        result->status_change_pipe = usb_dev->pipes[0].pipe;
     87        result->control_pipe = &usb_dev->ctrl_pipe;
     88        result->is_default_address_used = false;
     89        return result;
     90}
     91
     92/**
     93 * Load hub-specific information into hub_info structure.
     94 *
     95 * Particularly read port count and initialize structure holding port
     96 * information.
     97 * This function is hub-specific and should be run only after the hub is
     98 * configured using usb_hub_set_configuration function.
     99 * @param hub_info pointer to structure with usb hub data
     100 * @return error code
     101 */
     102static int usb_hub_get_hub_specific_info(usb_hub_info_t * hub_info){
     103        // get hub descriptor
     104        usb_log_debug("creating serialized descriptor\n");
     105        void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
     106        usb_hub_descriptor_t * descriptor;
     107
     108        /* this was one fix of some bug, should not be needed anymore
     109        int opResult = usb_request_set_configuration(&result->endpoints.control, 1);
     110        if(opResult!=EOK){
     111                usb_log_error("could not set default configuration, errno %d",opResult);
     112                return opResult;
     113        }
     114         */
     115        size_t received_size;
     116        int opResult = usb_request_get_descriptor(&hub_info->usb_device->ctrl_pipe,
     117                        USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
     118                        USB_DESCTYPE_HUB,
     119                        0, 0, serialized_descriptor,
     120                        USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
     121
     122        if (opResult != EOK) {
     123                usb_log_error("failed when receiving hub descriptor, badcode = %d\n",
     124                                opResult);
     125                free(serialized_descriptor);
     126                return opResult;
     127        }
     128        usb_log_debug2("deserializing descriptor\n");
     129        descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
     130        if(descriptor==NULL){
     131                usb_log_warning("could not deserialize descriptor \n");
     132                return opResult;
     133        }
     134        usb_log_info("setting port count to %d\n",descriptor->ports_count);
     135        hub_info->port_count = descriptor->ports_count;
     136        hub_info->attached_devs = (usb_hc_attached_device_t*)
     137            malloc((hub_info->port_count+1) * sizeof(usb_hc_attached_device_t));
     138        int i;
     139        for(i=0;i<hub_info->port_count+1;++i){
     140                hub_info->attached_devs[i].handle=0;
     141                hub_info->attached_devs[i].address=0;
     142        }
     143        usb_log_debug2("freeing data\n");
     144        free(serialized_descriptor);
     145        free(descriptor->devices_removable);
     146        free(descriptor);
     147        return EOK;
     148}
     149/**
     150 * Set configuration of hub
     151 *
     152 * Check whether there is at least one configuration and sets the first one.
     153 * This function should be run prior to running any hub-specific action.
     154 * @param hub_info
    97155 * @return
    98156 */
    99 static int usb_hub_init_communication(usb_hub_info_t * hub){
    100         usb_log_debug("Initializing hub USB communication (hub->device->handle=%zu).\n", hub->device->handle);
    101         int opResult;
    102         opResult = usb_device_connection_initialize_from_device(
    103                         &hub->device_connection,
    104                         hub->device);
    105         if(opResult != EOK){
    106                 usb_log_error("could not initialize connection to hc, errno %d",opResult);
    107                 return opResult;
    108         }
    109         usb_log_debug("Initializing USB wire abstraction.\n");
    110         opResult = usb_hc_connection_initialize_from_device(&hub->connection,
    111                         hub->device);
    112         if(opResult != EOK){
    113                 usb_log_error("could not initialize connection to device, errno %d",
    114                                 opResult);
    115                 return opResult;
    116         }
    117         usb_log_debug("Initializing default control pipe.\n");
    118         opResult = usb_endpoint_pipe_initialize_default_control(&hub->endpoints.control,
    119             &hub->device_connection);
    120         if(opResult != EOK){
    121                 usb_log_error("could not initialize connection to device endpoint, errno %d",
    122                                 opResult);
    123                 return opResult;
    124         }
    125 
    126         opResult = usb_endpoint_pipe_probe_default_control(&hub->endpoints.control);
    127         if (opResult != EOK) {
    128                 usb_log_error("failed probing endpoint 0, %d", opResult);
    129                 return opResult;
    130         }
    131 
    132         return EOK;
    133 }
    134 
    135 /**
    136  * When entering this function, hub->endpoints.control should be active.
    137  * @param hub
    138  * @return
    139  */
    140 static int usb_hub_process_configuration_descriptors(
    141         usb_hub_info_t * hub){
    142         if(hub==NULL) {
    143                 return EINVAL;
    144         }
    145         int opResult;
    146        
     157static int usb_hub_set_configuration(usb_hub_info_t * hub_info){
    147158        //device descriptor
    148159        usb_standard_device_descriptor_t std_descriptor;
    149         opResult = usb_request_get_device_descriptor(&hub->endpoints.control,
     160        int opResult = usb_request_get_device_descriptor(
     161                &hub_info->usb_device->ctrl_pipe,
    150162            &std_descriptor);
    151163        if(opResult!=EOK){
    152                 usb_log_error("could not get device descriptor, %d",opResult);
    153                 return opResult;
    154         }
    155         usb_log_info("hub has %d configurations",
     164                usb_log_error("could not get device descriptor, %d\n",opResult);
     165                return opResult;
     166        }
     167        usb_log_info("hub has %d configurations\n",
    156168                        std_descriptor.configuration_count);
    157169        if(std_descriptor.configuration_count<1){
    158                 usb_log_error("THERE ARE NO CONFIGURATIONS AVAILABLE");
     170                usb_log_error("THERE ARE NO CONFIGURATIONS AVAILABLE\n");
    159171                //shouldn`t I return?
    160172        }
     
    164176        size_t descriptors_size = 0;
    165177        opResult = usb_request_get_full_configuration_descriptor_alloc(
    166             &hub->endpoints.control, 0,
     178            &hub_info->usb_device->ctrl_pipe, 0,
    167179            (void **) &descriptors, &descriptors_size);
    168180        if (opResult != EOK) {
     
    175187
    176188        /* Set configuration. */
    177         opResult = usb_request_set_configuration(&hub->endpoints.control,
     189        opResult = usb_request_set_configuration(&hub_info->usb_device->ctrl_pipe,
    178190            config_descriptor->configuration_number);
    179191
     
    183195                return opResult;
    184196        }
    185         usb_log_debug("\tused configuration %d",
     197        usb_log_debug("\tused configuration %d\n",
    186198                        config_descriptor->configuration_number);
    187 
    188         usb_endpoint_mapping_t endpoint_mapping[1] = {
    189                 {
    190                         .pipe = &hub->endpoints.status_change,
    191                         .description = &status_change_endpoint_description,
    192                         .interface_no =
    193                             usb_device_get_assigned_interface(hub->device)
    194                 }
    195         };
    196         opResult = usb_endpoint_pipe_initialize_from_configuration(
    197             endpoint_mapping, 1,
    198             descriptors, descriptors_size,
    199             &hub->device_connection);
    200         if (opResult != EOK) {
    201                 usb_log_error("Failed to initialize status change pipe: %s",
    202                     str_error(opResult));
    203                 return opResult;
    204         }
    205         if (!endpoint_mapping[0].present) {
    206                 usb_log_error("Not accepting device, " \
    207                     "cannot understand what is happenning");
    208                 return EREFUSED;
    209         }
    210 
    211199        free(descriptors);
    212200        return EOK;
     201}
     202
     203/**
     204 * Initialize hub device driver fibril
     205 *
     206 * Creates hub representation and fibril that periodically checks hub`s status.
     207 * Hub representation is passed to the fibril.
     208 * @param usb_dev generic usb device information
     209 * @return error code
     210 */
     211int usb_hub_add_device(usb_device_t * usb_dev){
     212        if(!usb_dev) return EINVAL;
     213        usb_hub_info_t * hub_info = usb_hub_info_create(usb_dev);
     214        //create hc connection
     215        usb_log_debug("Initializing USB wire abstraction.\n");
     216        int opResult = usb_hc_connection_initialize_from_device(
     217                        &hub_info->connection,
     218                        hub_info->usb_device->ddf_dev);
     219        if(opResult != EOK){
     220                usb_log_error("could not initialize connection to device, errno %d\n",
     221                                opResult);
     222                free(hub_info);
     223                return opResult;
     224        }
    213225       
    214 }
    215 
    216 
    217 /**
    218  * Create hub representation from device information.
    219  * @param device
    220  * @return pointer to created structure or NULL in case of error
    221  */
    222 usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device) {
    223         usb_hub_info_t* result = usb_new(usb_hub_info_t);
    224         result->device = device;
    225         int opResult;
    226         opResult = usb_hub_init_communication(result);
    227         if(opResult != EOK){
    228                 free(result);
    229                 return NULL;
    230         }
    231 
    232         //result->device = device;
    233         result->port_count = -1;
    234         result->device = device;
    235         result->is_default_address_used = false;
    236 
    237         //result->usb_device = usb_new(usb_hcd_attached_device_info_t);
    238         size_t received_size;
    239 
    240         // get hub descriptor
    241         usb_log_debug("creating serialized descripton");
    242         void * serialized_descriptor = malloc(USB_HUB_MAX_DESCRIPTOR_SIZE);
    243         usb_hub_descriptor_t * descriptor;
    244         usb_log_debug("starting control transaction");
    245         usb_endpoint_pipe_start_session(&result->endpoints.control);
    246         opResult = usb_request_set_configuration(&result->endpoints.control, 1);
    247         assert(opResult == EOK);
    248 
    249         opResult = usb_request_get_descriptor(&result->endpoints.control,
    250                         USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_DEVICE,
    251                         USB_DESCTYPE_HUB,
    252                         0, 0, serialized_descriptor,
    253                         USB_HUB_MAX_DESCRIPTOR_SIZE, &received_size);
    254         usb_endpoint_pipe_end_session(&result->endpoints.control);
    255 
    256         if (opResult != EOK) {
    257                 usb_log_error("failed when receiving hub descriptor, badcode = %d",
    258                                 opResult);
    259                 free(serialized_descriptor);
    260                 free(result);
    261                 return NULL;
    262         }
    263         usb_log_debug2("deserializing descriptor");
    264         descriptor = usb_deserialize_hub_desriptor(serialized_descriptor);
    265         if(descriptor==NULL){
    266                 usb_log_warning("could not deserialize descriptor ");
    267                 free(result);
    268                 return NULL;
    269         }
    270 
    271         usb_log_info("setting port count to %d",descriptor->ports_count);
    272         result->port_count = descriptor->ports_count;
    273         result->attached_devs = (usb_hc_attached_device_t*)
    274             malloc((result->port_count+1) * sizeof(usb_hc_attached_device_t));
    275         int i;
    276         for(i=0;i<result->port_count+1;++i){
    277                 result->attached_devs[i].handle=0;
    278                 result->attached_devs[i].address=0;
    279         }
    280         usb_log_debug2("freeing data");
    281         free(serialized_descriptor);
    282         free(descriptor->devices_removable);
    283         free(descriptor);
    284 
    285         //finish
    286 
    287         usb_log_info("hub info created");
    288 
    289         return result;
    290 }
    291 
    292 /**
    293  * Create hub representation and add it into hub list
    294  * @param dev
    295  * @return
    296  */
    297 int usb_add_hub_device(ddf_dev_t *dev) {
    298         usb_log_info("add_hub_device(handle=%d)", (int) dev->handle);
    299 
    300         //dev->ops = &hub_device_ops;
    301         (void) hub_device_ops;
    302 
    303         usb_hub_info_t * hub_info = usb_create_hub_info(dev);
    304         if(!hub_info){
    305                 return EINTR;
    306         }
    307 
    308         int opResult;
    309 
    310         //perform final configurations
    311         usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
    312         // process descriptors
    313         opResult = usb_hub_process_configuration_descriptors(hub_info);
    314         if(opResult != EOK){
    315                 usb_log_error("could not get configuration descriptors, %d",
    316                                 opResult);
    317                 return opResult;
    318         }
    319         //power ports
    320         usb_device_request_setup_packet_t request;
    321         int port;
    322         for (port = 1; port < hub_info->port_count+1; ++port) {
    323                 usb_hub_set_power_port_request(&request, port);
    324                 opResult = usb_endpoint_pipe_control_write(&hub_info->endpoints.control,
    325                                 &request,sizeof(usb_device_request_setup_packet_t), NULL, 0);
    326                 usb_log_info("powering port %d",port);
    327                 if (opResult != EOK) {
    328                         usb_log_warning("something went wrong when setting hub`s %dth port", port);
    329                 }
    330         }
    331         //ports powered, hub seems to be enabled
    332         usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
    333 
    334         //add the hub to list
    335         //is this needed now?
    336         fibril_mutex_lock(&usb_hub_list_lock);
    337         usb_lst_append(&usb_hub_list, hub_info);
    338         fibril_mutex_unlock(&usb_hub_list_lock);
    339         usb_log_debug("hub info added to list");
    340 
     226        usb_endpoint_pipe_start_session(hub_info->control_pipe);
     227        //set hub configuration
     228        opResult = usb_hub_set_configuration(hub_info);
     229        if(opResult!=EOK){
     230                usb_log_error("could not set hub configuration, errno %d\n",opResult);
     231                free(hub_info);
     232                return opResult;
     233        }
     234        //get port count and create attached_devs
     235        opResult = usb_hub_get_hub_specific_info(hub_info);
     236        if(opResult!=EOK){
     237                usb_log_error("could not set hub configuration, errno %d\n",opResult);
     238                free(hub_info);
     239                return opResult;
     240        }
     241        usb_endpoint_pipe_end_session(hub_info->control_pipe);
     242
     243
     244        /// \TODO what is this?
    341245        usb_log_debug("adding to ddf");
    342         ddf_fun_t *hub_fun = ddf_fun_create(dev, fun_exposed, "hub");
     246        ddf_fun_t *hub_fun = ddf_fun_create(hub_info->usb_device->ddf_dev,
     247                        fun_exposed, "hub");
    343248        assert(hub_fun != NULL);
    344249        hub_fun->ops = NULL;
     
    349254        assert(rc == EOK);
    350255
     256        //create fibril for the hub control loop
    351257        fid_t fid = fibril_create(usb_hub_control_loop, hub_info);
    352258        if (fid == 0) {
     
    355261        }
    356262        fibril_add_ready(fid);
    357 
    358263        usb_log_debug("hub fibril created");
    359         //(void)hub_info;
    360         //usb_hub_check_hub_changes();
    361        
    362         usb_log_info("hub dev added");
    363         //address is lost...
    364         usb_log_debug("\taddress %d, has %d ports ",
    365                         //hub_info->endpoints.control.,
    366                         hub_info->port_count);
    367 
     264        usb_log_debug("has %d ports ",hub_info->port_count);
    368265        return EOK;
    369         //return ENOTSUP;
    370266}
    371267
     
    388284        int opResult = usb_hc_release_default_address(&hub->connection);
    389285        if(opResult!=EOK){
    390                 usb_log_error("could not release default address, errno %d",opResult);
     286                usb_log_error("could not release default address, errno %d\n",opResult);
    391287                return opResult;
    392288        }
     
    405301        //if this hub already uses default address, it cannot request it once more
    406302        if(hub->is_default_address_used) return;
    407         int opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
     303        usb_log_info("some connection changed\n");
     304        assert(hub->control_pipe->hc_phone);
     305        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
    408306                                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
    409307        if(opResult != EOK){
    410                 usb_log_warning("could not clear port-change-connection flag");
    411         }
    412 
     308                usb_log_warning("could not clear port-change-connection flag\n");
     309        }
    413310        usb_device_request_setup_packet_t request;
    414         usb_log_info("some connection changed");
    415         assert(hub->endpoints.control.hc_phone);
     311       
    416312        //get default address
    417313        opResult = usb_hc_reserve_default_address(&hub->connection, speed);
    418314       
    419315        if (opResult != EOK) {
    420                 usb_log_warning("cannot assign default address, it is probably used %d",
     316                usb_log_warning("cannot assign default address, it is probably used %d\n",
    421317                                opResult);
    422318                return;
     
    426322        usb_hub_set_reset_port_request(&request, port);
    427323        opResult = usb_endpoint_pipe_control_write(
    428                         &hub->endpoints.control,
     324                        hub->control_pipe,
    429325                        &request,sizeof(usb_device_request_setup_packet_t),
    430326                        NULL, 0
    431327                        );
    432328        if (opResult != EOK) {
    433                 usb_log_error("something went wrong when reseting a port %d",opResult);
     329                usb_log_error("something went wrong when reseting a port %d\n",opResult);
    434330                //usb_hub_release_default_address(hc);
    435331                usb_hub_release_default_address(hub);
     
    445341 */
    446342static void usb_hub_finalize_add_device( usb_hub_info_t * hub,
    447                 uint16_t port, bool isLowSpeed) {
     343                uint16_t port, usb_speed_t speed) {
    448344
    449345        int opResult;
    450         usb_log_info("finalizing add device");
    451         opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
     346        usb_log_info("finalizing add device\n");
     347        opResult = usb_hub_clear_port_feature(hub->control_pipe,
    452348            port, USB_HUB_FEATURE_C_PORT_RESET);
    453349
    454350        if (opResult != EOK) {
    455                 usb_log_error("failed to clear port reset feature");
     351                usb_log_error("failed to clear port reset feature\n");
    456352                usb_hub_release_default_address(hub);
    457353                return;
     
    468364                        &new_device_connection);
    469365        usb_endpoint_pipe_probe_default_control(&new_device_pipe);
    470         /// \TODO get highspeed info
    471         usb_speed_t speed = isLowSpeed?USB_SPEED_LOW:USB_SPEED_FULL;
    472 
    473366
    474367        /* Request address from host controller. */
     
    478371                        );
    479372        if (new_device_address < 0) {
    480                 usb_log_error("failed to get free USB address");
     373                usb_log_error("failed to get free USB address\n");
    481374                opResult = new_device_address;
    482375                usb_hub_release_default_address(hub);
    483376                return;
    484377        }
    485         usb_log_info("setting new address %d",new_device_address);
     378        usb_log_info("setting new address %d\n",new_device_address);
    486379        //opResult = usb_drv_req_set_address(hc, USB_ADDRESS_DEFAULT,
    487380        //    new_device_address);
     
    490383        usb_endpoint_pipe_end_session(&new_device_pipe);
    491384        if (opResult != EOK) {
    492                 usb_log_error("could not set address for new device %d",opResult);
     385                usb_log_error("could not set address for new device %d\n",opResult);
    493386                usb_hub_release_default_address(hub);
    494387                return;
     
    505398        //??
    506399    opResult = usb_device_register_child_in_devman(new_device_address,
    507             hub->connection.hc_handle, hub->device, &child_handle,
     400            hub->connection.hc_handle, hub->usb_device->ddf_dev, &child_handle,
    508401            NULL, NULL, NULL);
    509402
    510403        if (opResult != EOK) {
    511                 usb_log_error("could not start driver for new device %d",opResult);
     404                usb_log_error("could not start driver for new device %d\n",opResult);
    512405                return;
    513406        }
     
    520413                        &hub->attached_devs[port]);
    521414        if (opResult != EOK) {
    522                 usb_log_error("could not assign address of device in hcd %d",opResult);
    523                 return;
    524         }
    525         usb_log_info("new device address %d, handle %zu",
     415                usb_log_error("could not assign address of device in hcd %d\n",opResult);
     416                return;
     417        }
     418        usb_log_info("new device address %d, handle %zu\n",
    526419            new_device_address, child_handle);
    527420
     
    537430    usb_hub_info_t * hub,uint16_t port) {
    538431
    539         int opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
     432        int opResult = usb_hub_clear_port_feature(hub->control_pipe,
    540433                                port, USB_HUB_FEATURE_C_PORT_CONNECTION);
    541434        if(opResult != EOK){
    542                 usb_log_warning("could not clear port-change-connection flag");
     435                usb_log_warning("could not clear port-change-connection flag\n");
    543436        }
    544437        /** \TODO remove device from device manager - not yet implemented in
     
    559452                 */
    560453        }else{
    561                 usb_log_warning("this is strange, disconnected device had no address");
     454                usb_log_warning("this is strange, disconnected device had no address\n");
    562455                //device was disconnected before it`s port was reset - return default address
    563456                usb_hub_release_default_address(hub);
     
    577470                uint16_t port){
    578471        int opResult;
    579         opResult = usb_hub_clear_port_feature(&hub->endpoints.control,
     472        opResult = usb_hub_clear_port_feature(hub->control_pipe,
    580473            port, USB_HUB_FEATURE_PORT_POWER);
    581474        if(opResult!=EOK){
    582                 usb_log_error("cannot power off port %d;  %d",
     475                usb_log_error("cannot power off port %d;  %d\n",
    583476                                port, opResult);
    584477        }
     
    593486static void usb_hub_process_interrupt(usb_hub_info_t * hub,
    594487        uint16_t port) {
    595         usb_log_debug("interrupt at port %d", port);
     488        usb_log_debug("interrupt at port %d\n", port);
    596489        //determine type of change
    597         usb_endpoint_pipe_t *pipe = &hub->endpoints.control;
     490        usb_endpoint_pipe_t *pipe = hub->control_pipe;
    598491       
    599492        int opResult;
     
    612505                        );
    613506        if (opResult != EOK) {
    614                 usb_log_error("could not get port status");
     507                usb_log_error("could not get port status\n");
    615508                return;
    616509        }
    617510        if (rcvd_size != sizeof (usb_port_status_t)) {
    618                 usb_log_error("received status has incorrect size");
     511                usb_log_error("received status has incorrect size\n");
    619512                return;
    620513        }
     
    622515        if (usb_port_connect_change(&status)) {
    623516                if (usb_port_dev_connected(&status)) {
    624                         usb_log_info("some connection changed");
     517                        usb_log_info("some connection changed\n");
    625518                        usb_hub_init_add_device(hub, port, usb_port_speed(&status));
    626519                } else {
     
    634527                        usb_hub_over_current(hub,port);
    635528                }else{
    636                         usb_log_info("over current condition was auto-resolved on port %d",
     529                        usb_log_info("over current condition was auto-resolved on port %d\n",
    637530                                        port);
    638531                }
     
    642535                usb_log_info("port reset complete");
    643536                if (usb_port_enabled(&status)) {
    644                         usb_hub_finalize_add_device(hub, port, usb_port_low_speed(&status));
     537                        usb_hub_finalize_add_device(hub, port, usb_port_speed(&status));
    645538                } else {
    646                         usb_log_warning("port reset, but port still not enabled");
     539                        usb_log_warning("port reset, but port still not enabled\n");
    647540                }
    648541        }
     
    653546        usb_port_set_dev_connected(&status, false);
    654547        if (status>>16) {
    655                 usb_log_info("there was some unsupported change on port %d: %X",
     548                usb_log_info("there was some unsupported change on port %d: %X\n",
    656549                                port,status);
    657550
    658551        }
    659         /// \TODO handle other changes - is there any?
    660552}
    661553
     
    668560int usb_hub_check_hub_changes(usb_hub_info_t * hub_info){
    669561        int opResult;
    670         opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.status_change);
     562        opResult = usb_endpoint_pipe_start_session(
     563                        hub_info->status_change_pipe);
    671564        if(opResult != EOK){
    672                 usb_log_error("could not initialize communication for hub; %d",
     565                usb_log_error("could not initialize communication for hub; %d\n",
    673566                                opResult);
    674567                return opResult;
     
    686579         */
    687580        opResult = usb_endpoint_pipe_read(
    688                         &hub_info->endpoints.status_change,
     581                        hub_info->status_change_pipe,
    689582                        change_bitmap, byte_length, &actual_size
    690583                        );
     
    692585        if (opResult != EOK) {
    693586                free(change_bitmap);
    694                 usb_log_warning("something went wrong while getting status of hub");
    695                 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
     587                usb_log_warning("something went wrong while getting status of hub\n");
     588                usb_endpoint_pipe_end_session(hub_info->status_change_pipe);
    696589                return opResult;
    697590        }
    698591        unsigned int port;
    699         opResult = usb_endpoint_pipe_start_session(&hub_info->endpoints.control);
    700         if(opResult!=EOK){
    701                 usb_log_error("could not start control pipe session %d", opResult);
    702                 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
     592        opResult = usb_endpoint_pipe_start_session(hub_info->control_pipe);
     593        if(opResult!=EOK){
     594                usb_log_error("could not start control pipe session %d\n", opResult);
     595                usb_endpoint_pipe_end_session(hub_info->status_change_pipe);
    703596                return opResult;
    704597        }
    705598        opResult = usb_hc_connection_open(&hub_info->connection);
    706599        if(opResult!=EOK){
    707                 usb_log_error("could not start host controller session %d",
     600                usb_log_error("could not start host controller session %d\n",
    708601                                opResult);
    709                 usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
    710                 usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
     602                usb_endpoint_pipe_end_session(hub_info->control_pipe);
     603                usb_endpoint_pipe_end_session(hub_info->status_change_pipe);
    711604                return opResult;
    712605        }
     
    722615        }
    723616        usb_hc_connection_close(&hub_info->connection);
    724         usb_endpoint_pipe_end_session(&hub_info->endpoints.control);
    725         usb_endpoint_pipe_end_session(&hub_info->endpoints.status_change);
     617        usb_endpoint_pipe_end_session(hub_info->control_pipe);
     618        usb_endpoint_pipe_end_session(hub_info->status_change_pipe);
    726619        free(change_bitmap);
    727620        return EOK;
  • uspace/drv/usbhub/usbhub.h

    r8373f53 rfa8f1f7  
    4545
    4646#include <usb/pipes.h>
     47#include <usb/devdrv.h>
     48
     49
     50/** Hub status-change endpoint description
     51 *
     52 * For more see usb hub specification in 11.15.1 of
     53 */
     54extern usb_endpoint_description_t hub_status_change_endpoint_description;
     55
     56
    4757
    4858/* Hub endpoints. */
    49 typedef struct {
     59/*typedef struct {
    5060        usb_endpoint_pipe_t control;
    5161        usb_endpoint_pipe_t status_change;
    5262} usb_hub_endpoints_t;
    53 
     63*/
    5464
    5565
     
    5868        /** Number of ports. */
    5969        int port_count;
     70
    6071        /** attached device handles, for each port one */
    6172        usb_hc_attached_device_t * attached_devs;
    62         /** General usb device info. */
    63         //usb_hcd_attached_device_info_t * usb_device;
    64         /** General device info*/
    65         ddf_dev_t * device;
     73       
    6674        /** connection to hcd */
    67         //usb_device_connection_t connection;
    6875        usb_hc_connection_t connection;
    69         /** */
    70         usb_device_connection_t device_connection;
    71         /** hub endpoints */
    72         usb_hub_endpoints_t endpoints;
    7376
     77        /** default address is used indicator
     78         *
     79         * If default address is requested by this device, it cannot
     80         * be requested by the same hub again, otherwise a deadlock will occur.
     81         */
    7482        bool is_default_address_used;
     83
     84        /** convenience pointer to status change pipe
     85         *
     86         * Status change pipe is initialized in usb_device structure. This is
     87         * pointer into this structure, so that it does not have to be
     88         * searched again and again for the 'right pipe'.
     89         */
     90        usb_endpoint_pipe_t * status_change_pipe;
     91
     92        /** convenience pointer to control pipe
     93         *
     94         * Control pipe is initialized in usb_device structure. This is
     95         * pointer into this structure, so that it does not have to be
     96         * searched again and again for the 'right pipe'.
     97         */
     98        usb_endpoint_pipe_t * control_pipe;
     99
     100        /** generic usb device data*/
     101        usb_device_t * usb_device;
    75102} usb_hub_info_t;
    76103
     
    80107 */
    81108int usb_hub_control_loop(void * hub_info_param);
    82 
    83 /** Callback when new hub device is detected.
    84  *
    85  * @param dev New device.
    86  * @return Error code.
    87  */
    88 int usb_add_hub_device(ddf_dev_t *dev);
    89109
    90110/**
     
    97117
    98118
    99 
    100 
     119int usb_hub_add_device(usb_device_t * usb_dev);
    101120
    102121#endif
  • uspace/drv/usbhub/usbhub_private.h

    r8373f53 rfa8f1f7  
    5858
    5959
    60 //************
    61 //
    62 // convenience debug printf for usb hub
    63 //
    64 //************
    65 #define dprintf(level, format, ...) \
    66         usb_log_printf((level), format "\n", ##__VA_ARGS__)
    67 
    68 
    6960/**
    7061 * Create hub structure instance
     
    7768 */
    7869usb_hub_info_t * usb_create_hub_info(ddf_dev_t * device);
    79 
    80 /** List of hubs maanged by this driver */
    81 extern usb_general_list_t usb_hub_list;
    82 
    83 /** Lock for hub list*/
    84 extern fibril_mutex_t usb_hub_list_lock;
    85 
    86 
    87 /**
    88  * Perform complete control read transaction
    89  *
    90  * Manages all three steps of transaction: setup, read and finalize
    91  * @param phone
    92  * @param target
    93  * @param request Request packet
    94  * @param rcvd_buffer Received data
    95  * @param rcvd_size
    96  * @param actual_size Actual size of received data
    97  * @return error code
    98  */
    99 /*
    100 int usb_drv_sync_control_read(
    101     usb_endpoint_pipe_t *pipe,
    102     usb_device_request_setup_packet_t * request,
    103     void * rcvd_buffer, size_t rcvd_size, size_t * actual_size
    104 );*/
    105 
    106 /**
    107  * Perform complete control write transaction
    108  *
    109  * Manages all three steps of transaction: setup, write and finalize
    110  * @param phone
    111  * @param target
    112  * @param request Request packet to send data
    113  * @param sent_buffer
    114  * @param sent_size
    115  * @return error code
    116  */
    117 /*int usb_drv_sync_control_write(
    118     usb_endpoint_pipe_t *pipe,
    119     usb_device_request_setup_packet_t * request,
    120     void * sent_buffer, size_t sent_size
    121 );*/
    12270
    12371/**
     
    163111
    164112/**
    165  * @brief create uint8_t array with serialized descriptor
     113 * create uint8_t array with serialized descriptor
    166114 *
    167115 * @param descriptor
     
    171119
    172120/**
    173  * @brief create deserialized desriptor structure out of serialized descriptor
     121 * create deserialized desriptor structure out of serialized descriptor
    174122 *
    175123 * The serialized descriptor must be proper usb hub descriptor,
  • uspace/drv/usbhub/utils.c

    r8373f53 rfa8f1f7  
    8888
    8989        if (sdescriptor[1] != USB_DESCTYPE_HUB) {
    90                 dprintf(1,"[usb_hub] wrong descriptor %x\n",sdescriptor[1]);
     90                usb_log_warning("trying to deserialize wrong descriptor %x\n",sdescriptor[1]);
    9191                return NULL;
    9292        }
     
    103103                        ? 1 : 0);
    104104        result->devices_removable = (uint8_t*) malloc(var_size);
    105         //printf("[usb_hub] getting removable devices data \n");
     105
    106106        size_t i;
    107107        for (i = 0; i < var_size; ++i) {
     
    111111}
    112112
    113 //control transactions
    114 /*
    115 int usb_drv_sync_control_read(
    116     int phone, usb_target_t target,
    117     usb_device_request_setup_packet_t * request,
    118     void * rcvd_buffer, size_t rcvd_size, size_t * actual_size
    119 ) {
    120         usb_handle_t handle;
    121         int opResult;
    122         //setup
    123         opResult = usb_drv_async_control_read_setup(phone, target,
    124             request, sizeof (usb_device_request_setup_packet_t),
    125             &handle);
    126         if (opResult != EOK) {
    127                 return opResult;
    128         }
    129         opResult = usb_drv_async_wait_for(handle);
    130         if (opResult != EOK) {
    131                 return opResult;
    132         }
    133         //read
    134         opResult = usb_drv_async_control_read_data(phone, target,
    135                         rcvd_buffer, rcvd_size, actual_size,
    136                         &handle);
    137         if (opResult != EOK) {
    138                 return opResult;
    139         }
    140         opResult = usb_drv_async_wait_for(handle);
    141         if (opResult != EOK) {
    142                 return opResult;
    143         }
    144         //finalize
    145         opResult = usb_drv_async_control_read_status(phone, target,
    146                         &handle);
    147         if (opResult != EOK) {
    148                 return opResult;
    149         }
    150         opResult = usb_drv_async_wait_for(handle);
    151         if (opResult != EOK) {
    152                 return opResult;
    153         }
    154         return EOK;
    155 }
    156 
    157 int usb_drv_sync_control_write(
    158     int phone, usb_target_t target,
    159     usb_device_request_setup_packet_t * request,
    160     void * sent_buffer, size_t sent_size
    161 ) {
    162         usb_handle_t handle;
    163         int opResult;
    164         //setup
    165         opResult = usb_drv_async_control_write_setup(phone, target,
    166             request, sizeof (usb_device_request_setup_packet_t),
    167             &handle);
    168         if (opResult != EOK) {
    169                 return opResult;
    170         }
    171         opResult = usb_drv_async_wait_for(handle);
    172         if (opResult != EOK) {
    173                 return opResult;
    174         }
    175         //write
    176         opResult = usb_drv_async_control_write_data(phone, target,
    177                         sent_buffer, sent_size,
    178                         &handle);
    179         if (opResult != EOK) {
    180                 return opResult;
    181         }
    182         opResult = usb_drv_async_wait_for(handle);
    183         if (opResult != EOK) {
    184                 return opResult;
    185         }
    186         //finalize
    187         opResult = usb_drv_async_control_write_status(phone, target,
    188             &handle);
    189         if (opResult != EOK) {
    190                 return opResult;
    191         }
    192         opResult = usb_drv_async_wait_for(handle);
    193         if (opResult != EOK) {
    194                 return opResult;
    195         }
    196         return EOK;
    197 }
    198 
    199 */
    200 
    201113
    202114
  • uspace/lib/usb/include/usb/devdrv.h

    r8373f53 rfa8f1f7  
    7979         */
    8080        const char *name;
    81         /** Expected endpoints description. */
     81        /** Expected endpoints description, excluding default control endpoint.
     82         *
     83         * It MUST be of size expected_enpoints_count(excluding default ctrl) + 1
     84         * where the last record MUST BE NULL, otherwise catastrophic things may
     85         * happen.
     86         */
    8287        usb_endpoint_description_t **endpoints;
    8388        /** Driver ops. */
  • uspace/lib/usb/src/devdrv.c

    r8373f53 rfa8f1f7  
    206206 * @return Error code.
    207207 */
    208 static int initialize_pipes(usb_driver_t *drv, usb_device_t *dev)
     208static int initialize_pipes(usb_device_t *dev)
    209209{
    210210        int rc;
     
    284284        dev->driver_data = NULL;
    285285
    286         rc = initialize_pipes(driver, dev);
     286        rc = initialize_pipes(dev);
    287287        if (rc != EOK) {
    288288                free(dev);
Note: See TracChangeset for help on using the changeset viewer.