File indexing completed on 2025-05-11 08:23:04
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
0034
0035
0036 #include <bsp.h>
0037 #include <bsp/lpc32xx.h>
0038 #include <bsp/irq.h>
0039 #include <bsp/hsu.h>
0040
0041 #define HSU_FIFO_SIZE 64
0042
0043 #define HSU_LEVEL_RX_MASK 0xffU
0044 #define HSU_LEVEL_TX_MASK 0xff00U
0045 #define HSU_LEVEL_TX_SHIFT 8
0046
0047 #define HSU_RX_DATA_MASK 0xffU
0048 #define HSU_RX_EMPTY (1U << 8)
0049 #define HSU_RX_ERROR (1U << 9)
0050 #define HSU_RX_BREAK (1U << 10)
0051
0052 #define HSU_IIR_TX (1U << 0)
0053 #define HSU_IIR_RX_TRIG (1U << 1)
0054 #define HSU_IIR_RX_TIMEOUT (1U << 2)
0055
0056 #define HSU_CTRL_INTR_DISABLED 0x1280fU
0057 #define HSU_CTRL_RX_INTR_ENABLED 0x1284fU
0058 #define HSU_CTRL_RX_AND_TX_INTR_ENABLED 0x1286fU
0059
0060
0061 #define HSU_IIR_MASK 0x7U
0062
0063 bool lpc32xx_hsu_probe(rtems_termios_device_context *base)
0064 {
0065 lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
0066 volatile lpc32xx_hsu *hsu = ctx->hsu;
0067
0068 hsu->ctrl = HSU_CTRL_INTR_DISABLED;
0069
0070
0071 while (hsu->level != 0) {
0072 hsu->fifo;
0073 }
0074
0075 return true;
0076 }
0077
0078 static void lpc32xx_hsu_interrupt_handler(void *arg)
0079 {
0080 rtems_termios_tty *tty = arg;
0081 lpc32xx_hsu_context *ctx = rtems_termios_get_device_context(tty);
0082 volatile lpc32xx_hsu *hsu = ctx->hsu;
0083
0084
0085 do {
0086 int rv = 0;
0087 int i = 0;
0088 char buf [HSU_FIFO_SIZE];
0089
0090
0091 while (i < HSU_FIFO_SIZE) {
0092 uint32_t in = hsu->fifo;
0093
0094 if ((in & HSU_RX_EMPTY) == 0) {
0095 if ((in & HSU_RX_BREAK) == 0) {
0096 buf [i] = in & HSU_RX_DATA_MASK;
0097 ++i;
0098 }
0099 } else {
0100 break;
0101 }
0102 }
0103 rtems_termios_enqueue_raw_characters(tty, buf, i);
0104
0105
0106 rv = rtems_termios_dequeue_characters(tty, (int) ctx->chars_in_transmission);
0107 if (rv == 0) {
0108
0109 }
0110 } while ((hsu->iir & HSU_IIR_MASK) != 0);
0111 }
0112
0113 static bool lpc32xx_hsu_first_open(
0114 struct rtems_termios_tty *tty,
0115 rtems_termios_device_context *base,
0116 struct termios *term,
0117 rtems_libio_open_close_args_t *args
0118 )
0119 {
0120 lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
0121 volatile lpc32xx_hsu *hsu = ctx->hsu;
0122 rtems_status_code sc;
0123 bool ok;
0124
0125 sc = rtems_interrupt_handler_install(
0126 ctx->irq,
0127 "HSU",
0128 RTEMS_INTERRUPT_UNIQUE,
0129 lpc32xx_hsu_interrupt_handler,
0130 tty
0131 );
0132 ok = sc == RTEMS_SUCCESSFUL;
0133
0134 if (ok) {
0135 rtems_termios_set_initial_baud(tty, ctx->initial_baud);
0136 hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED;
0137 }
0138
0139 return ok;
0140 }
0141
0142 static void lpc32xx_hsu_last_close(
0143 struct rtems_termios_tty *tty,
0144 rtems_termios_device_context *base,
0145 rtems_libio_open_close_args_t *args
0146 )
0147 {
0148 lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
0149 volatile lpc32xx_hsu *hsu = ctx->hsu;
0150
0151 hsu->ctrl = HSU_CTRL_INTR_DISABLED;
0152
0153 rtems_interrupt_handler_remove(
0154 ctx->irq,
0155 lpc32xx_hsu_interrupt_handler,
0156 tty
0157 );
0158 }
0159
0160 static void lpc32xx_hsu_write(
0161 rtems_termios_device_context *base,
0162 const char *buf,
0163 size_t len
0164 )
0165 {
0166 lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
0167 volatile lpc32xx_hsu *hsu = ctx->hsu;
0168 size_t tx_level = (hsu->level & HSU_LEVEL_TX_MASK) >> HSU_LEVEL_TX_SHIFT;
0169 size_t tx_free = HSU_FIFO_SIZE - tx_level;
0170 size_t i = 0;
0171 size_t out = len > tx_free ? tx_free : len;
0172
0173 for (i = 0; i < out; ++i) {
0174 hsu->fifo = buf [i];
0175 }
0176
0177 ctx->chars_in_transmission = out;
0178
0179 if (len > 0) {
0180 hsu->ctrl = HSU_CTRL_RX_AND_TX_INTR_ENABLED;
0181 } else {
0182 hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED;
0183 hsu->iir = HSU_IIR_TX;
0184 }
0185 }
0186
0187 static bool lpc32xx_hsu_set_attributes(
0188 rtems_termios_device_context *base,
0189 const struct termios *term
0190 )
0191 {
0192 lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
0193 volatile lpc32xx_hsu *hsu = ctx->hsu;
0194 int baud_flags = term->c_ospeed;
0195
0196 if (baud_flags != 0) {
0197 int32_t baud = rtems_termios_baud_to_number(baud_flags);
0198
0199 if (baud > 0) {
0200 uint32_t baud_divisor = 14 * (uint32_t) baud;
0201 uint32_t rate = LPC32XX_PERIPH_CLK / baud_divisor;
0202 uint32_t remainder = LPC32XX_PERIPH_CLK - rate * baud_divisor;
0203
0204 if (2 * remainder >= baud_divisor) {
0205 ++rate;
0206 }
0207
0208 hsu->rate = rate - 1;
0209 }
0210 }
0211
0212 return true;
0213 }
0214
0215 const rtems_termios_device_handler lpc32xx_hsu_fns = {
0216 .first_open = lpc32xx_hsu_first_open,
0217 .last_close = lpc32xx_hsu_last_close,
0218 .write = lpc32xx_hsu_write,
0219 .set_attributes = lpc32xx_hsu_set_attributes,
0220 .mode = TERMIOS_IRQ_DRIVEN
0221 };