Home | History | Annotate | Line # | Download | only in mips
      1 /*  This file is part of the program GDB, the GNU debugger.
      2 
      3     Copyright (C) 1998-2024 Free Software Foundation, Inc.
      4     Contributed by Cygnus Solutions.
      5 
      6     This program is free software; you can redistribute it and/or modify
      7     it under the terms of the GNU General Public License as published by
      8     the Free Software Foundation; either version 3 of the License, or
      9     (at your option) any later version.
     10 
     11     This program is distributed in the hope that it will be useful,
     12     but WITHOUT ANY WARRANTY; without even the implied warranty of
     13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14     GNU General Public License for more details.
     15 
     16     You should have received a copy of the GNU General Public License
     17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     18 
     19     */
     20 
     21 /* This must come before any other includes.  */
     22 #include "defs.h"
     23 
     24 #include "sim-main.h"
     25 #include "hw-main.h"
     26 #include "dv-sockser.h"
     27 #include "sim-assert.h"
     28 
     29 #include <stdlib.h>
     30 
     31 /* DEVICE
     32 
     33 
     34    tx3904sio - tx3904 serial I/O
     35 
     36 
     37    DESCRIPTION
     38 
     39 
     40    Implements one tx3904 serial I/O controller described in the tx3904
     41    user guide.  Three instances are required for SIO0 and SIO1 within
     42    the tx3904, at different base addresses.
     43 
     44    Both internal and system clocks are synthesized as divided versions
     45    of the simulator clock.
     46 
     47    There is no support for:
     48     - CTS/RTS flow control
     49     - baud rate emulation - use infinite speed instead
     50     - general frame format - use 8N1
     51     - multi-controller system
     52     - DMA - use interrupt-driven or polled-I/O instead
     53 
     54 
     55    PROPERTIES
     56 
     57 
     58    reg <base> <length>
     59 
     60    Base of SIO control register bank.  <length> must equal 0x100.
     61    Register offsets:       0: SLCR: line control register
     62                            4: SLSR: line status register
     63                            8: SDICR: DMA/interrupt control register
     64                           12: SDISR: DMA/interrupt status register
     65                           16: SFCR: FIFO control register
     66 			  20: SBGR: baud rate control register
     67 			  32: transfer FIFO buffer
     68 			  48: transfer FIFO buffer
     69 
     70    backend {tcp | stdio}
     71 
     72    Use dv-sockser TCP-port backend or stdio for backend.  Default: stdio.
     73 
     74 
     75 
     76    PORTS
     77 
     78 
     79    int (output)
     80 
     81    Interrupt port.  An event is generated when a timer interrupt
     82    occurs.
     83 
     84 
     85    reset (input)
     86 
     87    Reset port.
     88 
     89    */
     90 
     91 
     92 
     93 /* static functions */
     94 
     95 struct tx3904sio_fifo;
     96 
     97 static void tx3904sio_tickle(struct hw*);
     98 static int tx3904sio_fifo_nonempty(struct hw*, struct tx3904sio_fifo*);
     99 static char tx3904sio_fifo_pop(struct hw*, struct tx3904sio_fifo*);
    100 static void tx3904sio_fifo_push(struct hw*, struct tx3904sio_fifo*, char);
    101 static void tx3904sio_fifo_reset(struct hw*, struct tx3904sio_fifo*);
    102 static void tx3904sio_poll(struct hw*, void* data);
    103 
    104 
    105 /* register numbers; each is one word long */
    106 enum
    107 {
    108   SLCR_REG = 0,
    109   SLSR_REG = 1,
    110   SDICR_REG = 2,
    111   SDISR_REG = 3,
    112   SFCR_REG = 4,
    113   SBGR_REG = 5,
    114   TFIFO_REG = 8,
    115   SFIFO_REG = 12,
    116 };
    117 
    118 
    119 
    120 /* port ID's */
    121 
    122 enum
    123  {
    124   RESET_PORT,
    125   INT_PORT,
    126 };
    127 
    128 
    129 static const struct hw_port_descriptor tx3904sio_ports[] =
    130 {
    131   { "int", INT_PORT, 0, output_port, },
    132   { "reset", RESET_PORT, 0, input_port, },
    133   { NULL, },
    134 };
    135 
    136 
    137 
    138 /* Generic FIFO */
    139 struct tx3904sio_fifo
    140 {
    141   int size, used;
    142   unsigned_1 *buffer;
    143 };
    144 
    145 
    146 
    147 /* The timer/counter register internal state.  Note that we store
    148    state using the control register images, in host endian order. */
    149 
    150 struct tx3904sio
    151 {
    152   address_word base_address; /* control register base */
    153   enum {sio_tcp, sio_stdio} backend; /* backend */
    154 
    155   struct tx3904sio_fifo rx_fifo, tx_fifo; /* FIFOs */
    156 
    157   unsigned_4 slcr;
    158 #define SLCR_WR_MASK        0xe17f0000U
    159 #define SLCR_SET_BYTE(c,o,b) ((c)->slcr = SLCR_WR_MASK & (((c)->slcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
    160   unsigned_4 slsr;
    161 #define SLSR_WR_MASK        0x00000000 /* UFER/UPER/UOER unimplemented */
    162   unsigned_4 sdicr;
    163 #define SDICR_WR_MASK       0x000f0000U
    164 #define SDICR_SET_BYTE(c,o,b) ((c)->sdicr = SDICR_WR_MASK & (((c)->sdicr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
    165 #define SDICR_GET_SDMAE(c)  ((c)->sdicr & 0x00080000)
    166 #define SDICR_GET_ERIE(c)   ((c)->sdicr & 0x00040000)
    167 #define SDICR_GET_TDIE(c)   ((c)->sdicr & 0x00020000)
    168 #define SDICR_GET_RDIE(c)   ((c)->sdicr & 0x00010000)
    169   unsigned_4 sdisr;
    170 #define SDISR_WR_MASK       0x00070000U
    171 #define SDISR_SET_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
    172 #define SDISR_CLEAR_FLAG_BYTE(c,o,b) ((c)->sdisr = SDISR_WR_MASK & (((c)->sdisr & ~LSMASK32((o)*8+7,(o)*8)) & ((b)<< (o)*8)))
    173 #define SDISR_GET_TDIS(c)   ((c)->sdisr & 0x00020000)
    174 #define SDISR_SET_TDIS(c)   ((c)->sdisr |= 0x00020000)
    175 #define SDISR_GET_RDIS(c)   ((c)->sdisr & 0x00010000)
    176 #define SDISR_SET_RDIS(c)   ((c)->sdisr |= 0x00010000)
    177   unsigned_4 sfcr;
    178 #define SFCR_WR_MASK       0x001f0000U
    179 #define SFCR_SET_BYTE(c,o,b) ((c)->sfcr = SFCR_WR_MASK & (((c)->sfcr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
    180 #define SFCR_GET_TFRST(c)   ((c)->sfcr & 0x00040000)
    181 #define SFCR_GET_RFRST(c)   ((c)->sfcr & 0x00020000)
    182 #define SFCR_GET_FRSTE(c)   ((c)->sfcr & 0x00010000)
    183   unsigned_4 sbgr;
    184 #define SBGR_WR_MASK       0x03ff0000U
    185 #define SBGR_SET_BYTE(c,o,b) ((c)->sbgr = SBGR_WR_MASK & (((c)->sbgr & ~LSMASK32((o)*8+7,(o)*8)) | ((b)<< (o)*8)))
    186 
    187   /* Periodic I/O polling */
    188   struct hw_event* poll_event;
    189 };
    190 
    191 
    192 
    193 /* Finish off the partially created hw device.  Attach our local
    194    callbacks.  Wire up our port names etc */
    195 
    196 static hw_io_read_buffer_method tx3904sio_io_read_buffer;
    197 static hw_io_write_buffer_method tx3904sio_io_write_buffer;
    198 static hw_port_event_method tx3904sio_port_event;
    199 
    200 
    201 static void
    202 attach_tx3904sio_regs (struct hw *me,
    203 		      struct tx3904sio *controller)
    204 {
    205   unsigned_word attach_address;
    206   int attach_space;
    207   unsigned attach_size;
    208   reg_property_spec reg;
    209 
    210   if (hw_find_property (me, "reg") == NULL)
    211     hw_abort (me, "Missing \"reg\" property");
    212 
    213   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    214     hw_abort (me, "\"reg\" property must contain one addr/size entry");
    215 
    216   hw_unit_address_to_attach_address (hw_parent (me),
    217 				     &reg.address,
    218 				     &attach_space,
    219 				     &attach_address,
    220 				     me);
    221   hw_unit_size_to_attach_size (hw_parent (me),
    222 			       &reg.size,
    223 			       &attach_size, me);
    224 
    225   hw_attach_address (hw_parent (me), 0,
    226 		     attach_space, attach_address, attach_size,
    227 		     me);
    228 
    229   if (hw_find_property(me, "backend") != NULL)
    230     {
    231       const char* value = hw_find_string_property(me, "backend");
    232       if (!strcmp(value, "tcp"))
    233 	controller->backend = sio_tcp;
    234       else if (!strcmp(value, "stdio"))
    235 	controller->backend = sio_stdio;
    236       else
    237 	hw_abort(me, "illegal value for backend parameter `%s': use tcp or stdio", value);
    238     }
    239 
    240   controller->base_address = attach_address;
    241 }
    242 
    243 
    244 static void
    245 tx3904sio_finish (struct hw *me)
    246 {
    247   struct tx3904sio *controller;
    248 
    249   controller = HW_ZALLOC (me, struct tx3904sio);
    250   set_hw_data (me, controller);
    251   set_hw_io_read_buffer (me, tx3904sio_io_read_buffer);
    252   set_hw_io_write_buffer (me, tx3904sio_io_write_buffer);
    253   set_hw_ports (me, tx3904sio_ports);
    254   set_hw_port_event (me, tx3904sio_port_event);
    255 
    256   /* Preset defaults */
    257   controller->backend = sio_stdio;
    258 
    259   /* Attach ourself to our parent bus */
    260   attach_tx3904sio_regs (me, controller);
    261 
    262   /* Initialize to reset state */
    263   tx3904sio_fifo_reset(me, & controller->rx_fifo);
    264   tx3904sio_fifo_reset(me, & controller->tx_fifo);
    265   controller->slsr = controller->sdicr
    266     = controller->sdisr = controller->sfcr
    267     = controller->sbgr = 0;
    268   controller->slcr = 0x40000000; /* set TWUB */
    269   controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
    270   controller->poll_event = NULL;
    271 }
    272 
    273 
    274 
    275 /* An event arrives on an interrupt port */
    276 
    277 static void
    278 tx3904sio_port_event (struct hw *me,
    279 		     int my_port,
    280 		     struct hw *source,
    281 		     int source_port,
    282 		     int level)
    283 {
    284   struct tx3904sio *controller = hw_data (me);
    285 
    286   switch (my_port)
    287     {
    288     case RESET_PORT:
    289       {
    290 	HW_TRACE ((me, "reset"));
    291 
    292 	tx3904sio_fifo_reset(me, & controller->rx_fifo);
    293 	tx3904sio_fifo_reset(me, & controller->tx_fifo);
    294 	controller->slsr = controller->sdicr
    295 	  = controller->sdisr = controller->sfcr
    296 	  = controller->sbgr = 0;
    297 	controller->slcr = 0x40000000; /* set TWUB */
    298 	controller->sbgr = 0x03ff0000; /* set BCLK=3, BRD=FF */
    299 	/* Don't interfere with I/O poller. */
    300 	break;
    301       }
    302 
    303     default:
    304       hw_abort (me, "Event on unknown port %d", my_port);
    305       break;
    306     }
    307 }
    308 
    309 
    310 /* generic read/write */
    311 
    312 static unsigned
    313 tx3904sio_io_read_buffer (struct hw *me,
    314 			 void *dest,
    315 			 int space,
    316 			 unsigned_word base,
    317 			 unsigned nr_bytes)
    318 {
    319   struct tx3904sio *controller = hw_data (me);
    320   unsigned byte;
    321 
    322   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
    323 
    324   /* tickle fifos */
    325   tx3904sio_tickle(me);
    326 
    327   for (byte = 0; byte < nr_bytes; byte++)
    328     {
    329       address_word address = base + byte;
    330       int reg_number = (address - controller->base_address) / 4;
    331       int reg_offset = (address - controller->base_address) % 4;
    332       unsigned_4 register_value; /* in target byte order */
    333 
    334       /* fill in entire register_value word */
    335       switch (reg_number)
    336 	{
    337 	case SLCR_REG: register_value = controller->slcr; break;
    338 	case SLSR_REG: register_value = controller->slsr; break;
    339 	case SDICR_REG: register_value = controller->sdicr; break;
    340 	case SDISR_REG: register_value = controller->sdisr; break;
    341 	case SFCR_REG: register_value = controller->sfcr; break;
    342 	case SBGR_REG: register_value = controller->sbgr; break;
    343 	case TFIFO_REG: register_value = 0; break;
    344 	case SFIFO_REG:
    345 	  /* consume rx fifo for MS byte */
    346 	  if (reg_offset == 0 && tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
    347 	    register_value = (tx3904sio_fifo_pop(me, & controller->rx_fifo) << 24);
    348 	  else
    349 	    register_value = 0;
    350 	  break;
    351 	default: register_value = 0;
    352 	}
    353 
    354       /* write requested byte out */
    355       register_value = H2T_4(register_value);
    356       /* HW_TRACE ((me, "byte %d %02x", reg_offset, ((char*)& register_value)[reg_offset])); */
    357       memcpy ((char*) dest + byte, ((char*)& register_value)+reg_offset, 1);
    358     }
    359 
    360   return nr_bytes;
    361 }
    362 
    363 
    364 
    365 static unsigned
    366 tx3904sio_io_write_buffer (struct hw *me,
    367 			  const void *source,
    368 			  int space,
    369 			  unsigned_word base,
    370 			  unsigned nr_bytes)
    371 {
    372   struct tx3904sio *controller = hw_data (me);
    373   unsigned byte;
    374 
    375   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
    376   for (byte = 0; byte < nr_bytes; byte++)
    377     {
    378       address_word address = base + byte;
    379       unsigned_1 write_byte = ((const unsigned char*) source)[byte];
    380       int reg_number = (address - controller->base_address) / 4;
    381       int reg_offset = 3 - (address - controller->base_address) % 4;
    382 
    383       /* HW_TRACE ((me, "byte %d %02x", reg_offset, write_byte)); */
    384 
    385       /* fill in entire register_value word */
    386       switch (reg_number)
    387 	{
    388 	case SLCR_REG:
    389 	  SLCR_SET_BYTE(controller, reg_offset, write_byte);
    390 	  break;
    391 
    392 	case SLSR_REG: /* unwriteable */ break;
    393 
    394 	case SDICR_REG:
    395 	  {
    396 	    unsigned_4 last_int, next_int;
    397 
    398 	    /* deassert interrupt upon clear */
    399 	    last_int = controller->sdisr & controller->sdicr;
    400 	    /* HW_TRACE ((me, "sdicr - sdisr %08x sdicr %08x",
    401 	       controller->sdisr, controller->sdicr)); */
    402 	    SDICR_SET_BYTE(controller, reg_offset, write_byte);
    403 	    /* HW_TRACE ((me, "sdicr + sdisr %08x sdicr %08x",
    404 	       controller->sdisr, controller->sdicr)); */
    405 	    next_int = controller->sdisr & controller->sdicr;
    406 
    407 	    if (SDICR_GET_SDMAE(controller))
    408 	      hw_abort(me, "Cannot support DMA-driven sio.");
    409 
    410 	    if (~last_int & next_int) /* any bits set? */
    411 	      hw_port_event(me, INT_PORT, 1);
    412 	    if (last_int & ~next_int) /* any bits cleared? */
    413 	      hw_port_event(me, INT_PORT, 0);
    414 	  }
    415 	break;
    416 
    417 	case SDISR_REG:
    418 	  {
    419 	    unsigned_4 last_int, next_int;
    420 
    421 	    /* deassert interrupt upon clear */
    422 	    last_int = controller->sdisr & controller->sdicr;
    423 	    /* HW_TRACE ((me, "sdisr - sdisr %08x sdicr %08x",
    424 	       controller->sdisr, controller->sdicr)); */
    425 	    SDISR_CLEAR_FLAG_BYTE(controller, reg_offset, write_byte);
    426 	    /* HW_TRACE ((me, "sdisr + sdisr %08x sdicr %08x",
    427 	       controller->sdisr, controller->sdicr)); */
    428 	    next_int = controller->sdisr & controller->sdicr;
    429 
    430 	    if (~last_int & next_int) /* any bits set? */
    431 	      hw_port_event(me, INT_PORT, 1);
    432 	    if (last_int & ~next_int) /* any bits cleared? */
    433 	      hw_port_event(me, INT_PORT, 0);
    434 	  }
    435 	break;
    436 
    437 	case SFCR_REG:
    438 	  SFCR_SET_BYTE(controller, reg_offset, write_byte);
    439 	  if (SFCR_GET_FRSTE(controller))
    440 	    {
    441 	      if (SFCR_GET_TFRST(controller)) tx3904sio_fifo_reset(me, & controller->tx_fifo);
    442 	      if (SFCR_GET_RFRST(controller)) tx3904sio_fifo_reset(me, & controller->rx_fifo);
    443 	    }
    444 	  break;
    445 
    446 	case SBGR_REG:
    447 	  SBGR_SET_BYTE(controller, reg_offset, write_byte);
    448 	  break;
    449 
    450 	case SFIFO_REG: /* unwriteable */ break;
    451 
    452 	case TFIFO_REG:
    453 	  if (reg_offset == 3) /* first byte */
    454 	    tx3904sio_fifo_push(me, & controller->tx_fifo, write_byte);
    455 	  break;
    456 
    457 	default:
    458 	  HW_TRACE ((me, "write to illegal register %d", reg_number));
    459 	}
    460     } /* loop over bytes */
    461 
    462   /* tickle fifos */
    463   tx3904sio_tickle(me);
    464 
    465   return nr_bytes;
    466 }
    467 
    468 
    469 
    470 
    471 
    472 
    473 /* Send enqueued characters from tx_fifo and trigger TX interrupt.
    474 Receive characters into rx_fifo and trigger RX interrupt. */
    475 void
    476 tx3904sio_tickle(struct hw *me)
    477 {
    478   struct tx3904sio* controller = hw_data(me);
    479   int c;
    480   char cc;
    481   unsigned_4 last_int, next_int;
    482 
    483   /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */
    484   switch (controller->backend)
    485     {
    486     case sio_tcp:
    487 
    488       while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
    489 	{
    490 	  cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
    491 	  dv_sockser_write(hw_system(me), cc);
    492 	  HW_TRACE ((me, "tcp output: %02x", cc));
    493 	}
    494 
    495       c = dv_sockser_read(hw_system(me));
    496       while(c != -1)
    497 	{
    498 	  cc = (char) c;
    499 	  HW_TRACE ((me, "tcp input: %02x", cc));
    500 	  tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
    501 	  c = dv_sockser_read(hw_system(me));
    502 	}
    503       break;
    504 
    505     case sio_stdio:
    506 
    507       while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
    508 	{
    509 	  cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
    510 	  sim_io_write_stdout(hw_system(me), & cc, 1);
    511 	  sim_io_flush_stdout(hw_system(me));
    512 	  HW_TRACE ((me, "stdio output: %02x", cc));
    513 	}
    514 
    515       c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
    516       while(c == 1)
    517 	{
    518 	  HW_TRACE ((me, "stdio input: %02x", cc));
    519 	  tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
    520 	  c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
    521 	}
    522 
    523       break;
    524 
    525     default:
    526       hw_abort(me, "Illegal backend mode: %d", controller->backend);
    527     }
    528 
    529   /* Update RDIS / TDIS flags */
    530   last_int = controller->sdisr & controller->sdicr;
    531   /* HW_TRACE ((me, "tickle - sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
    532   if (tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
    533     SDISR_SET_RDIS(controller);
    534   if (!tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
    535     SDISR_SET_TDIS(controller);
    536   next_int = controller->sdisr & controller->sdicr;
    537   /* HW_TRACE ((me, "tickle + sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
    538 
    539   if (~last_int & next_int) /* any bits set? */
    540     hw_port_event(me, INT_PORT, 1);
    541   if (last_int & ~next_int) /* any bits cleared? */
    542     hw_port_event(me, INT_PORT, 0);
    543 
    544   /* Add periodic polling for this port, if it's not already going. */
    545   if (controller->poll_event == NULL)
    546     {
    547       controller->poll_event = hw_event_queue_schedule (me, 1000,
    548 							tx3904sio_poll, NULL);
    549 
    550     }
    551 }
    552 
    553 
    554 
    555 
    556 int
    557 tx3904sio_fifo_nonempty(struct hw* me, struct tx3904sio_fifo* fifo)
    558 {
    559   /* HW_TRACE ((me, "fifo used: %d", fifo->used)); */
    560   return(fifo->used > 0);
    561 }
    562 
    563 
    564 char
    565 tx3904sio_fifo_pop(struct hw* me, struct tx3904sio_fifo* fifo)
    566 {
    567   char it;
    568   ASSERT(fifo->used > 0);
    569   ASSERT(fifo->buffer != NULL);
    570   it = fifo->buffer[0];
    571   memcpy(& fifo->buffer[0], & fifo->buffer[1], fifo->used - 1);
    572   fifo->used --;
    573   /* HW_TRACE ((me, "pop fifo -> %02x", it)); */
    574   return it;
    575 }
    576 
    577 
    578 void
    579 tx3904sio_fifo_push(struct hw* me, struct tx3904sio_fifo* fifo, char it)
    580 {
    581   /* HW_TRACE ((me, "push %02x -> fifo", it)); */
    582   if (fifo->size == fifo->used) /* full */
    583     {
    584       int next_size = fifo->size * 2 + 16;
    585       unsigned_1* next_buf = zalloc(next_size);
    586       memcpy(next_buf, fifo->buffer, fifo->used);
    587 
    588       if (fifo->buffer != NULL) free(fifo->buffer);
    589       fifo->buffer = next_buf;
    590       fifo->size = next_size;
    591     }
    592 
    593   fifo->buffer[fifo->used] = it;
    594   fifo->used ++;
    595 }
    596 
    597 
    598 void
    599 tx3904sio_fifo_reset(struct hw* me, struct tx3904sio_fifo* fifo)
    600 {
    601   /* HW_TRACE ((me, "reset fifo")); */
    602   fifo->used = 0;
    603   fifo->size = 0;
    604   free(fifo->buffer);
    605   fifo->buffer = 0;
    606 }
    607 
    608 
    609 void
    610 tx3904sio_poll(struct hw* me, void* ignored)
    611 {
    612   struct tx3904sio* controller = hw_data (me);
    613   tx3904sio_tickle (me);
    614   hw_event_queue_deschedule (me, controller->poll_event);
    615   controller->poll_event = hw_event_queue_schedule (me, 1000,
    616 						    tx3904sio_poll, NULL);
    617 }
    618 
    619 
    620 
    621 const struct hw_descriptor dv_tx3904sio_descriptor[] = {
    622   { "tx3904sio", tx3904sio_finish, },
    623   { NULL },
    624 };
    625