Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:07

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /* GRTM CCSDS Telemetry Encoder driver
0004  *
0005  * COPYRIGHT (c) 2007.
0006  * Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #include <bsp.h>
0031 #include <rtems/libio.h>
0032 #include <stdlib.h>
0033 #include <stdio.h>
0034 #include <string.h>
0035 #include <assert.h>
0036 #include <ctype.h>
0037 #include <rtems/bspIo.h>
0038 
0039 #include <drvmgr/drvmgr.h>
0040 #include <grlib/ambapp.h>
0041 #include <grlib/ambapp_bus.h>
0042 #include <grlib/grtm.h>
0043 
0044 #include <grlib/grlib_impl.h>
0045 
0046 /*
0047 #define DEBUG
0048 #define DEBUGFUNCS
0049 */
0050 
0051 #include <grlib/debug_defs.h>
0052 
0053 /* GRTM register map */
0054 struct grtm_regs {
0055     volatile unsigned int   dma_ctrl;   /* DMA Control Register (0x00) */
0056     volatile unsigned int   dma_status; /* DMA Status Register (0x04) */
0057     volatile unsigned int   dma_len;    /* DMA Length Register (0x08) */    
0058     volatile unsigned int   dma_bd;     /* DMA Descriptor Pointer Register (0x0c) */
0059 
0060     volatile unsigned int   dma_cfg;    /* DMA Configuration Register (0x10) */
0061     volatile unsigned int   revision;   /* GRTM Revision Register (0x14) */
0062 
0063     int unused0[(0x80-0x18)/4];
0064 
0065     volatile unsigned int   ctrl;       /* TM Control Register (0x80) */
0066     volatile unsigned int   status;     /* TM Status Register (0x84) */
0067     volatile unsigned int   cfg;        /* TM Configuration Register (0x88) */
0068     volatile unsigned int   size;       /* TM Size Register (0x8c) */
0069 
0070     volatile unsigned int   phy;        /* TM Physical Layer Register (0x90) */
0071     volatile unsigned int   code;       /* TM Coding Sub-Layer Register (0x94) */
0072     volatile unsigned int   asmr;       /* TM Attached Synchronization Marker Register (0x98) */
0073 
0074     int unused1;
0075 
0076     volatile unsigned int   all_frm;    /* TM All Frames Generation Register (0xa0) */
0077     volatile unsigned int   mst_frm;    /* TM Master Channel Frame Generation Register (0xa4) */
0078     volatile unsigned int   idle_frm;   /* TM Idle Frame Generation Register (0xa8) */
0079 
0080     int unused2[(0xc0-0xac)/4];
0081 
0082     volatile unsigned int   fsh[4];     /* TM FSH/Insert Zone Registers (0xc0..0xcc) */
0083 
0084     volatile unsigned int   ocf;        /* TM Operational Control Field Register (0xd0) */
0085 };
0086 
0087 /* DMA Control Register (0x00) */
0088 #define GRTM_DMA_CTRL_EN_BIT    0
0089 #define GRTM_DMA_CTRL_IE_BIT    1
0090 #define GRTM_DMA_CTRL_TXRST_BIT 2
0091 #define GRTM_DMA_CTRL_RST_BIT   3
0092 #define GRTM_DMA_CTRL_TFIE_BIT  4
0093 
0094 #define GRTM_DMA_CTRL_EN    (1<<GRTM_DMA_CTRL_EN_BIT)
0095 #define GRTM_DMA_CTRL_IE    (1<<GRTM_DMA_CTRL_IE_BIT)
0096 #define GRTM_DMA_CTRL_TXRST (1<<GRTM_DMA_CTRL_TXRST_BIT)
0097 #define GRTM_DMA_CTRL_RST   (1<<GRTM_DMA_CTRL_RST_BIT)
0098 #define GRTM_DMA_CTRL_TFIE  (1<<GRTM_DMA_CTRL_TFIE_BIT)
0099 
0100 /* DMA Status Register (0x04) */
0101 #define GRTM_DMA_STS_TE_BIT 0
0102 #define GRTM_DMA_STS_TI_BIT 1
0103 #define GRTM_DMA_STS_TA_BIT 2
0104 #define GRTM_DMA_STS_TFF_BIT    3
0105 #define GRTM_DMA_STS_TFS_BIT    4
0106 
0107 #define GRTM_DMA_STS_TE     (1<<GRTM_DMA_STS_TE_BIT)
0108 #define GRTM_DMA_STS_TI     (1<<GRTM_DMA_STS_TI_BIT)
0109 #define GRTM_DMA_STS_TA     (1<<GRTM_DMA_STS_TA_BIT)
0110 #define GRTM_DMA_STS_TFF    (1<<GRTM_DMA_STS_TFF_BIT)
0111 #define GRTM_DMA_STS_TFS    (1<<GRTM_DMA_STS_TFS_BIT)
0112 #define GRTM_DMA_STS_ALL    0x1f
0113 
0114 /* DMA Length Register (0x08) */
0115 #define GRTM_DMA_LEN_LEN_BIT    0
0116 #define GRTM_DMA_LEN_LIM_BIT    16
0117 
0118 #define GRTM_DMA_LEN_LEN    (0x7ff<<GRTM_DMA_LEN_LEN_BIT)
0119 #define GRTM_DMA_LEN_LIM    (0x3ff<<GRTM_DMA_LEN_LIM_BIT)
0120 
0121 /* DMA Descriptor Pointer Register (0x0c) */
0122 #define GRTM_DMA_BD_INDEX_BIT   0
0123 #define GRTM_DMA_BD_BASE_BIT    10
0124 
0125 #define GRTM_DMA_BD_INDEX   (0x3ff<<GRTM_DMA_BD_INDEX_BIT)
0126 #define GRTM_DMA_BD_BASE    (0xfffffc<<GRTM_DMA_BD_BASE_BIT)
0127 
0128 /* DMA Configuration Register (0x10) */
0129 #define GRTM_DMA_CFG_BLKSZ_BIT  0
0130 #define GRTM_DMA_CFG_FIFOSZ_BIT 16
0131 
0132 #define GRTM_DMA_CFG_BLKSZ  (0xffff<<GRTM_DMA_CFG_BLKSZ_BIT)
0133 #define GRTM_DMA_CFG_FIFOSZ (0xffff<<GRTM_DMA_CFG_FIFOSZ_BIT)
0134 
0135 /* TM Control Register (0x80) */
0136 #define GRTM_CTRL_EN_BIT    0
0137 
0138 #define GRTM_CTRL_EN        (1<<GRTM_CTRL_EN_BIT)
0139 
0140 /* TM Status Register (0x84) - Unused */
0141 
0142 /* TM Configuration Register (0x88) */
0143 #define GRTM_CFG_SC_BIT     0
0144 #define GRTM_CFG_SP_BIT     1
0145 #define GRTM_CFG_CE_BIT     2
0146 #define GRTM_CFG_NRZ_BIT    3
0147 #define GRTM_CFG_PSR_BIT    4
0148 #define GRTM_CFG_TE_BIT     5
0149 #define GRTM_CFG_RSDEP_BIT  6
0150 #define GRTM_CFG_RS_BIT     9
0151 #define GRTM_CFG_AASM_BIT   11
0152 #define GRTM_CFG_FECF_BIT   12
0153 #define GRTM_CFG_OCF_BIT    13
0154 #define GRTM_CFG_EVC_BIT    14
0155 #define GRTM_CFG_IDLE_BIT   15
0156 #define GRTM_CFG_FSH_BIT    16
0157 #define GRTM_CFG_MCG_BIT    17
0158 #define GRTM_CFG_IZ_BIT     18
0159 #define GRTM_CFG_FHEC_BIT   19
0160 #define GRTM_CFG_AOS_BIT    20
0161 #define GRTM_CFG_CIF_BIT    21
0162 #define GRTM_CFG_OCFB_BIT   22
0163 
0164 #define GRTM_CFG_SC     (1<<GRTM_CFG_SC_BIT)
0165 #define GRTM_CFG_SP     (1<<GRTM_CFG_SP_BIT)
0166 #define GRTM_CFG_CE     (1<<GRTM_CFG_CE_BIT)
0167 #define GRTM_CFG_NRZ        (1<<GRTM_CFG_NRZ_BIT)
0168 #define GRTM_CFG_PSR        (1<<GRTM_CFG_PSR_BIT)
0169 #define GRTM_CFG_TE     (1<<GRTM_CFG_TE_BIT)
0170 #define GRTM_CFG_RSDEP      (0x7<<GRTM_CFG_RSDEP_BIT)
0171 #define GRTM_CFG_RS     (0x3<<GRTM_CFG_RS_BIT)
0172 #define GRTM_CFG_AASM       (1<<GRTM_CFG_AASM_BIT)
0173 #define GRTM_CFG_FECF       (1<<GRTM_CFG_FECF_BIT)
0174 #define GRTM_CFG_OCF        (1<<GRTM_CFG_OCF_BIT)
0175 #define GRTM_CFG_EVC        (1<<GRTM_CFG_EVC_BIT)
0176 #define GRTM_CFG_IDLE       (1<<GRTM_CFG_IDLE_BIT)
0177 #define GRTM_CFG_FSH        (1<<GRTM_CFG_FSH_BIT)
0178 #define GRTM_CFG_MCG        (1<<GRTM_CFG_MCG_BIT)
0179 #define GRTM_CFG_IZ     (1<<GRTM_CFG_IZ_BIT)
0180 #define GRTM_CFG_FHEC       (1<<GRTM_CFG_FHEC_BIT)
0181 #define GRTM_CFG_AOS        (1<<GRTM_CFG_AOS_BIT)
0182 #define GRTM_CFG_CIF        (1<<GRTM_CFG_CIF_BIT)
0183 #define GRTM_CFG_OCFB       (1<<GRTM_CFG_OCFB_BIT)
0184 
0185 /* TM Size Register (0x8c) */
0186 #define GRTM_SIZE_BLKSZ_BIT 0
0187 #define GRTM_SIZE_FIFOSZ_BIT    8
0188 #define GRTM_SIZE_LEN_BIT   20
0189 
0190 #define GRTM_SIZE_BLKSZ     (0xff<<GRTM_SIZE_BLKSZ_BIT)
0191 #define GRTM_SIZE_FIFOSZ    (0xfff<<GRTM_SIZE_FIFOSZ_BIT)
0192 #define GRTM_SIZE_LEN       (0xfff<<GRTM_SIZE_LEN_BIT)
0193 
0194 /* TM Physical Layer Register (0x90) */
0195 #define GRTM_PHY_SUB_BIT    0
0196 #define GRTM_PHY_SCF_BIT    15
0197 #define GRTM_PHY_SYM_BIT    16
0198 #define GRTM_PHY_SF_BIT     31
0199 
0200 #define GRTM_PHY_SUB        (0x7fff<<GRTM_PHY_SUB_BIT)
0201 #define GRTM_PHY_SCF        (1<<GRTM_PHY_SCF_BIT)
0202 #define GRTM_PHY_SYM        (0x7fff<<GRTM_PHY_SYM_BIT)
0203 #define GRTM_PHY_SF     (1<<GRTM_PHY_SF_BIT)
0204 
0205 /* TM Coding Sub-Layer Register (0x94) */
0206 #define GRTM_CODE_SC_BIT    0
0207 #define GRTM_CODE_SP_BIT    1
0208 #define GRTM_CODE_CERATE_BIT    2
0209 #define GRTM_CODE_CE_BIT    5
0210 #define GRTM_CODE_NRZ_BIT   6
0211 #define GRTM_CODE_PSR_BIT   7
0212 #define GRTM_CODE_RS8_BIT   11
0213 #define GRTM_CODE_RSDEP_BIT 12
0214 #define GRTM_CODE_RS_BIT    15
0215 #define GRTM_CODE_AASM_BIT  16
0216 #define GRTM_CODE_CSEL_BIT  17
0217 
0218 #define GRTM_CODE_SC        (1<<GRTM_CODE_SC_BIT)
0219 #define GRTM_CODE_SP        (1<<GRTM_CODE_SP_BIT)
0220 #define GRTM_CODE_CERATE    (0x7<<GRTM_CODE_CERATE_BIT)
0221 #define GRTM_CODE_CE        (1<<GRTM_CODE_CE_BIT)
0222 #define GRTM_CODE_NRZ       (1<<GRTM_CODE_NRZ_BIT)
0223 #define GRTM_CODE_PSR       (1<<GRTM_CODE_PSR_BIT)
0224 #define GRTM_CODE_RS8       (1<<GRTM_CODE_RS8_BIT)
0225 #define GRTM_CODE_RSDEP     (0x7<<GRTM_CODE_RSDEP_BIT)
0226 #define GRTM_CODE_RS        (1<<GRTM_CODE_RS_BIT)
0227 #define GRTM_CODE_AASM      (1<<GRTM_CODE_AASM_BIT)
0228 #define GRTM_CODE_CSEL      (0x3<<GRTM_CODE_CSEL_BIT)
0229 
0230 /* TM Attached Synchronization Marker Register (0x98) */
0231 #define GRTM_ASM_BIT        0
0232 
0233 #define GRTM_ASM        0xffffffff
0234 
0235 /* TM All Frames Generation Register (0xa0) */
0236 #define GRTM_ALL_LEN_BIT    0
0237 #define GRTM_ALL_VER_BIT    12
0238 #define GRTM_ALL_FHEC_BIT   14
0239 #define GRTM_ALL_FECF_BIT   15
0240 #define GRTM_ALL_IZ_BIT     16
0241 #define GRTM_ALL_IZLEN_BIT  17
0242 
0243 #define GRTM_ALL_LEN        (0x7ff<<GRTM_ALL_LEN_BIT)
0244 #define GRTM_ALL_VER        (0x3<<GRTM_ALL_VER_BIT)
0245 #define GRTM_ALL_FHEC       (1<<GRTM_ALL_FHEC_BIT)
0246 #define GRTM_ALL_FECF       (1<<GRTM_ALL_FECF_BIT)
0247 #define GRTM_ALL_IZ     (1<<GRTM_ALL_IZ_BIT)
0248 #define GRTM_ALL_IZLEN      (0x1f<<GRTM_ALL_IZLEN_BIT)
0249 
0250 /* TM Master Channel Frame Generation Register (0xa4) */
0251 #define GRTM_MST_OW_BIT     0
0252 #define GRTM_MST_OCF_BIT    1
0253 #define GRTM_MST_FSH_BIT    2
0254 #define GRTM_MST_MC_BIT     3
0255 #define GRTM_MST_MCCNTR_BIT 24
0256 
0257 #define GRTM_MST_OW     (1<<GRTM_MST_OW_BIT)
0258 #define GRTM_MST_OCF        (1<<GRTM_MST_OCF_BIT)
0259 #define GRTM_MST_FSH        (1<<GRTM_MST_FSH_BIT)
0260 #define GRTM_MST_MC     (0xff<<GRTM_MST_MC_BIT)
0261 
0262 /* TM Idle Frame Generation Register (0xa8) */
0263 #define GRTM_IDLE_SCID_BIT  0
0264 #define GRTM_IDLE_VCID_BIT  10
0265 #define GRTM_IDLE_MC_BIT    16
0266 #define GRTM_IDLE_VCC_BIT   17
0267 #define GRTM_IDLE_FSH_BIT   18
0268 #define GRTM_IDLE_EVC_BIT   19
0269 #define GRTM_IDLE_OCF_BIT   20
0270 #define GRTM_IDLE_IDLE_BIT  21
0271 #define GRTM_IDLE_MCCNTR_BIT    24
0272 
0273 #define GRTM_IDLE_SCID      (0x3ff<<GRTM_IDLE_SCID_BIT)
0274 #define GRTM_IDLE_VCID      (0x3f<<GRTM_IDLE_VCID_BIT)
0275 #define GRTM_IDLE_MC        (1<<GRTM_IDLE_MC_BIT)
0276 #define GRTM_IDLE_VCC       (1<<GRTM_IDLE_VCC_BIT)
0277 #define GRTM_IDLE_FSH       (1<<GRTM_IDLE_FSH_BIT)
0278 #define GRTM_IDLE_EVC       (1<<GRTM_IDLE_EVC_BIT)
0279 #define GRTM_IDLE_OCF       (1<<GRTM_IDLE_OCF_BIT)
0280 #define GRTM_IDLE_IDLE      (1<<GRTM_IDLE_IDLE_BIT)
0281 #define GRTM_IDLE_MCCNTR    (0xff<<GRTM_IDLE_MCCNTR_BIT)
0282 
0283 /* TM FSH/Insert Zone Registers (0xc0..0xcc) */
0284 #define GRTM_FSH_DATA_BIT   0
0285 
0286 #define GRTM_FSH_DATA       0xffffffff
0287 
0288 
0289 /* TM Operational Control Field Register (0xd0) */
0290 #define GRTM_OCF_CLCW_BIT   0
0291 
0292 #define GRTM_OCF_CLCW       0xffffffff
0293 
0294 
0295 /* GRTM Revision 0 */
0296 #define GRTM_REV0_DMA_CTRL_TXRDY_BIT    5
0297 #define GRTM_REV0_DMA_CTRL_TXRDY    (1<<GRTM_REV0_DMA_CTRL_TXRDY_BIT)
0298 
0299 /* GRTM Revision 1 */
0300 #define GRTM_REV1_DMA_STS_TXRDY_BIT 6
0301 #define GRTM_REV1_DMA_STS_TXSTAT_BIT    7
0302 #define GRTM_REV1_DMA_STS_TXRDY     (1<<GRTM_REV1_DMA_STS_TXRDY_BIT)
0303 #define GRTM_REV1_DMA_STS_TXSTAT    (1<<GRTM_REV1_DMA_STS_TXSTAT_BIT)
0304 
0305 #define GRTM_REV1_REV_SREV_BIT      0
0306 #define GRTM_REV1_REV_MREV_BIT      8
0307 #define GRTM_REV1_REV_TIRQ_BIT      16
0308 #define GRTM_REV1_REV_SREV      (0xff<<GRTM_REV1_REV_SREV_BIT)
0309 #define GRTM_REV1_REV_MREV      (0xff<<GRTM_REV1_REV_MREV_BIT)
0310 #define GRTM_REV1_REV_TIRQ      (1<<GRTM_REV1_REV_TIRQ_BIT)
0311 
0312 
0313 /* GRTM transmit descriptor (0x400 Alignment need) */
0314 struct grtm_bd {
0315     volatile unsigned int   ctrl;
0316     unsigned int        address;
0317 };
0318 
0319 #define GRTM_BD_EN_BIT      0
0320 #define GRTM_BD_WR_BIT      1
0321 #define GRTM_BD_IE_BIT      2
0322 #define GRTM_BD_FECFB_BIT   3
0323 #define GRTM_BD_IZB_BIT     4
0324 #define GRTM_BD_FHECB_BIT   5
0325 #define GRTM_BD_OCFB_BIT    6
0326 #define GRTM_BD_FSHB_BIT    7
0327 #define GRTM_BD_MCB_BIT     8
0328 #define GRTM_BD_VCE_BIT     9
0329 #define GRTM_BD_TS_BIT      14
0330 #define GRTM_BD_UE_BIT      15
0331 
0332 #define GRTM_BD_EN      (1<<GRTM_BD_EN_BIT)
0333 #define GRTM_BD_WR      (1<<GRTM_BD_WR_BIT)
0334 #define GRTM_BD_IE      (1<<GRTM_BD_IE_BIT)
0335 #define GRTM_BD_FECFB       (1<<GRTM_BD_FECFB_BIT)
0336 #define GRTM_BD_IZB     (1<<GRTM_BD_IZB_BIT)
0337 #define GRTM_BD_FHECB       (1<<GRTM_BD_FHECB_BIT)
0338 #define GRTM_BD_OCFB        (1<<GRTM_BD_OCFB_BIT)
0339 #define GRTM_BD_FSHB        (1<<GRTM_BD_FSHB_BIT)
0340 #define GRTM_BD_MCB     (1<<GRTM_BD_MCB_BIT)
0341 #define GRTM_BD_VCE     (1<<GRTM_BD_VCE_BIT)
0342 #define GRTM_BD_TS      (1<<GRTM_BD_TS_BIT)
0343 #define GRTM_BD_UE      (1<<GRTM_BD_UE_BIT)
0344 
0345 /* Load register */
0346 
0347 #define READ_REG(address)   (*(volatile unsigned int *)address)
0348 
0349 /* Driver functions */
0350 static rtems_device_driver grtm_initialize(rtems_device_major_number  major, rtems_device_minor_number  minor, void *arg);
0351 static rtems_device_driver grtm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0352 static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0353 static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0354 static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0355 static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0356 
0357 #define GRTM_DRIVER_TABLE_ENTRY { grtm_initialize, grtm_open, grtm_close, grtm_read, grtm_write, grtm_ioctl }
0358 
0359 static rtems_driver_address_table grtm_driver = GRTM_DRIVER_TABLE_ENTRY;
0360 
0361 /* Structure that connects BD with SoftWare Frame */
0362 struct grtm_ring {
0363     struct grtm_ring    *next;
0364     struct grtm_bd      *bd;
0365     struct grtm_frame   *frm;
0366 };
0367 
0368 struct grtm_priv {
0369     struct drvmgr_dev   *dev;       /* Driver manager device */
0370     char            devName[52];    /* Device Name */
0371     struct grtm_regs    *regs;
0372     int         irq;
0373     int         minor;
0374     int         subrev;     /* GRTM Revision */
0375     SPIN_DECLARE(devlock);          /* spin-lock ISR protection */
0376 
0377     int         open;
0378     int         running;
0379 
0380     struct grtm_bd      *bds;
0381     void            *_bds;
0382 
0383     /* Interrupt generation */
0384     int         enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */
0385     volatile int        handling_transmission;  /* Tells ISR if user are active changing descriptors/queues */
0386 
0387     struct grtm_ring    *_ring;     /* Root of ring */
0388     struct grtm_ring    *ring;      /* Next ring to use for new frames to be transmitted */
0389     struct grtm_ring    *ring_end;  /* Oldest activated ring used */
0390 
0391     /* Collections of frames Ready to sent/ Scheduled for transmission/Sent 
0392      * frames waiting for the user to reclaim 
0393      */
0394     struct grtm_list    ready;      /* Frames Waiting for free BDs */
0395     struct grtm_list    scheduled;  /* Frames in BDs beeing transmitted */
0396     struct grtm_list    sent;       /* Sent Frames waiting for user to reclaim and reuse */
0397 
0398     /* Number of frames in the lists */
0399     int         ready_cnt;  /* Number of ready frames */
0400     int         scheduled_cnt;  /* Number of scheduled frames */
0401     int         sent_cnt;   /* Number of sent frames */
0402 
0403     struct grtm_ioc_hw  hw_avail;   /* Hardware support available */
0404     struct grtm_ioc_config  config;
0405     struct grtm_ioc_stats   stats;
0406 
0407     rtems_id        sem_tx;
0408 };
0409 
0410 /* Prototypes */
0411 static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf);
0412 static void grtm_hw_reset(struct grtm_priv *pDev);
0413 static void grtm_interrupt(void *arg);
0414 
0415 /* Common Global Variables */
0416 static rtems_id grtm_dev_sem;
0417 static int grtm_driver_io_registered = 0;
0418 static rtems_device_major_number grtm_driver_io_major = 0;
0419 
0420 /******************* Driver manager interface ***********************/
0421 
0422 /* Driver prototypes */
0423 static int grtm_register_io(rtems_device_major_number *m);
0424 static int grtm_device_init(struct grtm_priv *pDev);
0425 
0426 static int grtm_init2(struct drvmgr_dev *dev);
0427 static int grtm_init3(struct drvmgr_dev *dev);
0428 
0429 static struct drvmgr_drv_ops grtm_ops = 
0430 {
0431     {NULL, grtm_init2, grtm_init3, NULL},
0432     NULL,
0433     NULL
0434 };
0435 
0436 static struct amba_dev_id grtm_ids[] = 
0437 {
0438     {VENDOR_GAISLER, GAISLER_GRTM},
0439     {0, 0}      /* Mark end of table */
0440 };
0441 
0442 static struct amba_drv_info grtm_drv_info =
0443 {
0444     {
0445         DRVMGR_OBJ_DRV,         /* Driver */
0446         NULL,               /* Next driver */
0447         NULL,               /* Device list */
0448         DRIVER_AMBAPP_GAISLER_GRTM_ID,  /* Driver ID */
0449         "GRTM_DRV",         /* Driver Name */
0450         DRVMGR_BUS_TYPE_AMBAPP,     /* Bus Type */
0451         &grtm_ops,
0452         NULL,               /* Funcs */
0453         0,              /* No devices yet */
0454         0,
0455     },
0456     &grtm_ids[0]
0457 };
0458 
0459 void grtm_register_drv (void)
0460 {
0461     DBG("Registering GRTM driver\n");
0462     drvmgr_drv_register(&grtm_drv_info.general);
0463 }
0464 
0465 static int grtm_init2(struct drvmgr_dev *dev)
0466 {
0467     struct grtm_priv *priv;
0468 
0469     DBG("GRTM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0470     priv = dev->priv = grlib_calloc(1, sizeof(*priv));
0471     if ( !priv )
0472         return DRVMGR_NOMEM;
0473     priv->dev = dev;
0474 
0475     /* This core will not find other cores, so we wait for init2() */
0476 
0477     return DRVMGR_OK;
0478 }
0479 
0480 static int grtm_init3(struct drvmgr_dev *dev)
0481 {
0482     struct grtm_priv *priv;
0483     char prefix[32];
0484     rtems_status_code status;
0485 
0486     priv = dev->priv;
0487 
0488     /* Do initialization */
0489 
0490     if ( grtm_driver_io_registered == 0) {
0491         /* Register the I/O driver only once for all cores */
0492         if ( grtm_register_io(&grtm_driver_io_major) ) {
0493             /* Failed to register I/O driver */
0494             dev->priv = NULL;
0495             return DRVMGR_FAIL;
0496         }
0497 
0498         grtm_driver_io_registered = 1;
0499     }
0500 
0501     /* I/O system registered and initialized 
0502      * Now we take care of device initialization.
0503      */
0504     if ( grtm_device_init(priv) ) {
0505         return DRVMGR_FAIL;
0506     }
0507 
0508     /* Get Filesystem name prefix */
0509     prefix[0] = '\0';
0510     if ( drvmgr_get_dev_prefix(dev, prefix) ) {
0511         /* Failed to get prefix, make sure of a unique FS name
0512          * by using the driver minor.
0513          */
0514         sprintf(priv->devName, "/dev/grtm%d", dev->minor_drv);
0515     } else {
0516         /* Got special prefix, this means we have a bus prefix
0517          * And we should use our "bus minor"
0518          */
0519         sprintf(priv->devName, "/dev/%sgrtm%d", prefix, dev->minor_bus);
0520     }
0521 
0522     SPIN_INIT(&priv->devlock, priv->devName);
0523 
0524     /* Register Device */
0525     status = rtems_io_register_name(priv->devName, grtm_driver_io_major, dev->minor_drv);
0526     if (status != RTEMS_SUCCESSFUL) {
0527         return DRVMGR_FAIL;
0528     }
0529 
0530     return DRVMGR_OK;
0531 }
0532 
0533 /******************* Driver Implementation ***********************/
0534 
0535 static int grtm_register_io(rtems_device_major_number *m)
0536 {
0537     rtems_status_code r;
0538 
0539     if ((r = rtems_io_register_driver(0, &grtm_driver, m)) == RTEMS_SUCCESSFUL) {
0540         DBG("GRTM driver successfully registered, major: %d\n", *m);
0541     } else {
0542         switch(r) {
0543         case RTEMS_TOO_MANY:
0544             printk("GRTM rtems_io_register_driver failed: RTEMS_TOO_MANY\n");
0545             return -1;
0546         case RTEMS_INVALID_NUMBER:  
0547             printk("GRTM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n");
0548             return -1;
0549         case RTEMS_RESOURCE_IN_USE:
0550             printk("GRTM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n");
0551             return -1;
0552         default:
0553             printk("GRTM rtems_io_register_driver failed\n");
0554             return -1;
0555         }
0556     }
0557     return 0;
0558 }
0559 
0560 static int grtm_device_init(struct grtm_priv *pDev)
0561 {
0562     struct amba_dev_info *ambadev;
0563     struct ambapp_core *pnpinfo;
0564     union drvmgr_key_value *value;
0565 
0566     /* Get device information from AMBA PnP information */
0567     ambadev = (struct amba_dev_info *)pDev->dev->businfo;
0568     if ( ambadev == NULL ) {
0569         return -1;
0570     }
0571     pnpinfo = &ambadev->info;
0572     pDev->irq = pnpinfo->irq;
0573     pDev->regs = (struct grtm_regs *)pnpinfo->apb_slv->start;
0574     pDev->minor = pDev->dev->minor_drv;
0575     pDev->open = 0;
0576     pDev->running = 0;
0577 
0578     /* Create Binary RX Semaphore with count = 0 */
0579     if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'M', '0' + pDev->minor),
0580         0,
0581         RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\
0582         RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, 
0583         0,
0584         &pDev->sem_tx) != RTEMS_SUCCESSFUL ) {
0585         return -1;
0586     }
0587 
0588     /* Allocate Memory for Buffer Descriptor Table, or let user provide a custom
0589      * address.
0590      */
0591     value = drvmgr_dev_key_get(pDev->dev, "bdTabAdr", DRVMGR_KT_POINTER);
0592     if ( value ) {
0593         pDev->bds = (struct grtm_bd *)value->ptr;
0594         pDev->_bds = (void *)value->ptr;    
0595     } else {
0596         pDev->bds = (struct grtm_bd *)grtm_memalign(0x400, 0x400, &pDev->_bds);
0597     }
0598     if ( !pDev->bds ) {
0599         DBG("GRTM: Failed to allocate descriptor table\n");
0600         return -1;
0601     }
0602     memset(pDev->bds, 0, 0x400);
0603 
0604     pDev->_ring = grlib_malloc(sizeof(*pDev->_ring) * 128);
0605     if ( !pDev->_ring ) {
0606         return -1;
0607     }
0608 
0609     /* Reset Hardware before attaching IRQ handler */
0610     grtm_hw_reset(pDev);
0611 
0612     /* Read SUB revision number, ignore  */
0613     pDev->subrev = (READ_REG(&pDev->regs->revision) & GRTM_REV1_REV_SREV)
0614             >> GRTM_REV1_REV_SREV_BIT;
0615 
0616     return 0;
0617 }
0618 
0619 
0620 static inline void grtm_list_clr(struct grtm_list *list)
0621 {
0622     list->head = NULL;
0623     list->tail = NULL;
0624 }
0625 
0626 static void grtm_hw_reset(struct grtm_priv *pDev)
0627 {
0628     /* Reset Core */
0629     pDev->regs->dma_ctrl = GRTM_DMA_CTRL_RST;
0630 }
0631 
0632 static void grtm_hw_get_implementation(struct grtm_priv *pDev, struct grtm_ioc_hw *hwcfg)
0633 {
0634     unsigned int cfg = READ_REG(&pDev->regs->cfg);
0635 
0636     hwcfg->cs   = (cfg & GRTM_CFG_SC)   ? 1:0;
0637     hwcfg->sp   = (cfg & GRTM_CFG_SP)   ? 1:0;
0638     hwcfg->ce   = (cfg & GRTM_CFG_CE)   ? 1:0;
0639     hwcfg->nrz  = (cfg & GRTM_CFG_NRZ)  ? 1:0;
0640     hwcfg->psr  = (cfg & GRTM_CFG_PSR)  ? 1:0;
0641     hwcfg->te   = (cfg & GRTM_CFG_TE)   ? 1:0;
0642     hwcfg->rsdep    = (cfg & GRTM_CFG_RSDEP)>>GRTM_CFG_RSDEP_BIT;
0643     hwcfg->rs   = (cfg & GRTM_CFG_RS)>>GRTM_CFG_RS_BIT;
0644     hwcfg->aasm = (cfg & GRTM_CFG_AASM) ? 1:0;
0645     hwcfg->fecf = (cfg & GRTM_CFG_FECF) ? 1:0;
0646     hwcfg->ocf  = (cfg & GRTM_CFG_OCF)  ? 1:0;
0647     hwcfg->evc  = (cfg & GRTM_CFG_EVC)  ? 1:0;
0648     hwcfg->idle = (cfg & GRTM_CFG_IDLE) ? 1:0;
0649     hwcfg->fsh  = (cfg & GRTM_CFG_FSH)  ? 1:0;
0650     hwcfg->mcg  = (cfg & GRTM_CFG_MCG)  ? 1:0;
0651     hwcfg->iz   = (cfg & GRTM_CFG_IZ)   ? 1:0;
0652     hwcfg->fhec = (cfg & GRTM_CFG_FHEC) ? 1:0;
0653     hwcfg->aos  = (cfg & GRTM_CFG_AOS)  ? 1:0;
0654     hwcfg->cif  = (cfg & GRTM_CFG_CIF)  ? 1:0;
0655     hwcfg->ocfb = (cfg & GRTM_CFG_OCFB) ? 1:0;
0656 
0657     cfg = READ_REG(&pDev->regs->dma_cfg);
0658     hwcfg->blk_size = (cfg & GRTM_DMA_CFG_BLKSZ) >> GRTM_DMA_CFG_BLKSZ_BIT;
0659     hwcfg->fifo_size= (cfg & GRTM_DMA_CFG_FIFOSZ) >> GRTM_DMA_CFG_FIFOSZ_BIT;
0660 }
0661 
0662 
0663 /* TODO: Implement proper default calculation from hardware configuration */
0664 static void grtm_hw_get_default_modes(struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
0665 {
0666     cfg->mode = GRTM_MODE_TM;
0667     cfg->frame_length = 223;
0668     cfg->limit = 0; /* Make driver auto configure it on START, user may override with non-zero value */
0669     cfg->as_marker = 0x1ACFFC1D;
0670 
0671     /* Physical */
0672     cfg->phy_subrate = 1;
0673     cfg->phy_symbolrate = 1;
0674     cfg->phy_opts = 0;
0675 
0676     /* Coding Layer */
0677     cfg->code_rsdep = 1;
0678     cfg->code_ce_rate = 0;
0679     cfg->code_csel = 0;
0680     cfg->code_opts = 0;
0681 
0682     /* All Frame Generation */
0683     cfg->all_izlen = 0;
0684     cfg->all_opts = GRTM_IOC_ALL_FECF;
0685 
0686     /* Master Channel Frame Generation */
0687     if ( hwcfg->mcg ) {
0688         cfg->mf_opts = GRTM_IOC_MF_MC;
0689     } else {
0690         cfg->mf_opts = 0;
0691     }
0692 
0693     /* Idle Frame Generation */
0694     cfg->idle_scid = 0;
0695     cfg->idle_vcid = 0;
0696     if ( hwcfg->idle ) {
0697         cfg->idle_opts = GRTM_IOC_IDLE_EN;
0698     } else {
0699         cfg->idle_opts = 0;
0700     }
0701 
0702     /* Interrupt options */
0703     cfg->blocking = 0;  /* non-blocking mode is default */
0704     cfg->enable_cnt = 16;   /* generate interrupt every 16 descriptor */
0705     cfg->isr_desc_proc = 1; /* Let interrupt handler do descriptor processing */
0706     cfg->timeout = RTEMS_NO_TIMEOUT;
0707     
0708 }
0709 
0710 static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf)
0711 {
0712     *(int *)realbuf = (int)grlib_malloc(length+boundary);
0713     DBG("GRTM: Alloced %d (0x%x) bytes, requested: %d\n",length+boundary,length+boundary,length);
0714     return (void *)(((*(unsigned int *)realbuf)+boundary) & ~(boundary-1));
0715 }
0716 
0717 static int grtm_hw_set_config(struct grtm_priv *pDev, struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg)
0718 {
0719     struct grtm_regs *regs = pDev->regs;
0720     unsigned int tmp;
0721     unsigned int limit;
0722 
0723     if ( cfg->limit == 0 ) {
0724         /* Calculate Limit */
0725         if ( cfg->frame_length > hwcfg->blk_size ) {
0726             limit = hwcfg->blk_size*2;
0727         } else {
0728             limit = cfg->frame_length;
0729         }
0730     } else {
0731         /* Use user configured limit */
0732         limit = cfg->limit;
0733     }
0734 
0735     /* Frame Length and Limit */
0736     regs->dma_len = (((limit-1) << GRTM_DMA_LEN_LIM_BIT) & GRTM_DMA_LEN_LIM)|
0737             (((cfg->frame_length-1) << GRTM_DMA_LEN_LEN_BIT) & GRTM_DMA_LEN_LEN);
0738 
0739     /* Physical layer options */
0740     tmp =   (cfg->phy_opts & (GRTM_IOC_PHY_SCF|GRTM_IOC_PHY_SF)) | 
0741         (((cfg->phy_symbolrate-1)<<GRTM_PHY_SYM_BIT) & GRTM_PHY_SYM) | (((cfg->phy_subrate-1)<<GRTM_PHY_SUB_BIT) & GRTM_PHY_SUB);
0742     regs->phy = tmp;
0743 
0744     /* Coding Sub-layer Options */
0745     tmp =   (cfg->code_opts & GRTM_IOC_CODE_ALL) | ((cfg->code_csel<<GRTM_CODE_CSEL_BIT) & GRTM_CODE_CSEL) |
0746         (((cfg->code_rsdep-1)<<GRTM_CODE_RSDEP_BIT) & GRTM_CODE_RSDEP) | ((cfg->code_ce_rate<<GRTM_CODE_CERATE_BIT) & GRTM_CODE_CERATE);
0747     regs->code = tmp;
0748 
0749     /* Attached synchronization marker register */
0750     regs->asmr = cfg->as_marker;
0751 
0752     /* All Frames Generation */
0753     tmp =   ((cfg->all_opts & GRTM_IOC_ALL_ALL)<<14) | 
0754         ((cfg->all_izlen<<GRTM_ALL_IZLEN_BIT) & GRTM_ALL_IZLEN) |
0755         ((cfg->mode<<GRTM_ALL_VER_BIT) & GRTM_ALL_VER);
0756     regs->all_frm = tmp;
0757 
0758     /* Master Frame Generation */
0759     regs->mst_frm = cfg->mf_opts & GRTM_IOC_MF_ALL;
0760 
0761     /* Idle frame Generation */
0762     tmp =   ((cfg->idle_opts & GRTM_IOC_IDLE_ALL) << 16) |
0763         ((cfg->idle_vcid << GRTM_IDLE_VCID_BIT) & GRTM_IDLE_VCID) |
0764         ((cfg->idle_scid << GRTM_IDLE_SCID_BIT) & GRTM_IDLE_SCID);
0765     regs->idle_frm = tmp;
0766 
0767     return 0;
0768 }
0769 
0770 static int grtm_start(struct grtm_priv *pDev)
0771 {
0772     struct grtm_regs *regs = pDev->regs;
0773     int i;
0774     struct grtm_ioc_config *cfg = &pDev->config;
0775     unsigned int txrdy;
0776 
0777     /* Clear Descriptors */
0778     memset(pDev->bds,0,0x400);
0779     
0780     /* Clear stats */
0781     memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
0782     
0783     /* Init Descriptor Ring */
0784     memset(pDev->_ring,0,sizeof(struct grtm_ring)*128);
0785     for(i=0;i<127;i++){
0786         pDev->_ring[i].next = &pDev->_ring[i+1];
0787         pDev->_ring[i].bd = &pDev->bds[i];
0788         pDev->_ring[i].frm = NULL;
0789     }
0790     pDev->_ring[127].next = &pDev->_ring[0];
0791     pDev->_ring[127].bd = &pDev->bds[127];
0792     pDev->_ring[127].frm = NULL;
0793 
0794     pDev->ring = &pDev->_ring[0];
0795     pDev->ring_end = &pDev->_ring[0];
0796 
0797     /* Clear Scheduled, Ready and Sent list */
0798     grtm_list_clr(&pDev->ready);
0799     grtm_list_clr(&pDev->scheduled);
0800     grtm_list_clr(&pDev->sent);
0801 
0802     /* Software init */
0803     pDev->handling_transmission = 0;
0804     
0805     /* Reset the transmitter */
0806     regs->dma_ctrl = GRTM_DMA_CTRL_TXRST;
0807     regs->dma_ctrl = 0; /* Leave Reset */
0808 
0809     /* Clear old interrupts */
0810     regs->dma_status = GRTM_DMA_STS_ALL;
0811 
0812     /* Set Descriptor Pointer Base register to point to first descriptor */
0813     drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA, (void *)pDev->bds,
0814                 (void **)&regs->dma_bd, 0x400);
0815 
0816     /* Set hardware options as defined by config */
0817     if ( grtm_hw_set_config(pDev, cfg, &pDev->hw_avail) ) {
0818         return RTEMS_IO_ERROR;
0819     }
0820 
0821     /* Enable TM Transmitter */
0822     regs->ctrl = GRTM_CTRL_EN;
0823 
0824     /* Wait for TXRDY to be cleared */
0825     i=1000;
0826     while( i > 0 ) {
0827         asm volatile ("nop"::);
0828         i--;
0829     }
0830 
0831     /* Check transmitter startup OK */
0832     i = 1000000;
0833     do {
0834         /* Location of TXRDY Bit is different for different revisions */
0835         if ( pDev->subrev == 0 ) {
0836             txrdy = READ_REG(&regs->dma_ctrl) &
0837                 GRTM_REV0_DMA_CTRL_TXRDY;
0838         } else {
0839             txrdy = READ_REG(&regs->dma_status) &
0840                 GRTM_REV1_DMA_STS_TXRDY;
0841         }
0842         if (txrdy != 0)
0843             break;
0844 
0845         asm volatile ("nop"::);
0846     } while ( --i > 0 );
0847     if ( i == 0 ) {
0848         /* Reset Failed */
0849         DBG("GRTM: start: Reseting transmitter failed (%d)\n",i);
0850         return RTEMS_IO_ERROR;
0851     }
0852     DBG("GRTM: reset time %d\n",i);
0853 
0854     /* Everything is configured, the TM transmitter is started
0855      * and idle frames has been sent.
0856      */
0857 
0858     /* Mark running before enabling the DMA transmitter */
0859     pDev->running = 1;
0860 
0861     /* Enable interrupts (Error and DMA TX) */
0862     regs->dma_ctrl = GRTM_DMA_CTRL_IE;
0863 
0864     DBG("GRTM: STARTED\n");
0865 
0866     return RTEMS_SUCCESSFUL;
0867 }
0868 
0869 static void grtm_stop(struct grtm_priv *pDev)
0870 {
0871     struct grtm_regs *regs = pDev->regs;
0872 
0873     /* Disable the transmitter & Interrupts */
0874     regs->dma_ctrl = 0;
0875     
0876     /* Clear any pending interrupt  */
0877     regs->dma_status = GRTM_DMA_STS_ALL;
0878 
0879     DBG("GRTM: STOPPED\n");
0880 
0881     /* Flush semaphore in case a thread is stuck waiting for TX Interrupts */
0882     rtems_semaphore_flush(pDev->sem_tx);
0883 }
0884 
0885 static rtems_device_driver grtm_open(
0886     rtems_device_major_number major, 
0887     rtems_device_minor_number minor, 
0888     void *arg)
0889 {
0890     struct grtm_priv *pDev;
0891     struct drvmgr_dev *dev;
0892 
0893     FUNCDBG();
0894 
0895     if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
0896         DBG("Wrong minor %d\n", minor);
0897         return RTEMS_INVALID_NUMBER;
0898     }
0899     pDev = (struct grtm_priv *)dev->priv;
0900     
0901     /* Wait until we get semaphore */
0902     if ( rtems_semaphore_obtain(grtm_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){
0903         return RTEMS_INTERNAL_ERROR;
0904     }
0905 
0906     /* Is device in use? */
0907     if ( pDev->open ){
0908         rtems_semaphore_release(grtm_dev_sem);
0909         return RTEMS_RESOURCE_IN_USE;
0910     }
0911     
0912     /* Mark device taken */
0913     pDev->open = 1;
0914     
0915     rtems_semaphore_release(grtm_dev_sem);
0916     
0917     DBG("grtm_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev);
0918     
0919     /* Set defaults */
0920     pDev->config.timeout = RTEMS_NO_TIMEOUT;    /* no timeout (wait forever) */
0921     pDev->config.blocking = 0;          /* polling mode */
0922     
0923     pDev->running = 0;              /* not in running mode yet */
0924 
0925     memset(&pDev->config,0,sizeof(pDev->config));
0926     
0927     /* The core has been reset when we execute here, so it is possible
0928      * to read out what HW is implemented from core.
0929      */
0930     grtm_hw_get_implementation(pDev, &pDev->hw_avail);
0931 
0932     /* Get default modes */
0933     grtm_hw_get_default_modes(&pDev->config,&pDev->hw_avail);
0934     
0935     return RTEMS_SUCCESSFUL;
0936 }
0937 
0938 static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0939 {
0940     struct grtm_priv *pDev;
0941     struct drvmgr_dev *dev;
0942 
0943     FUNCDBG();
0944 
0945     if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
0946         return RTEMS_INVALID_NUMBER;
0947     }
0948     pDev = (struct grtm_priv *)dev->priv;
0949 
0950     if ( pDev->running ){
0951         drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev);
0952         grtm_stop(pDev);
0953         pDev->running = 0;
0954     }
0955 
0956     /* Reset core */
0957     grtm_hw_reset(pDev);
0958 
0959     /* Clear descriptor area just for sure */
0960     memset(pDev->bds, 0, 0x400);
0961     
0962     /* Mark not open */
0963     pDev->open = 0;
0964 
0965     return RTEMS_SUCCESSFUL;
0966 }
0967 
0968 static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0969 {
0970     FUNCDBG();
0971     return RTEMS_NOT_IMPLEMENTED;
0972 }
0973 
0974 static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0975 {
0976     FUNCDBG();
0977     return RTEMS_NOT_IMPLEMENTED;
0978 }
0979 
0980 /* Scans the desciptor table for scheduled frames that has been sent, 
0981  * and moves these frames from the head of the scheduled queue to the
0982  * tail of the sent queue.
0983  *
0984  * Also, for all frames the status is updated.
0985  *
0986  * Return Value
0987  * Number of frames freed.
0988  */
0989 static int grtm_free_sent(struct grtm_priv *pDev)
0990 {
0991     struct grtm_ring *curr;
0992     struct grtm_frame *last_frm, *first_frm;
0993     int freed_frame_cnt=0;
0994     unsigned int ctrl;
0995 
0996     curr = pDev->ring_end;
0997 
0998     /* Step into TX ring to find sent frames */
0999     if ( !curr->frm ){
1000         /* No scheduled frames, abort */
1001         return 0;
1002     }
1003 
1004     /* There has been messages scheduled ==> scheduled messages may have been
1005      * transmitted and needs to be collected.
1006      */
1007 
1008     first_frm = curr->frm;
1009 
1010     /* Loop until first enabled unsent frame is found. 
1011      * A unused descriptor is indicated by an unassigned frm field
1012      */
1013     while ( curr->frm && !((ctrl=READ_REG(&curr->bd->ctrl)) & GRTM_BD_EN) ){
1014         /* Handle one sent Frame */
1015         
1016         /* Remember last handled frame so that insertion/removal from
1017          * frames lists go fast.
1018          */
1019         last_frm = curr->frm;
1020         
1021         /* 1. Set flags to indicate error(s) and other information */
1022         last_frm->flags |= GRTM_FLAGS_SENT; /* Mark sent */
1023         
1024         /* Update Stats */
1025         pDev->stats.frames_sent++;
1026     
1027         /* Did packet encounter link error? */
1028         if ( ctrl & GRTM_BD_UE ) {
1029             pDev->stats.err_underrun++;
1030             last_frm->flags |= GRRM_FLAGS_ERR;
1031         }
1032 
1033         curr->frm = NULL; /* Mark unused */
1034 
1035         /* Increment */
1036         curr = curr->next;
1037         freed_frame_cnt++;
1038     }
1039 
1040     /* 1. Remove all handled frames from scheduled queue
1041      * 2. Put all handled frames into sent queue
1042      */
1043     if ( freed_frame_cnt > 0 ){
1044 
1045         /* Save TX ring posistion */
1046         pDev->ring_end = curr;
1047 
1048         /* Remove all sent frames from scheduled list */
1049         if ( pDev->scheduled.tail == last_frm ){
1050             /* All scheduled frames sent... */
1051             pDev->scheduled.head = NULL;
1052             pDev->scheduled.tail = NULL;
1053         }else{
1054             pDev->scheduled.head = last_frm->next;
1055         }
1056         last_frm->next = NULL;
1057 
1058         /* Put all sent frames into "Sent queue" for user to
1059          * collect, later on.
1060          */
1061         if ( !pDev->sent.head ){
1062             /* Sent queue empty */
1063             pDev->sent.head = first_frm;
1064             pDev->sent.tail = last_frm;
1065         }else{
1066             pDev->sent.tail->next = first_frm;
1067             pDev->sent.tail = last_frm;
1068         }
1069     }
1070     return freed_frame_cnt;
1071 }
1072 
1073 
1074 /* Moves as many frames in the ready queue (as there are free descriptors for)
1075  * to the scheduled queue. The free descriptors are then assigned one frame
1076  * each and enabled for transmission.
1077  * 
1078  * Return Value
1079  * Returns number of frames moved from ready to scheduled queue 
1080  */
1081 static int grtm_schedule_ready(struct grtm_priv *pDev)
1082 {
1083     int cnt;
1084     unsigned int ctrl, dmactrl;
1085     struct grtm_ring *curr_bd;
1086     struct grtm_frame *curr_frm, *last_frm;
1087 
1088     if ( !pDev->ready.head ){
1089         return 0;
1090     }
1091 
1092     cnt=0;
1093     curr_frm = pDev->ready.head;
1094     curr_bd = pDev->ring;
1095     while( !curr_bd->frm ){
1096         /* Assign frame to descriptor */
1097         curr_bd->frm = curr_frm;
1098 
1099         /* Prepare descriptor address. Three cases:
1100          *  - GRTM core on same bus as CPU ==> no translation (Address used by CPU = address used by GRTM)
1101          *  - GRTM core on remote bus, and payload address given as used by CPU ==> Translation needed
1102          *  - GRTM core on remote bus, and payload address given as used by GRTM ==> no translation  [ USER does custom translation]
1103          */
1104         if ( curr_frm->flags & (GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER) ) {
1105             /* Do translation */
1106             drvmgr_translate(pDev->dev, CPUMEM_TO_DMA, (void *)curr_frm->payload, (void **)&curr_bd->bd->address);
1107             if ( curr_frm->flags & GRTM_FLAGS_TRANSLATE_AND_REMEMBER ) {
1108                 if ( curr_frm->payload != (unsigned int *)curr_bd->bd->address ) {
1109                     /* Translation needed */
1110                     curr_frm->flags &= ~GRTM_FLAGS_TRANSLATE_AND_REMEMBER;
1111                     curr_frm->flags |= GRTM_FLAGS_TRANSLATE;
1112                 } else {
1113                     /* No Trnaslation needed */
1114                     curr_frm->flags &= ~(GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER);
1115                 }
1116             }
1117         } else {
1118             /* Custom translation or no translation needed */
1119             curr_bd->bd->address = (unsigned int)curr_frm->payload;
1120         }
1121 
1122         ctrl = GRTM_BD_EN;
1123         if ( curr_bd->next == pDev->_ring ){
1124             ctrl |= GRTM_BD_WR; /* Wrap around */
1125         }
1126         /* Apply user options/flags */
1127         ctrl |= (curr_frm->flags & GRTM_FLAGS_MASK);
1128 
1129         /* Is this Frame going to be an interrupt Frame? */
1130         if ( (--pDev->enable_cnt_curr) <= 0 ){
1131             if ( pDev->config.enable_cnt == 0 ){
1132                 pDev->enable_cnt_curr = 0x3fffffff;
1133             }else{
1134                 pDev->enable_cnt_curr = pDev->config.enable_cnt;
1135                 ctrl |= GRTM_BD_IE;
1136             }
1137         }
1138 
1139         /* Enable descriptor */
1140         curr_bd->bd->ctrl = ctrl;
1141 
1142         last_frm = curr_frm;
1143         curr_bd = curr_bd->next;
1144         cnt++;
1145         
1146         /* Get Next Frame from Ready Queue */
1147         if ( curr_frm == pDev->ready.tail ){
1148             /* Handled all in ready queue. */
1149             curr_frm = NULL;
1150             break;
1151         }
1152         curr_frm = curr_frm->next;
1153     }
1154     
1155     /* Has frames have been scheduled? */
1156     if ( cnt > 0 ){
1157         /* Make last frame mark end of chain, probably pointless... */
1158         last_frm->next = NULL;
1159 
1160         /* Insert scheduled packets into scheduled queue */
1161         if ( !pDev->scheduled.head ){
1162             /* empty scheduled queue */
1163             pDev->scheduled.head = pDev->ready.head;
1164             pDev->scheduled.tail = last_frm;
1165         }else{
1166             pDev->scheduled.tail->next = pDev->ready.head;
1167             pDev->scheduled.tail = last_frm;
1168         }
1169 
1170         /* Remove scheduled packets from ready queue */
1171         pDev->ready.head = curr_frm;
1172         if ( !curr_frm ){
1173             pDev->ready.tail = NULL;
1174         }
1175 
1176         /* Update TX ring posistion */
1177         pDev->ring = curr_bd;
1178 
1179         /* Make hardware aware of the newly enabled descriptors */
1180         dmactrl = READ_REG(&pDev->regs->dma_ctrl);
1181         dmactrl &= ~(GRTM_DMA_CTRL_TXRST | GRTM_DMA_CTRL_RST);
1182         dmactrl |= GRTM_DMA_CTRL_EN;
1183         pDev->regs->dma_ctrl = dmactrl;
1184     }
1185 
1186     return cnt;
1187 }
1188 
1189 static void grtm_tx_process(struct grtm_priv *pDev)
1190 {
1191     int num;
1192 
1193     /* Free used descriptors and put the sent frame into the "Sent queue"  
1194      *   (SCHEDULED->SENT)
1195      */
1196     num = grtm_free_sent(pDev);
1197     pDev->scheduled_cnt -= num;
1198     pDev->sent_cnt += num;
1199 
1200     /* Use all available free descriptors there are frames for
1201      * in the ready queue.
1202      *   (READY->SCHEDULED)
1203      */
1204     if (pDev->running) {
1205         num = grtm_schedule_ready(pDev);
1206         pDev->ready_cnt -= num;
1207         pDev->scheduled_cnt += num;
1208     }
1209 }
1210 
1211 /*
1212  * The TX lock protects user tasks from the ISR. If TX DMA interrupt occurs
1213  * while the user task is processing the TX DMA descriptors the ISR will
1214  * ignore interrupt the request by not processing the DMA table since that
1215  * is done by the user task anyway. In SMP, when a user task enters the TX DMA
1216  * processing while the ISR (on another CPU) is also processing the user task
1217  * will loop waiting for the ISR to complete.
1218  */
1219 static int grtm_request_txlock(struct grtm_priv *pDev, int block)
1220 {
1221     SPIN_IRQFLAGS(irqflags);
1222     int got_lock = 0;
1223 
1224     do {
1225         SPIN_LOCK_IRQ(&pDev->devlock, irqflags);
1226         if (pDev->handling_transmission == 0) {
1227             pDev->handling_transmission = 1;
1228             got_lock = 1;
1229         }
1230         SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags);
1231     } while (!got_lock && block);
1232 
1233     return got_lock;
1234 }
1235 
1236 static inline int grtm_request_txlock_isr(struct grtm_priv *pDev)
1237 {
1238     SPIN_ISR_IRQFLAGS(irqflags);
1239     int got_lock = 0;
1240 
1241     SPIN_LOCK(&pDev->devlock, irqflags);
1242     if (pDev->handling_transmission == 0) {
1243         pDev->handling_transmission = 1;
1244         got_lock = 1;
1245     }
1246     SPIN_UNLOCK(&pDev->devlock, irqflags);
1247 
1248     return got_lock;
1249 }
1250 
1251 static inline void grtm_release_txlock(struct grtm_priv *pDev)
1252 {
1253     pDev->handling_transmission = 0;
1254 }
1255 
1256 static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
1257 {
1258     struct grtm_priv *pDev;
1259     struct drvmgr_dev *dev;
1260     rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg;
1261     unsigned int *data;
1262     int status;
1263     struct grtm_ioc_config *cfg;
1264     struct grtm_ioc_hw_status *hwregs;
1265     struct grtm_list *chain;
1266     struct grtm_frame *curr;
1267     struct grtm_ioc_hw *hwimpl;
1268     struct grtm_ioc_stats *stats;
1269     int num,ret;
1270 
1271     FUNCDBG();
1272 
1273     if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) {
1274         return RTEMS_INVALID_NUMBER;
1275     }
1276     pDev = (struct grtm_priv *)dev->priv;
1277 
1278     if (!ioarg)
1279         return RTEMS_INVALID_NAME;
1280 
1281     data = ioarg->buffer;
1282     ioarg->ioctl_return = 0;
1283     switch(ioarg->command) {
1284         case GRTM_IOC_START:
1285         if ( pDev->running ) {
1286             return RTEMS_RESOURCE_IN_USE; /* EBUSY */
1287         }
1288         if ( (status=grtm_start(pDev)) != RTEMS_SUCCESSFUL ){
1289             return status;
1290         }
1291         /* Register ISR & Enable interrupt */
1292         drvmgr_interrupt_register(dev, 0, "grtm", grtm_interrupt, pDev);
1293 
1294         /* Read and write are now open... */
1295         break;
1296 
1297         case GRTM_IOC_STOP:
1298         if ( !pDev->running ) {
1299             return RTEMS_RESOURCE_IN_USE;
1300         }
1301 
1302         /* Disable interrupts */
1303         drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev);
1304         grtm_stop(pDev);
1305         pDev->running = 0;
1306         break;
1307 
1308         case GRTM_IOC_ISSTARTED:
1309         if ( !pDev->running ) {
1310             return RTEMS_RESOURCE_IN_USE;
1311         }
1312         break;
1313 
1314         case GRTM_IOC_SET_BLOCKING_MODE:
1315         if ( (unsigned int)data > GRTM_BLKMODE_BLK ) {
1316             return RTEMS_INVALID_NAME;
1317         }
1318         DBG("GRTM: Set blocking mode: %d\n",(unsigned int)data);
1319         pDev->config.blocking = (unsigned int)data;
1320         break;
1321 
1322         case GRTM_IOC_SET_TIMEOUT:
1323         DBG("GRTM: Timeout: %d\n",(unsigned int)data);
1324         pDev->config.timeout = (rtems_interval)data;
1325         break;
1326 
1327         case GRTM_IOC_SET_CONFIG:
1328         cfg = (struct grtm_ioc_config *)data;
1329         if ( !cfg ) {
1330             return RTEMS_INVALID_NAME;
1331         }
1332         
1333         if ( pDev->running ) {
1334             return RTEMS_RESOURCE_IN_USE;
1335         }
1336 
1337         pDev->config = *cfg;
1338         break;
1339 
1340         case GRTM_IOC_GET_STATS:
1341         stats = (struct grtm_ioc_stats *)data;
1342         if ( !stats ) {
1343             return RTEMS_INVALID_NAME;
1344         }
1345         memcpy(stats,&pDev->stats,sizeof(struct grtm_ioc_stats));
1346         break;
1347 
1348         case GRTM_IOC_CLR_STATS:
1349         memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats));
1350         break;
1351 
1352         case GRTM_IOC_GET_CONFIG:
1353         cfg = (struct grtm_ioc_config *)data;
1354         if ( !cfg ) {
1355             return RTEMS_INVALID_NAME;
1356         }
1357 
1358         *cfg = pDev->config;
1359         break;
1360 
1361         case GRTM_IOC_GET_OCFREG:
1362         if ( !pDev->hw_avail.ocf ) {
1363             /* Hardware does not implement the OCF register */
1364             return RTEMS_NOT_DEFINED;
1365         }
1366         if ( !data ) {
1367             return RTEMS_INVALID_NAME;
1368         }
1369         *(unsigned int **)data = (unsigned int *)&pDev->regs->ocf;
1370         break;
1371 
1372         case GRTM_IOC_GET_HW_IMPL:
1373         hwimpl = (struct grtm_ioc_hw *)data;
1374         if ( !hwimpl ) {
1375             return RTEMS_INVALID_NAME;
1376         }
1377         *hwimpl = pDev->hw_avail;
1378         break;
1379 
1380         case GRTM_IOC_GET_HW_STATUS:
1381         hwregs = (struct grtm_ioc_hw_status *)data;
1382         if ( !hwregs ) {
1383             return RTEMS_INVALID_NAME;
1384         }
1385         /* We disable interrupt in order to get a snapshot of the registers */
1386 /* TODO: implement hwregs */
1387         break;
1388 
1389         /* Put a chain of frames at the back of the "Ready frames" queue. This 
1390          * triggers the driver to put frames from the Ready queue into unused 
1391          * available descriptors. (Ready -> Scheduled)
1392          */
1393 
1394         case GRTM_IOC_SEND:
1395         if ( !pDev->running ){
1396             return RTEMS_RESOURCE_IN_USE;
1397         }
1398 
1399         /* Get pointer to frame chain wished be sent */
1400         chain = (struct grtm_list *)ioarg->buffer;
1401         if ( !chain ){
1402             /* No new frames to send ==> just trigger hardware
1403              * to send previously made ready frames to be sent.
1404              * If someone else is processing the DMA we igore the
1405              * request.
1406              */
1407             if (grtm_request_txlock(pDev, 0)) {
1408                 grtm_tx_process(pDev);
1409                 grtm_release_txlock(pDev);
1410             }
1411             break;
1412         }
1413         if ( !chain->tail || !chain->head ){
1414             return RTEMS_INVALID_NAME;
1415         }
1416 
1417         DBG("GRTM_SEND: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
1418 
1419         /* Mark ready frames unsent by clearing GRTM_FLAGS_SENT of all frames */
1420 
1421         num = 0;
1422         curr = chain->head;
1423         while(curr != chain->tail){
1424             curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
1425             curr = curr->next;
1426             num++;
1427         }
1428         curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR);
1429         num++;
1430 
1431         /* wait until we get the device lock */
1432         grtm_request_txlock(pDev, 1);
1433 
1434         /* 1. Put frames into ready queue 
1435          *    (New Frames->READY)
1436          */
1437         if ( pDev->ready.head ){
1438             /* Frames already on ready queue (no free descriptors previously) ==>
1439              * Put frames at end of ready queue
1440              */
1441             pDev->ready.tail->next = chain->head;
1442             pDev->ready.tail = chain->tail;
1443             chain->tail->next = NULL;
1444         }else{
1445             /* All frames is put into the ready queue for later processing */
1446             pDev->ready.head = chain->head;
1447             pDev->ready.tail = chain->tail;
1448             chain->tail->next = NULL;
1449         }
1450         pDev->ready_cnt += num; /* Added 'num' frames to ready queue */
1451 
1452         /* 2. SCHEDULED->SENT
1453          * 3. READY->SCHEDULED
1454          */
1455         grtm_tx_process(pDev);
1456         grtm_release_txlock(pDev);
1457         break;
1458 
1459         /* Take all available sent frames from the "Sent frames" queue.
1460          * If no frames has been sent, the thread may get blocked if in blocking
1461          * mode. The blocking mode is not available if driver is not in running mode.
1462          *
1463          * Note this ioctl may return success even if the driver is not in STARTED mode.
1464          * This is because in case of a error (link error of similar) and the driver switch
1465          * from START to STOP mode we must still be able to get our frames back.
1466          * 
1467          * Note in case the driver fails to send a frame for some reason (link error),
1468          * the sent flag is set to 0 indicating a failure.
1469          *
1470          */
1471         case GRTM_IOC_RECLAIM:
1472         /* Get pointer to were to place reaped chain */
1473         chain = (struct grtm_list *)ioarg->buffer;
1474         if ( !chain ){
1475             return RTEMS_INVALID_NAME;
1476         }
1477 
1478         /* Lock out interrupt handler */
1479         grtm_request_txlock(pDev, 1);
1480 
1481         do {
1482             /* Process descriptor table and populate with new
1483              * buffers:
1484              *    * SCHEDULED->SENT
1485              *    * READY->SCHEDULED
1486              */
1487             grtm_tx_process(pDev);
1488 
1489             /* Are there any frames on the sent queue waiting to be 
1490              * reclaimed?
1491              */
1492 
1493             if ( !pDev->sent.head ){
1494                 /* No frames to reclaim - no frame in sent queue.
1495                  * Instead we block thread until frames have been sent 
1496                  * if in blocking mode.
1497                  */
1498                 if ( pDev->running && pDev->config.blocking ){
1499                     ret = rtems_semaphore_obtain(pDev->sem_tx,RTEMS_WAIT,pDev->config.timeout);
1500                     if ( ret == RTEMS_TIMEOUT ) {
1501                         grtm_release_txlock(pDev);
1502                         return RTEMS_TIMEOUT;
1503                     } else if ( ret == RTEMS_SUCCESSFUL ) {
1504                         /* There might be frames available, go check */
1505                         continue;
1506                     } else {
1507                         /* any error (driver closed, internal error etc.) */
1508                         grtm_release_txlock(pDev);
1509                         return RTEMS_UNSATISFIED;
1510                     }
1511 
1512                 }else{
1513                     /* non-blocking mode, we quit */
1514                     chain->head = NULL;
1515                     chain->tail = NULL;
1516                     /* do not lock out interrupt handler any more */
1517                     grtm_release_txlock(pDev);
1518                     return RTEMS_TIMEOUT;
1519                 }
1520             }else{
1521                 /* Take all sent framess from sent queue to userspace queue */
1522                 chain->head = pDev->sent.head;
1523                 chain->tail = pDev->sent.tail;
1524                 chain->tail->next = NULL; /* Just for sure */
1525 
1526                 /* Mark no Sent */
1527                 grtm_list_clr(&pDev->sent);
1528                 pDev->sent_cnt = 0;
1529 
1530                 DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail);
1531                 break;
1532             }
1533 
1534         }while(1);
1535         
1536         /* do not lock out interrupt handler any more */
1537         grtm_release_txlock(pDev);
1538         break;
1539 
1540         default:
1541         return RTEMS_NOT_DEFINED;
1542     }
1543     return RTEMS_SUCCESSFUL;
1544 }
1545 
1546 static void grtm_interrupt(void *arg)
1547 {
1548     struct grtm_priv *pDev = arg;
1549     struct grtm_regs *regs = pDev->regs;
1550     unsigned int status;
1551 
1552     /* Clear interrupt by reading it */
1553     status = READ_REG(&regs->dma_status);
1554 
1555     /* Spurious Interrupt? */
1556     if ( !pDev->running || !status)
1557         return;
1558 
1559     regs->dma_status = status;
1560 
1561     if ( status & GRTM_DMA_STS_TFF ){
1562         pDev->stats.err_transfer_frame++;
1563     }
1564 
1565     if ( status & GRTM_DMA_STS_TA ){
1566         pDev->stats.err_ahb++;
1567     }
1568 
1569     if ( status & GRTM_DMA_STS_TE ){
1570         pDev->stats.err_tx++;
1571     }
1572 
1573     if ( status & GRTM_DMA_STS_TI ){
1574         
1575         if ( pDev->config.isr_desc_proc) {
1576             if (grtm_request_txlock_isr(pDev)) {
1577                 grtm_tx_process(pDev);
1578                 grtm_release_txlock(pDev);
1579             }
1580 
1581 #if 0
1582             if ( (pDev->config.blocking==GRTM_BLKMODE_COMPLETE) && pDev->timeout ){
1583                 /* Signal to thread only if enough data is available */
1584                 if ( pDev->wait_for_frames > grtm_data_avail(pDev) ){
1585                     /* Not enough data available */
1586                     goto procceed_processing_interrupts;
1587                 }
1588 
1589                 /* Enough number of frames has been transmitted which means that
1590                  * the waiting thread should be woken up.
1591                  */
1592                 rtems_semaphore_release(pDev->sem_tx);
1593             }
1594 #endif
1595         }
1596 
1597         if ( pDev->config.blocking == GRTM_BLKMODE_BLK ) {
1598             /* Blocking mode */
1599 
1600 #if 0
1601             /* Disable further Interrupts until handled by waiting task. */
1602             regs->dma_ctrl = READ_REG(&regs->dma_ctrl) & ~GRTM_DMA_CTRL_IE;
1603 #endif
1604         
1605             /* Signal Semaphore to wake waiting thread in ioctl(SEND|RECLAIM) */
1606             rtems_semaphore_release(pDev->sem_tx);
1607         }
1608 
1609     }
1610 #if 0
1611 procceed_processing_interrupts:
1612     ;
1613 #endif
1614 }
1615 
1616 static rtems_device_driver grtm_initialize(
1617   rtems_device_major_number major, 
1618   rtems_device_minor_number unused,
1619   void *arg
1620   )
1621 {
1622     /* Device Semaphore created with count = 1 */
1623     if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'M'),
1624         1,
1625         RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING,
1626         0,
1627         &grtm_dev_sem) != RTEMS_SUCCESSFUL ) {
1628         return RTEMS_INTERNAL_ERROR;
1629     }
1630 
1631     return RTEMS_SUCCESSFUL;
1632 }