Notice: We have migrated to GitLab launching 2024-05-01 see here: https://gitlab.rtems.org/

Changes between Version 2 and Version 3 of TBR/UserManual/DriverManager


Ignore:
Timestamp:
02/25/09 15:53:36 (15 years ago)
Author:
Hellstrom
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • TBR/UserManual/DriverManager

    v2 v3  
    1111
    1212The purpose of the Driver Manager is mainly,
    13  * more easily reuse driver code
    14  * enable drivers to be written independent of how certain sevices are implemented.
    15     - interrupt handling (registeration, masking, unmasking, acknowledging)
    16     - memory space translation
    17  * Unify the way drivers are configured. The driver registration string is replaced.
    18  * build images suitable for multiple targets with different hardware present.
    19  * Hardware topology awareness.
    20  * Easier to access which drivers are loaded and what hardware is present.
    21  * An initial step towards an architecture independent PCI layer.
     13 *  more easily reuse driver code
     14 *  enable drivers to be written independent of how certain services are implemented.
     15  *  interrupt handling (registration, masking, unmasking, acknowledging)
     16  *  memory space translation
     17  *  Bus information (Bus frequency, Snooping/Cache options)
     18 *  Unify the way drivers are configured. The driver registration string is replaced.
     19 *  build images suitable for multiple targets with different hardware present.
     20 *  Hardware topology awareness.
     21 *  Easier to access which drivers are loaded and what hardware is present.
     22 *  An initial step towards an architecture independent PCI layer.
    2223=  Overview  =
    2324
     
    8990        struct rtems_drvmgr_bus_ops     *ops;           /*!< Bus operations supported by this bus driver */
    9091        int                             dev_cnt;        /*!< Number of devices this bus has */
    91         struct bus_res_node             *reslist;       /*!< Bus resources, head of a linked list of resources. */
    92         struct bus_mmap_entry           *mmaps;         /*!< Memory Map Translation, array of address spaces */
    93 };
     92        struct rtems_drvmgr_bus_res     *reslist;       /*!< Bus resources, head of a linked list of resources. */
     93        struct rtems_drvmgr_mmap_entry  *mmaps;         /*!< Memory Map Translation, array of address spaces */
     94};
     95
    9496}}}
    9597=  Root bus driver  =
     
    195197
    196198/*! Union of different values */
    197 union key_value {
     199union rtems_drvmgr_key_value {
    198200        unsigned int            i;              /*!< Key data type UNIGNED INTEGER */
    199201        char                    *str;           /*!< Key data type STRING */
     
    201203};
    202204
    203 /* One key. Holding information relevant to the driver. */
    204 struct drv_res_key {
    205         char                    *key_name;      /* Name of key */
    206         int                     key_type;       /* How to interpret key_value */
    207         union key_value         key_value;      /* The value or pointer to the value */
    208 };
    209 
    210 /*! Bus resource entry, Driver resources for a certain device instance, containing a number of keys
     205/* One key. One Value. Holding information relevant to the driver. */
     206struct rtems_drvmgr_key {
     207        char                            *key_name;      /* Name of key */
     208        int                             key_type;       /* How to interpret key_value */
     209        union rtems_drvmgr_key_value    key_value;      /* The value or pointer to the value */
     210};
     211
     212/*! Driver resource entry, Driver resources for a certain device instance, containing a number of keys
    211213 * Where each key hold the data of interest.
    212214 */
    213 struct drv_res {
     215struct rtems_drvmgr_drv_res {
    214216        unsigned long long      drv_id;         /*!< Identifies the driver this resource is aiming */
    215217        int                     minor_bus;      /*!< Indentifies a specfic device */
    216         struct drv_res_key      *keys;          /*!< First key in key array */
     218        struct rtems_drvmgr_key *keys;          /*!< First key in key array, ended with KEY_EMPTY */
    217219};
    218220
    219221/*! Bus resource list node */
    220 struct bus_res_node {
    221         struct bus_res_node     *next;          /*!< Next resource node in list */
    222         struct drv_res          *resource;      /*!< Array of resources, one per device instance */
    223 };
     222struct rtems_drvmgr_bus_res {
     223        struct rtems_drvmgr_bus_res     *next;          /*!< Next resource node in list */
     224        struct rtems_drvmgr_drv_res     *resource;      /*!< Array of resources, one per device instance */
     225};
     226
    224227}}}
    225228
     229User defined Driver resources for the first three GRSPW cores. GRSPW core 1 and 2 uses the same configuration.
    226230{{{
    227231/* GRSPW0 resources */
    228 struct drv_res_key grlib_grspw0_res[] =
     232struct rtems_drvmgr_key grlib_grspw0_res[] =
    229233
    230234{
     
    233237        KEY_EMPTY
    234238};
    235 /* GRSPW1 resources */
    236 struct drv_res_key grlib_grspw1_res[] =
     239/* GRSPW1 and GRSPW2 resources */
     240struct rtems_drvmgr_key grlib_grspw1_res[] =
    237241
    238242{
     
    242246};
    243247/* GRLIB Plug & Play bus driver resources */
    244 struct drv_res grlib_drv_resources[] =
     248struct rtems_drvmgr_drv_res grlib_drv_resources[] =
    245249
    246250{
    247251        {DRIVER_AMBAPP_GAISLER_GRSPW_ID, 0, &grlib_grspw0_res[0]},
    248252        {DRIVER_AMBAPP_GAISLER_GRSPW_ID, 1, &grlib_grspw1_res[0]},
     253        {DRIVER_AMBAPP_GAISLER_GRSPW_ID, 2, &grlib_grspw1_res[0]},
    249254        RES_EMPTY
    250255};
     
    260265
    261266The following may be configured,
    262  - Driver resources per bus.
     267 - Driver resources per bus
    263268 - Root bus driver
    264  - Driver table.
     269 - Driver table
    265270
    266271The driver manager is configured by selecting drivers used by the driver manager and by
     
    411416        void *src_address,
    412417        void **dst_address);
     418
     419/*! Get key value from the bus resources matching [device[drv_id, minor_bus], key name, key type]
     420 * if no matching key NULL is returned.
     421 *
     422 * This is typically used by device drivers to find a particular device resource.
     423 *
     424 * \param dev         The device to search resource for.
     425 * \param key_name    The key name to search for
     426 * \param key_type    The key type expected.
     427 * \return            Returns NULL if no value found matching Key Name and Key Type was found for device.
     428 */
     429extern union rtems_drvmgr_key_value *rtems_drvmgr_dev_key_get(
     430        struct rtems_drvmgr_dev_info *dev,
     431        char *key_name,
     432        int key_type);
     433
     434}}}
     435=  Driver skeleton  =
     436
     437
     438Below is a selection from the GRSPW driver on how to create a driver using the Driver Manager structure. Below
     439is also a sniplet from AMBA PnP the bus driver that the GRSPW driver is intended for.
     440
     441{{{
     442/*  General part of a AMBA Plug & Play bus driver. */
     443
     444#define DRIVER_AMBA_ID(vendor, device, subid) \
     445        DRIVER_SUBID_ADD((((unsigned long long)(vendor)<<32) | ((unsigned long long)(device))), subid)
     446
     447/*** Gaisler Hardware Device Driver definitions ***/
     448#define DRIVER_AMBAPP_GAISLER_GRETH_ID          DRIVER_AMBA_ID(VENDOR_GAISLER, GAISLER_ETHMAC, 0)
     449#define DRIVER_AMBAPP_GAISLER_GRETH_ID_ALL      DRIVER_AMBA_ID(VENDOR_GAISLER, GAISLER_ETHMAC, -1)
     450
     451#define DRIVER_AMBAPP_GAISLER_GRSPW_ID          DRIVER_AMBA_ID(VENDOR_GAISLER, GAISLER_SPW, 0)
     452#define DRIVER_AMBAPP_GAISLER_GRSPW_ID_ALL      DRIVER_AMBA_ID(VENDOR_GAISLER, GAISLER_SPW, -1)
     453
     454#define DRIVER_AMBAPP_GAISLER_GRCAN_ID          DRIVER_AMBA_ID(VENDOR_GAISLER, GAISLER_GRCAN, 0)
     455#define DRIVER_AMBAPP_GAISLER_GRCAN_ID_ALL      DRIVER_AMBA_ID(VENDOR_GAISLER, GAISLER_GRCAN, -1)
     456
     457/*** ESA Hardware Device Driver definitions ***/
     458#define DRIVER_AMBAPP_ESA_MCTRL_ID              DRIVER_AMBA_ID(VENDOR_ESA, ESA_MCTRL, 0)
     459#define DRIVER_AMBAPP_ESA_MCTRL_ID_ALL          DRIVER_AMBA_ID(VENDOR_ESA, ESA_MCTRL, -1)
     460#define DRIVER_AMBAPP_MCTRL_ID                  DRIVER_AMBAPP_ESA_MCTRL_ID
     461#define DRIVER_AMBAPP_MCTRL_ID_ALL              DRIVER_AMBAPP_ESA_MCTRL_ID_ALL
     462
     463struct amba_dev_id {
     464        unsigned short          vendor;
     465        unsigned short          device;
     466        /* Version ? */
     467};
     468
     469struct amba_drv_info {
     470        struct rtems_drvmgr_drv_info    general;        /* General bus info */
     471        /* AMBA specific bus information */
     472        struct amba_dev_id              *ids;           /* Supported hardware */
     473};
     474
     475struct amba_dev_info {
     476        struct amba_dev_id      id;
     477        struct ambapp_dev_info  info;
     478};
     479}}}
     480
     481{{{
     482#define GRSPW_DRIVER_TABLE_ENTRY \
     483  { grspw_initialize, \
     484    grspw_open, \
     485    grspw_close, \
     486    grspw_read, \
     487    grspw_write, \
     488    grspw_control }
     489
     490static rtems_driver_address_table grspw_driver = GRSPW_DRIVER_TABLE_ENTRY;
     491static int grspw_driver_io_registered = 0;
     492static rtems_device_major_number grspw_driver_io_major = 0;
     493
     494/******************* Driver manager interface ***********************/
     495
     496/* Driver prototypes */
     497int grspw_register_io(rtems_device_major_number *m);
     498int grspw_device_init(GRSPW_DEV *pDev);
     499
     500rtems_status_code grspw_init1(struct rtems_drvmgr_dev_info *dev);
     501rtems_status_code grspw_init2(struct rtems_drvmgr_dev_info *dev);
     502
     503/* Driver operations */
     504struct rtems_drvmgr_drv_ops grspw_ops =
     505{
     506        grspw_init1,
     507        grspw_init2,
     508        NULL            /* Driver does not support device unregister (delete) */
     509};
     510
     511/* Supported Hardware, Two different cores, however GRSPW2 is backwards compatible
     512 * except for some small details.
     513 */
     514struct amba_dev_id grspw_ids[] =
     515{
     516        {VENDOR_GAISLER, GAISLER_SPW},
     517        {VENDOR_GAISLER, GAISLER_SPW2},
     518        {0, 0}          /* Mark end of table */
     519};
     520
     521struct amba_drv_info grspw_drv_info =
     522
     523{
     524        /* General Driver Part that all drivers must define */
     525        {
     526                NULL,                           /* Next driver */
     527                NULL,                           /* Device list */
     528                DRIVER_AMBAPP_GAISLER_GRSPW_ID, /* Driver ID */
     529                "GRSPW_DRV",                    /* Driver Name */
     530                DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
     531                &grspw_ops,                     /* Driver oprtations supported */
     532                0,                              /* No devices yet */
     533        },
     534        /* AMBA PnP Specific Driver Part that all AMBA PnP drivers must define */
     535        &grspw_ids[0]
     536};
     537
     538void grspw_register_drv (void)
     539{
     540        SPACEWIRE_DBG("Registering GRSPW driver\n");
     541        rtems_drvmgr_drv_register(&grspw_drv_info.general);
     542}
     543
     544rtems_status_code grspw_init1(struct rtems_drvmgr_dev_info *dev)
     545{
     546        GRSPW_DEV *priv;
     547
     548        SPACEWIRE_DBG("GRSPW[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
     549        priv = dev->priv = malloc(sizeof(GRSPW_DEV));
     550        if ( !priv )
     551                return RTEMS_NO_MEMORY;
     552        memset(priv, 0, sizeof(*priv));
     553        priv->dev = dev;
     554
     555        /* This core will not find other cores, so we wait for init2() */
     556
     557        return RTEMS_SUCCESSFUL;
     558}
     559
     560rtems_status_code grspw_init2(struct rtems_drvmgr_dev_info *dev)
     561{
     562        GRSPW_DEV *priv;
     563        char prefix[16];
     564        rtems_status_code status;
     565
     566        priv = dev->priv;
     567
     568        /* Do initialization */
     569
     570        if ( grspw_driver_io_registered == 0) {
     571                /* Register the I/O driver only once for all cores */
     572                if ( grspw_register_io(&grspw_driver_io_major) ) {
     573                        /* Failed to register I/O driver */
     574                        free(dev->priv);
     575                        dev->priv = NULL;
     576                        return RTEMS_UNSATISFIED;
     577                }
     578
     579                grspw_driver_io_registered = 1;
     580        }
     581
     582        /* I/O system registered and initialized
     583         * Now we take care of device initialization.
     584         */
     585
     586        /* Get Bus frequency in Hz. The SpaceWire core is clocked by the bus */
     587        if ( rtems_drvmgr_get_freq(dev, &priv->core_freq_khz) ) {
     588                return RTEMS_UNSATISFIED;
     589        }
     590        /* Convert from Hz -> kHz */
     591        priv->core_freq_khz = priv->core_freq_khz / 1000;
     592
     593        /* Initialize Device */
     594        if ( grspw_device_init(priv) ) {
     595                return RTEMS_UNSATISFIED;
     596        }
     597
     598        /* Get Filesystem name prefix, this is to separate GRSPW cores by bus,
     599         * This might not always be wanted.
     600         */
     601        prefix[0] = '\0';
     602        if ( rtems_drvmgr_get_dev_prefix(dev, prefix) ) {
     603                /* Failed to get prefix, make sure of a unique FS name
     604                 * by using the driver minor.
     605                 */
     606                sprintf(priv->devName, "/dev/grspw%d", dev->minor_drv);
     607        } else {
     608                /* Got special prefix, this means we have a bus prefix
     609                 * And we should use our "bus minor"
     610                 */
     611                sprintf(priv->devName, "/dev/%sgrspw%d", prefix, dev->minor_bus);
     612        }
     613
     614        /* Register Device */
     615        status = rtems_io_register_name(priv->devName, grspw_driver_io_major, dev->minor_drv);
     616        if (status != RTEMS_SUCCESSFUL) {
     617                return status;
     618        }
     619
     620        return RTEMS_SUCCESSFUL;
     621}
     622
     623/******************* Driver Implementation ***********************/
     624
     625int grspw_register_io(rtems_device_major_number *m)
     626{
     627        rtems_status_code r;
     628
     629        if ((r = rtems_io_register_driver(0, &grspw_driver, m)) == RTEMS_SUCCESSFUL) {
     630                SPACEWIRE_DBG("GRSPW driver successfully registered, major: %d\n", *m);
     631        } else {
     632                switch(r) {
     633                case RTEMS_TOO_MANY:
     634                        printk("GRSPW rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
     635                        return -1;
     636                case RTEMS_INVALID_NUMBER: 
     637                        printk("GRSPW rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
     638                        return -1;
     639                case RTEMS_RESOURCE_IN_USE:
     640                        printk("GRSPW rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
     641                        return -1;
     642                default:
     643                        printk("GRSPW rtems_io_register_driver failed\n");
     644                        return -1;
     645                }
     646        }
     647        return 0;
     648}
     649
     650int grspw_device_init(GRSPW_DEV *pDev)
     651{
     652        struct amba_dev_info *ambadev;
     653        struct ambapp_dev_info *pnpinfo;
     654        union rtems_drvmgr_key_value *value;
     655
     656        /* Get device information from AMBA PnP information */
     657        ambadev = (struct amba_dev_info *)pDev->dev->businfo;
     658        if ( ambadev == NULL ) {
     659                return -1;
     660        }
     661        pnpinfo = &ambadev->info;
     662        pDev->irq = pnpinfo->irq;
     663        pDev->regs = (LEON3_SPACEWIRE_Regs_Map *)pnpinfo->apb_slv->start;
     664        pDev->minor = pDev->dev->minor_drv;
     665
     666        /* Get SpaceWire core version */
     667        switch( pnpinfo->device ) {
     668                case GAISLER_SPW:
     669                        pDev->core_ver = 1;
     670                        break;
     671                case GAISLER_SPW2:
     672                        pDev->core_ver = 2;
     673                        break;
     674                default:
     675                        return -1;
     676        }
     677
     678        /* initialize the code with some resonable values,
     679         * actual initialization is done later using ioctl(fd)
     680         * on the opened device */
     681        pDev->config.rxmaxlen = SPACEWIRE_RXPCK_SIZE;
     682        pDev->txdbufsize = SPACEWIRE_TXD_SIZE;
     683        pDev->txhbufsize = SPACEWIRE_TXH_SIZE;
     684        pDev->rxbufsize = SPACEWIRE_RXPCK_SIZE;
     685        pDev->txbufcnt = SPACEWIRE_TXBUFS_NR;
     686        pDev->rxbufcnt = SPACEWIRE_RXBUFS_NR;
     687
     688        pDev->ptr_rxbuf0 = 0;
     689        pDev->ptr_txdbuf0 = 0;
     690        pDev->ptr_txhbuf0 = 0;
     691        pDev->rx_dma_area = 0;
     692        pDev->tx_data_dma_area = 0;
     693        pDev->tx_hdr_dma_area = 0;
     694
     695        /* Get Configuration from Bus resources (Let user override defaults) */
     696
     697        value = rtems_drvmgr_dev_key_get(pDev->dev, "txBdCnt", KEY_TYPE_INT);
     698        if ( value )
     699                pDev->txbufcnt = value->i;
     700
     701        value = rtems_drvmgr_dev_key_get(pDev->dev, "rxBdCnt", KEY_TYPE_INT);
     702        if ( value )
     703                pDev->rxbufcnt = value->i;
     704
     705        value = rtems_drvmgr_dev_key_get(pDev->dev, "txDataSize", KEY_TYPE_INT);
     706        if ( value )
     707                pDev->txdbufsize = value->i;
     708
     709        value = rtems_drvmgr_dev_key_get(pDev->dev, "txHdrSize", KEY_TYPE_INT);
     710        if ( value )
     711                pDev->txhbufsize = value->i;
     712
     713        value = rtems_drvmgr_dev_key_get(pDev->dev, "rxPktSize", KEY_TYPE_INT);
     714        if ( value )
     715                pDev->rxbufsize = value->i;
     716       
     717        value = rtems_drvmgr_dev_key_get(pDev->dev, "rxDmaArea", KEY_TYPE_INT);
     718        if ( value )
     719                pDev->rx_dma_area = value->i;
     720
     721        value = rtems_drvmgr_dev_key_get(pDev->dev, "txDataDmaArea", KEY_TYPE_INT);
     722        if ( value )
     723                pDev->tx_data_dma_area = value->i;
     724
     725        value = rtems_drvmgr_dev_key_get(pDev->dev, "txHdrDmaArea", KEY_TYPE_INT);
     726        if ( value )
     727                pDev->tx_hdr_dma_area = value->i;
     728
     729        if (grspw_buffer_alloc(pDev))
     730                return RTEMS_NO_MEMORY;
     731
     732        /* Create semaphores */
     733        rtems_semaphore_create(
     734                rtems_build_name('T', 'x', 'S', '0' + pDev->minor),
     735                0,
     736                RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
     737                RTEMS_NO_PRIORITY_CEILING,
     738                0,
     739                &(pDev->txsp));
     740
     741        rtems_semaphore_create(
     742                rtems_build_name('R', 'x', 'S', '0' + pDev->minor),
     743                0,
     744                RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
     745                RTEMS_NO_PRIORITY_CEILING,
     746                0,
     747                &(pDev->rxsp));
     748
     749        grspw_hw_init(pDev);
     750
     751        /* Register interrupt routine */
     752        if ( rtems_drvmgr_interrupt_register(pDev->dev, 0, grspw_interrupt, pDev) ) {
     753                return -1;
     754        }
     755
     756        return 0;
     757}
     758
     759/* IOCTL */
     760static rtems_device_driver grspw_control(
     761        rtems_device_major_number major,
     762        rtems_device_minor_number minor,
     763        void                * arg
     764        )
     765{
     766        int timeout;
     767        rtems_device_driver ret;
     768        rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg;
     769        GRSPW_DEV *pDev;
     770        struct rtems_drvmgr_dev_info *dev;
     771
     772        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "ctrl [%i,%i]\n", major, minor);
     773
     774        /* Get device pointer by searching in driver list for matching driver minor,
     775         * it would be better if RTEMS delivered the device pointer when calling
     776         * grspw_control...
     777         */
     778        if ( rtems_drvmgr_get_dev(&grspw_drv_info.general, minor, &dev) ) {
     779                return RTEMS_INVALID_NAME;
     780        }
     781        pDev = (GRSPW_DEV *)dev->priv;
     782
     783        if (!ioarg)
     784                return RTEMS_INVALID_NAME;
     785
     786        ioarg->ioctl_return = 0;
     787        switch(ioarg->command) {
     788                case SPACEWIRE_IOCTRL_START:
     789                        if ( pDev->running ){
     790                                return RTEMS_INVALID_NAME;
     791                        }
     792
     793                        /* Get timeout from userspace
     794                         *  timeout:
     795                         *   ¤  -1         = Default timeout
     796                         *   ¤  less than -1 = forever
     797                         *   ¤  0           = no wait, proceed if link is up
     798                         *   ¤  positive     = specifies number of system clock ticks that
     799                         *                   startup will wait for link to enter ready mode.
     800                         */
     801                        timeout = (int)ioarg->buffer;
     802                       
     803                        if ( (ret=grspw_hw_startup(pDev,timeout)) != RTEMS_SUCCESSFUL ) {
     804                                return ret;
     805                        }
     806                        pDev->running = 1;
     807                        /* Enable interrupt */
     808                        rtems_drvmgr_interrupt_enable(dev, 0);
     809                        break;
     810
     811                case SPACEWIRE_IOCTRL_STOP:
     812                        if ( !pDev->running ){
     813                                return RTEMS_INVALID_NAME;
     814                        }
     815                        /* Disable interrupts */
     816                        rtems_drvmgr_interrupt_disable(dev, 0);
     817
     818                        pDev->running = 0;
     819
     820                        /* Stop Receiver and transmitter */
     821                        grspw_hw_stop(pDev,1,1);
     822                        break;
     823
     824                default:
     825                        return RTEMS_NOT_IMPLEMENTED;
     826        }
     827
     828        SPACEWIRE_DBGC(DBGSPW_IOCALLS, "SPW_IOCTRL Return\n");
     829        return RTEMS_SUCCESSFUL;
     830}
    413831}}}
    414832=  TODO  =
     
    417835
    418836Changes to BSPs:
    419  * Add support to BSP to register root bus
    420  * Make driver resources on the root bus weak so that the user can override them.
    421 = = RTEMS  ==
    422 
    423  * Make I/O Manager handle regestering I/O Drivers before I/O Manager is initialized.
    424 =  == Driver Manager ===
     837 *  Add support to BSP to register root bus
     838 *  Make driver resources on the root bus weak so that the user can override them.
     839=  == RTEMS ===
     840
     841 *  Make I/O Manager handle registering I/O Drivers before I/O Manager is initialized.
     842
     843=== Driver Manager ===
    425844
    426845 *  Initialize the Driver manager before I/O Manager initialization.
     846 *  Write console/timer/IRQ driver