File indexing completed on 2025-05-11 08:24:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <stdlib.h>
0034
0035 #include <rtems/bspIo.h>
0036
0037 #include <bsp.h>
0038
0039 #include <libchip/ns16550.h>
0040 #include <libchip/ns16550_p.h>
0041
0042 #if defined(BSP_FEATURE_IRQ_EXTENSION)
0043 #include <bsp/irq.h>
0044 #elif defined(BSP_FEATURE_IRQ_LEGACY)
0045 #include <bsp/irq.h>
0046 #elif defined(__PPC__) || defined(__i386__)
0047 #include <bsp/irq.h>
0048 #define BSP_FEATURE_IRQ_LEGACY
0049 #ifdef BSP_SHARED_HANDLER_SUPPORT
0050 #define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
0051 #endif
0052 #endif
0053
0054 static uint32_t NS16550_GetBaudDivisor(ns16550_context *ctx, uint32_t baud)
0055 {
0056 uint32_t clock;
0057 uint32_t baudDivisor;
0058 uint32_t err;
0059 uint32_t actual;
0060 uint32_t newErr;
0061
0062 if (ctx->clock != 0) {
0063 clock = ctx->clock;
0064 } else {
0065 clock = 115200;
0066 }
0067
0068 baudDivisor = clock / (baud * 16);
0069
0070 if (ctx->has_precision_clock_synthesizer) {
0071 uint32_t i;
0072
0073 err = baud;
0074 baudDivisor = 0x0001ffff;
0075
0076 for (i = 2; i <= 0x10000; i *= 2) {
0077 uint32_t fout;
0078 uint32_t fin;
0079
0080 fin = i - 1;
0081 fout = (baud * fin * 16) / clock;
0082 actual = (clock * fout) / (16 * fin);
0083 newErr = actual > baud ? actual - baud : baud - actual;
0084
0085 if (newErr < err) {
0086 err = newErr;
0087 baudDivisor = fin | (fout << 16);
0088 }
0089 }
0090 } else if (ctx->has_fractional_divider_register) {
0091 uint32_t fractionalDivider = 0x10;
0092 uint32_t mulVal;
0093 uint32_t divAddVal;
0094
0095 err = baud;
0096 clock /= 16 * baudDivisor;
0097
0098 for (mulVal = 1; mulVal < 16; ++mulVal) {
0099 for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
0100 actual = (mulVal * clock) / (mulVal + divAddVal);
0101 newErr = actual > baud ? actual - baud : baud - actual;
0102
0103 if (newErr < err) {
0104 err = newErr;
0105 fractionalDivider = (mulVal << 4) | divAddVal;
0106 }
0107 }
0108 }
0109
0110 (*ctx->set_reg)(
0111 ctx->port,
0112 NS16550_FRACTIONAL_DIVIDER,
0113 fractionalDivider
0114 );
0115 } else if (ctx->calculate_baud_divisor != NULL) {
0116 baudDivisor = ctx->calculate_baud_divisor(ctx, baud);
0117 }
0118
0119 return baudDivisor;
0120 }
0121
0122
0123
0124
0125
0126
0127 static void ns16550_enable_interrupts(
0128 ns16550_context *ctx,
0129 int mask
0130 )
0131 {
0132 (*ctx->set_reg)(ctx->port, NS16550_INTERRUPT_ENABLE, mask);
0133 }
0134
0135 static void ns16550_clear_and_set_interrupts(
0136 ns16550_context *ctx,
0137 uint8_t clear,
0138 uint8_t set
0139 )
0140 {
0141 rtems_interrupt_lock_context lock_context;
0142 ns16550_get_reg get_reg = ctx->get_reg;
0143 ns16550_set_reg set_reg = ctx->set_reg;
0144 uintptr_t port = ctx->port;
0145 uint8_t val;
0146
0147 rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
0148 val = (*get_reg)(port, NS16550_INTERRUPT_ENABLE);
0149 val &= ~clear;
0150 val |= set;
0151 (*set_reg)(port, NS16550_INTERRUPT_ENABLE, val);
0152 rtems_termios_device_lock_release(&ctx->base, &lock_context);
0153 }
0154
0155
0156
0157
0158
0159 bool ns16550_probe(rtems_termios_device_context *base)
0160 {
0161 ns16550_context *ctx = (ns16550_context *) base;
0162 uintptr_t pNS16550;
0163 uint8_t ucDataByte;
0164 uint32_t ulBaudDivisor;
0165 ns16550_set_reg setReg;
0166 ns16550_get_reg getReg;
0167
0168 ctx->modem_control = SP_MODEM_IRQ;
0169
0170 pNS16550 = ctx->port;
0171 setReg = ctx->set_reg;
0172 getReg = ctx->get_reg;
0173
0174
0175
0176
0177
0178
0179 (*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
0180 ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR );
0181
0182
0183
0184 ulBaudDivisor = NS16550_GetBaudDivisor(ctx, ctx->initial_baud);
0185 ctx->baud_divisor = ulBaudDivisor;
0186 ucDataByte = SP_LINE_DLAB;
0187 (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
0188
0189
0190 (*setReg)(pNS16550,NS16550_DIVISOR_LATCH_L,(uint8_t)(ulBaudDivisor & 0xffU));
0191 (*setReg)(
0192 pNS16550,NS16550_DIVISOR_LATCH_M,
0193 (uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
0194 );
0195
0196
0197
0198 ucDataByte = EIGHT_BITS;
0199 ctx->line_control = ucDataByte;
0200
0201 if (ctx->has_precision_clock_synthesizer) {
0202 uint8_t fcr;
0203
0204
0205
0206
0207
0208 fcr = (*getReg)(pNS16550, NS16550_FIFO_CONTROL );
0209 fcr |= 0x10;
0210 (*setReg)(pNS16550, NS16550_FIFO_CONTROL, fcr);
0211
0212 (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 24));
0213 (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte );
0214 (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 16));
0215 } else {
0216 (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
0217 }
0218
0219
0220 ucDataByte = SP_FIFO_ENABLE;
0221 (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
0222
0223 ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
0224 (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
0225
0226 ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
0227
0228
0229
0230 (*setReg)(pNS16550, NS16550_MODEM_CONTROL,ctx->modem_control);
0231
0232 (*getReg)(pNS16550, NS16550_LINE_STATUS );
0233 (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER );
0234
0235 return true;
0236 }
0237
0238 static size_t ns16550_write_to_fifo(
0239 const ns16550_context *ctx,
0240 const char *buf,
0241 size_t len
0242 )
0243 {
0244 uintptr_t port = ctx->port;
0245 ns16550_set_reg set = ctx->set_reg;
0246 size_t out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
0247 size_t i;
0248
0249 for (i = 0; i < out; ++i) {
0250 (*set)(port, NS16550_TRANSMIT_BUFFER, buf[i]);
0251 }
0252
0253 return out;
0254 }
0255
0256
0257
0258
0259 static void ns16550_isr(void *arg)
0260 {
0261 rtems_termios_tty *tty = arg;
0262 ns16550_context *ctx = rtems_termios_get_device_context(tty);
0263 uintptr_t port = ctx->port;
0264 ns16550_get_reg get = ctx->get_reg;
0265 int i = 0;
0266 char buf [SP_FIFO_SIZE];
0267
0268
0269 do {
0270
0271 for (i = 0; i < SP_FIFO_SIZE; ++i) {
0272 if ((get( port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
0273 buf [i] = (char) get(port, NS16550_RECEIVE_BUFFER);
0274 } else {
0275 break;
0276 }
0277 }
0278
0279
0280 rtems_termios_enqueue_raw_characters(tty, buf, i);
0281
0282
0283 if (ctx->out_total > 0
0284 && (get(port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
0285 size_t current = ctx->out_current;
0286
0287 ctx->out_buf += current;
0288 ctx->out_remaining -= current;
0289
0290 if (ctx->out_remaining > 0) {
0291 ctx->out_current =
0292 ns16550_write_to_fifo(ctx, ctx->out_buf, ctx->out_remaining);
0293 } else {
0294 rtems_termios_dequeue_characters(tty, ctx->out_total);
0295 }
0296 }
0297 } while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
0298 }
0299
0300 static void ns16550_isr_task(void *arg)
0301 {
0302 rtems_termios_tty *tty = arg;
0303 ns16550_context *ctx = rtems_termios_get_device_context(tty);
0304 uint8_t status = (*ctx->get_reg)(ctx->port, NS16550_LINE_STATUS);
0305
0306 if ((status & SP_LSR_RDY) != 0) {
0307 ns16550_clear_and_set_interrupts(ctx, SP_INT_RX_ENABLE, 0);
0308 rtems_termios_rxirq_occured(tty);
0309 }
0310
0311 if (ctx->out_total > 0 && (status & SP_LSR_THOLD) != 0) {
0312 size_t current = ctx->out_current;
0313
0314 ctx->out_buf += current;
0315 ctx->out_remaining -= current;
0316
0317 if (ctx->out_remaining > 0) {
0318 ctx->out_current =
0319 ns16550_write_to_fifo(ctx, ctx->out_buf, ctx->out_remaining);
0320 } else {
0321 size_t done = ctx->out_total;
0322
0323 ctx->out_total = 0;
0324 ns16550_clear_and_set_interrupts(ctx, SP_INT_TX_ENABLE, 0);
0325 rtems_termios_dequeue_characters(tty, done);
0326 }
0327 }
0328 }
0329
0330 static int ns16550_read_task(rtems_termios_device_context *base)
0331 {
0332 ns16550_context *ctx = (ns16550_context *) base;
0333 uintptr_t port = ctx->port;
0334 ns16550_get_reg get = ctx->get_reg;
0335 char buf[SP_FIFO_SIZE];
0336 int i;
0337
0338 for (i = 0; i < SP_FIFO_SIZE; ++i) {
0339 if ((get(port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
0340 buf[i] = (char) get(port, NS16550_RECEIVE_BUFFER);
0341 } else {
0342 break;
0343 }
0344 }
0345
0346 rtems_termios_enqueue_raw_characters(ctx->tty, buf, i);
0347 ns16550_clear_and_set_interrupts(ctx, 0, SP_INT_RX_ENABLE);
0348
0349 return -1;
0350 }
0351
0352
0353
0354
0355
0356
0357 static void ns16550_initialize_interrupts(
0358 struct rtems_termios_tty *tty,
0359 ns16550_context *ctx,
0360 void (*isr)(void *)
0361 )
0362 {
0363 #ifdef BSP_FEATURE_IRQ_EXTENSION
0364 {
0365 rtems_status_code sc = RTEMS_SUCCESSFUL;
0366 sc = rtems_interrupt_handler_install(
0367 ctx->irq,
0368 "NS16550",
0369 RTEMS_INTERRUPT_SHARED,
0370 isr,
0371 tty
0372 );
0373 if (sc != RTEMS_SUCCESSFUL) {
0374
0375 printk( "%s: Error: Install interrupt handler\n", __func__);
0376 rtems_fatal_error_occurred( 0xdeadbeef);
0377 }
0378 }
0379 #elif defined(BSP_FEATURE_IRQ_LEGACY)
0380 {
0381 int rv = 0;
0382 #ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
0383 rtems_irq_connect_data cd = {
0384 ctx->irq,
0385 isr,
0386 tty,
0387 NULL,
0388 NULL,
0389 NULL,
0390 NULL
0391 };
0392 rv = BSP_install_rtems_shared_irq_handler( &cd);
0393 #else
0394 rtems_irq_connect_data cd = {
0395 ctx->irq,
0396 isr,
0397 tty,
0398 NULL,
0399 NULL,
0400 NULL
0401 };
0402 rv = BSP_install_rtems_irq_handler( &cd);
0403 #endif
0404 if (rv == 0) {
0405
0406 printk( "%s: Error: Install interrupt handler\n", __func__);
0407 rtems_fatal_error_occurred( 0xdeadbeef);
0408 }
0409 }
0410 #endif
0411 }
0412
0413
0414
0415
0416
0417 static bool ns16550_open(
0418 struct rtems_termios_tty *tty,
0419 rtems_termios_device_context *base,
0420 struct termios *term,
0421 rtems_libio_open_close_args_t *args
0422 )
0423 {
0424 ns16550_context *ctx = (ns16550_context *) base;
0425
0426 ctx->tty = tty;
0427
0428
0429 rtems_termios_set_initial_baud(tty, ctx->initial_baud);
0430
0431 if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
0432 ns16550_initialize_interrupts(tty, ctx, ns16550_isr);
0433 ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
0434 } else if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
0435 ns16550_initialize_interrupts(tty, ctx, ns16550_isr_task);
0436 ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
0437 }
0438
0439 return true;
0440 }
0441
0442 static void ns16550_cleanup_interrupts(
0443 struct rtems_termios_tty *tty,
0444 ns16550_context *ctx,
0445 void (*isr)(void *)
0446 )
0447 {
0448 #if defined(BSP_FEATURE_IRQ_EXTENSION)
0449 rtems_status_code sc = RTEMS_SUCCESSFUL;
0450 sc = rtems_interrupt_handler_remove(
0451 ctx->irq,
0452 isr,
0453 tty
0454 );
0455 if (sc != RTEMS_SUCCESSFUL) {
0456
0457 printk("%s: Error: Remove interrupt handler\n", __func__);
0458 rtems_fatal_error_occurred(0xdeadbeef);
0459 }
0460 #elif defined(BSP_FEATURE_IRQ_LEGACY)
0461 int rv = 0;
0462 rtems_irq_connect_data cd = {
0463 .name = ctx->irq,
0464 .hdl = isr,
0465 .handle = tty
0466 };
0467 rv = BSP_remove_rtems_irq_handler(&cd);
0468 if (rv == 0) {
0469
0470 printk("%s: Error: Remove interrupt handler\n", __func__);
0471 rtems_fatal_error_occurred(0xdeadbeef);
0472 }
0473 #endif
0474 }
0475
0476
0477
0478
0479
0480 static void ns16550_close(
0481 struct rtems_termios_tty *tty,
0482 rtems_termios_device_context *base,
0483 rtems_libio_open_close_args_t *args
0484 )
0485 {
0486 ns16550_context *ctx = (ns16550_context *) base;
0487
0488 ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
0489
0490 if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
0491 ns16550_cleanup_interrupts(tty, ctx, ns16550_isr);
0492 } else if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
0493 ns16550_cleanup_interrupts(tty, ctx, ns16550_isr_task);
0494 }
0495 }
0496
0497
0498
0499
0500 void ns16550_polled_putchar(rtems_termios_device_context *base, char out)
0501 {
0502 ns16550_context *ctx = (ns16550_context *) base;
0503 uintptr_t port = ctx->port;
0504 ns16550_get_reg get = ctx->get_reg;
0505 ns16550_set_reg set = ctx->set_reg;
0506 uint32_t status = 0;
0507 rtems_interrupt_lock_context lock_context;
0508
0509
0510 uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
0511
0512
0513 ns16550_enable_interrupts(ctx, NS16550_DISABLE_ALL_INTR);
0514
0515 while (true) {
0516
0517 rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
0518
0519
0520 status = get( port, NS16550_LINE_STATUS);
0521 if ((status & SP_LSR_THOLD) != 0) {
0522
0523 set( port, NS16550_TRANSMIT_BUFFER, out);
0524
0525
0526 rtems_termios_device_lock_release(&ctx->base, &lock_context);
0527 break;
0528 } else {
0529 rtems_termios_device_lock_release(&ctx->base, &lock_context);
0530 }
0531
0532
0533 do {
0534 status = get( port, NS16550_LINE_STATUS);
0535 } while ((status & SP_LSR_THOLD) == 0);
0536 }
0537
0538
0539 set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
0540 }
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550 static void ns16550_assert_RTS(rtems_termios_device_context *base)
0551 {
0552 ns16550_context *ctx = (ns16550_context *) base;
0553 rtems_interrupt_lock_context lock_context;
0554
0555
0556
0557
0558 rtems_termios_device_lock_acquire(base, &lock_context);
0559 ctx->modem_control |= SP_MODEM_RTS;
0560 (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
0561 rtems_termios_device_lock_release(base, &lock_context);
0562 }
0563
0564
0565
0566
0567
0568 static void ns16550_negate_RTS(rtems_termios_device_context *base)
0569 {
0570 ns16550_context *ctx = (ns16550_context *) base;
0571 rtems_interrupt_lock_context lock_context;
0572
0573
0574
0575
0576 rtems_termios_device_lock_acquire(base, &lock_context);
0577 ctx->modem_control &= ~SP_MODEM_RTS;
0578 (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
0579 rtems_termios_device_lock_release(base, &lock_context);
0580 }
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 static void ns16550_assert_DTR(rtems_termios_device_context *base)
0592 {
0593 ns16550_context *ctx = (ns16550_context *) base;
0594 rtems_interrupt_lock_context lock_context;
0595
0596
0597
0598
0599 rtems_termios_device_lock_acquire(base, &lock_context);
0600 ctx->modem_control |= SP_MODEM_DTR;
0601 (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL, ctx->modem_control);
0602 rtems_termios_device_lock_release(base, &lock_context);
0603 }
0604
0605
0606
0607
0608
0609 static void ns16550_negate_DTR(rtems_termios_device_context *base)
0610 {
0611 ns16550_context *ctx = (ns16550_context *) base;
0612 rtems_interrupt_lock_context lock_context;
0613
0614
0615
0616
0617 rtems_termios_device_lock_acquire(base, &lock_context);
0618 ctx->modem_control &=~SP_MODEM_DTR;
0619 (*ctx->set_reg)(ctx->port, NS16550_MODEM_CONTROL,ctx->modem_control);
0620 rtems_termios_device_lock_release(base, &lock_context);
0621 }
0622
0623
0624
0625
0626
0627
0628
0629
0630 static bool ns16550_set_attributes(
0631 rtems_termios_device_context *base,
0632 const struct termios *t
0633 )
0634 {
0635 ns16550_context *ctx = (ns16550_context *) base;
0636 uint32_t pNS16550;
0637 uint32_t ulBaudDivisor;
0638 uint8_t ucLineControl;
0639 uint32_t baud_requested;
0640 ns16550_set_reg setReg;
0641
0642 pNS16550 = ctx->port;
0643 setReg = ctx->set_reg;
0644
0645
0646
0647
0648
0649
0650
0651 baud_requested = rtems_termios_baud_to_number(t->c_ospeed);
0652 _Assert( baud_requested != 0 );
0653
0654 ulBaudDivisor = NS16550_GetBaudDivisor(ctx, baud_requested);
0655
0656 ucLineControl = 0;
0657
0658
0659
0660
0661
0662 if (t->c_cflag & PARENB) {
0663 ucLineControl |= SP_LINE_PAR;
0664 if (!(t->c_cflag & PARODD))
0665 ucLineControl |= SP_LINE_ODD;
0666 }
0667
0668
0669
0670
0671
0672 if (t->c_cflag & CSIZE) {
0673 switch (t->c_cflag & CSIZE) {
0674 case CS5: ucLineControl |= FIVE_BITS; break;
0675 case CS6: ucLineControl |= SIX_BITS; break;
0676 case CS7: ucLineControl |= SEVEN_BITS; break;
0677 case CS8: ucLineControl |= EIGHT_BITS; break;
0678 }
0679 } else {
0680 ucLineControl |= EIGHT_BITS;
0681 }
0682
0683
0684
0685
0686
0687 if (t->c_cflag & CSTOPB) {
0688 ucLineControl |= SP_LINE_STOP;
0689 } else {
0690 ;
0691 }
0692
0693
0694
0695
0696
0697 if (ulBaudDivisor != ctx->baud_divisor || ucLineControl != ctx->line_control) {
0698 rtems_interrupt_lock_context lock_context;
0699
0700 ctx->baud_divisor = ulBaudDivisor;
0701 ctx->line_control = ucLineControl;
0702
0703 rtems_termios_device_lock_acquire(base, &lock_context);
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713 (*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
0714 (*setReg)(pNS16550, NS16550_DIVISOR_LATCH_L, ulBaudDivisor&0xff);
0715 (*setReg)(pNS16550, NS16550_DIVISOR_LATCH_M, (ulBaudDivisor>>8)&0xff);
0716
0717
0718
0719
0720 if (ctx->has_precision_clock_synthesizer) {
0721 (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 24));
0722 (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
0723 (*setReg)(pNS16550, NS16550_SCRATCH_PAD, (uint8_t)(ulBaudDivisor >> 16));
0724 } else {
0725 (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
0726 }
0727
0728 rtems_termios_device_lock_release(base, &lock_context);
0729 }
0730
0731 return true;
0732 }
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743 static void ns16550_write_support_int(
0744 rtems_termios_device_context *base,
0745 const char *buf,
0746 size_t len
0747 )
0748 {
0749 ns16550_context *ctx = (ns16550_context *) base;
0750
0751 ctx->out_total = len;
0752
0753 if (len > 0) {
0754 ctx->out_remaining = len;
0755 ctx->out_buf = buf;
0756 ctx->out_current = ns16550_write_to_fifo(ctx, buf, len);
0757
0758 ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR);
0759 } else {
0760 ns16550_enable_interrupts(ctx, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
0761 }
0762 }
0763
0764 static void ns16550_write_support_task(
0765 rtems_termios_device_context *base,
0766 const char *buf,
0767 size_t len
0768 )
0769 {
0770 ns16550_context *ctx = (ns16550_context *) base;
0771
0772 ctx->out_total = len;
0773
0774 if (len > 0) {
0775 ctx->out_remaining = len;
0776 ctx->out_buf = buf;
0777 ctx->out_current = ns16550_write_to_fifo(ctx, buf, len);
0778
0779 ns16550_clear_and_set_interrupts(ctx, 0, SP_INT_TX_ENABLE);
0780 }
0781 }
0782
0783
0784
0785
0786
0787
0788
0789
0790 static void ns16550_write_support_polled(
0791 rtems_termios_device_context *base,
0792 const char *buf,
0793 size_t len
0794 )
0795 {
0796 size_t nwrite = 0;
0797
0798
0799
0800
0801 while (nwrite < len) {
0802
0803
0804
0805 ns16550_polled_putchar(base, *buf++);
0806 nwrite++;
0807 }
0808 }
0809
0810
0811
0812
0813 int ns16550_polled_getchar(rtems_termios_device_context *base)
0814 {
0815 ns16550_context *ctx = (ns16550_context *) base;
0816 uint32_t pNS16550;
0817 unsigned char ucLineStatus;
0818 uint8_t cChar;
0819 ns16550_get_reg getReg;
0820
0821 pNS16550 = ctx->port;
0822 getReg = ctx->get_reg;
0823
0824 ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
0825 if (ucLineStatus & SP_LSR_RDY) {
0826 cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
0827 return (int)cChar;
0828 }
0829 return -1;
0830 }
0831
0832
0833
0834
0835
0836 const rtems_termios_device_flow ns16550_flow_rtscts = {
0837 .stop_remote_tx = ns16550_negate_RTS,
0838 .start_remote_tx = ns16550_assert_RTS
0839 };
0840
0841 const rtems_termios_device_flow ns16550_flow_dtrcts = {
0842 .stop_remote_tx = ns16550_negate_DTR,
0843 .start_remote_tx = ns16550_assert_DTR
0844 };
0845
0846 const rtems_termios_device_handler ns16550_handler_interrupt = {
0847 .first_open = ns16550_open,
0848 .last_close = ns16550_close,
0849 .poll_read = NULL,
0850 .write = ns16550_write_support_int,
0851 .set_attributes = ns16550_set_attributes,
0852 .mode = TERMIOS_IRQ_DRIVEN
0853 };
0854
0855 const rtems_termios_device_handler ns16550_handler_polled = {
0856 .first_open = ns16550_open,
0857 .last_close = ns16550_close,
0858 .poll_read = ns16550_polled_getchar,
0859 .write = ns16550_write_support_polled,
0860 .set_attributes = ns16550_set_attributes,
0861 .mode = TERMIOS_POLLED
0862 };
0863
0864 const rtems_termios_device_handler ns16550_handler_task = {
0865 .first_open = ns16550_open,
0866 .last_close = ns16550_close,
0867 .poll_read = ns16550_read_task,
0868 .write = ns16550_write_support_task,
0869 .set_attributes = ns16550_set_attributes,
0870 .mode = TERMIOS_TASK_DRIVEN
0871 };