On Mon, Mar 07, 2022 at 07:36:35AM +0000, Visa Hankala wrote: > On Wed, Mar 02, 2022 at 07:25:36AM +0100, Anton Lindqvist wrote: > > On Tue, Mar 01, 2022 at 01:41:10PM +0000, Visa Hankala wrote: > > > On Tue, Mar 01, 2022 at 07:08:51AM +0100, Anton Lindqvist wrote: > > > > On Sun, Feb 27, 2022 at 05:33:17PM +0100, Mark Kettenis wrote: > > > > > > Date: Sun, 27 Feb 2022 16:01:25 +0100 > > > > > > From: Anton Lindqvist <an...@basename.se> > > > > > > > > > > > > > > > r1p5 is revision 3 with a 32 bytes FIFO. My only concern is that the > > > > > > following registers which this diff makes use of are not enumerated > > > > > > in > > > > > > the "Base UART Register Set" listing: > > > > > > > > > > > > 1. UARTPeriphID2 - used to deduce the revision > > > > > > 2. UARTIFLS - interrupt FIFO level select register > > > > > > > > > > Right. So you can't really use those registers, at least not > > > > > unconditionally. > > > > > > > > > > What we could do is add a flag to the softc to indicate that we're > > > > > dealing with an SBSA UART instead of a genuine PL011 UART. This would > > > > > skip reading the UARTPeriphID2 (assuming r1p5 properties) and skip > > > > > touching UARTIFLS (and perhaps some other potentially unimplemented > > > > > registers). > > > > > > > > > > We would set this flag based on the compatible string in pluart_fdt.c > > > > > and based on the _HID (or maybe even unconditionally) in > > > > > pluart_acpi.c. > > > > > > > > Here's a first stab at handling such devices. Attaching over ACPI also > > > > keeps the FIFO disabled. > > > > > > > > diff --git sys/dev/fdt/pluart_fdt.c sys/dev/fdt/pluart_fdt.c > > > > index 7f17365f1d6..45e31f9872f 100644 > > > > --- sys/dev/fdt/pluart_fdt.c > > > > +++ sys/dev/fdt/pluart_fdt.c > > > > @@ -69,6 +69,16 @@ pluart_fdt_attach(struct device *parent, struct > > > > device *self, void *aux) > > > > return; > > > > } > > > > > > > > + /* > > > > + * The SBSA UART is PL011 r1p5 compliant which implies revision > > > > 3 with a > > > > + * 32 byte FIFO. However, we cannot expect to configure RX/TX > > > > interrupt > > > > + * levels using the UARTIFLS register making it impossible to > > > > make > > > > + * assumptions about the number of available bytes in the FIFO. > > > > + * Therefore disable FIFO support for such devices. > > > > + */ > > > > + if (!OF_is_compatible(faa->fa_node, "arm,sbsa-uart")) > > > > + sc->sc_hwflags |= COM_HW_FIFO; > > > > + > > > > > > Could this piece of code use a dedicated flag, say COM_HW_SBSA (or > > > inversely COM_HW_PL011), that tells that the UART is an SBSA UART (or > > > true PL011 UART). > > > > > > To me, this use of the COM_HW_FIFO is a bit obscure; you need to look > > > at the comment in pluart_fdt_attach() to understand the logic. > > > > New diff replacing usage of COM_HW_FIFO with COM_HW_SBSA. > > > > > Is worrying about the exact size of the FIFO really worthwhile? As I > > > suggested earlier, pluart_start() could check the TXFF flag in the > > > Flag Register before feeding each byte to the FIFO. This would allow > > > the same transmit code apply to both SBSA and true PL011 UARTs. > > > > > > The SBSA UART interface does not have the IFLS register. However, it > > > looks that the FIFO and the interrupt are usable nevertheless. At least > > > Linux appears to enable them. > > > > I did look at Linux as well. They do not initialize the ifls field for > > SBSA devices causing 0 to be written to the UARTIFLS register which > > implies an interrupt level of 1/8 for both RX and TX. However, it's > > still unknown whenever this have any effect or not. > > I think the Linux driver does not use ifls when setting up > the SBSA UART. Compare pl011_startup() and sbsa_uart_startup() on Linux. > > > diff --git sys/dev/acpi/pluart_acpi.c sys/dev/acpi/pluart_acpi.c > > index dc8ea5e9922..08ebe13ffbc 100644 > > --- sys/dev/acpi/pluart_acpi.c > > +++ sys/dev/acpi/pluart_acpi.c > > @@ -91,6 +91,8 @@ pluart_acpi_attach(struct device *parent, struct device > > *self, void *aux) > > return; > > } > > > > + sc->sc.sc_hwflags |= COM_HW_SBSA; > > + > > pluart_attach_common(&sc->sc, pluart_acpi_is_console(sc)); > > } > > > > diff --git sys/dev/fdt/pluart_fdt.c sys/dev/fdt/pluart_fdt.c > > index 7f17365f1d6..798250593bf 100644 > > --- sys/dev/fdt/pluart_fdt.c > > +++ sys/dev/fdt/pluart_fdt.c > > @@ -69,6 +69,9 @@ pluart_fdt_attach(struct device *parent, struct device > > *self, void *aux) > > return; > > } > > > > + if (OF_is_compatible(faa->fa_node, "arm,sbsa-uart")) > > + sc->sc_hwflags |= COM_HW_SBSA; > > + > > sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY, pluart_intr, > > sc, sc->sc_dev.dv_xname); > > > > diff --git sys/dev/ic/pluart.c sys/dev/ic/pluart.c > > index eaa11b6c44b..61233290e0d 100644 > > --- sys/dev/ic/pluart.c > > +++ sys/dev/ic/pluart.c > > @@ -99,6 +99,13 @@ > > #define UART_CR_CTSE (1 << 14) /* CTS hardware flow > > control enable */ > > #define UART_CR_RTSE (1 << 15) /* RTS hardware flow > > control enable */ > > #define UART_IFLS 0x34 /* Interrupt FIFO level select > > register */ > > +#define UART_IFLS_RX_SHIFT 3 /* RX level in bits [5:3] */ > > +#define UART_IFLS_TX_SHIFT 0 /* TX level in bits [2:0] */ > > +#define UART_IFLS_1_8 0 /* FIFO 1/8 full */ > > +#define UART_IFLS_1_4 1 /* FIFO 1/4 full */ > > +#define UART_IFLS_1_2 2 /* FIFO 1/2 full */ > > +#define UART_IFLS_3_4 3 /* FIFO 3/4 full */ > > +#define UART_IFLS_7_8 4 /* FIFO 7/8 full */ > > #define UART_IMSC 0x38 /* Interrupt mask set/clear > > register */ > > #define UART_IMSC_RIMIM (1 << 0) > > #define UART_IMSC_CTSMIM (1 << 1) > > @@ -115,8 +122,16 @@ > > #define UART_MIS 0x40 /* Masked interrupt status > > register */ > > #define UART_ICR 0x44 /* Interrupt clear register */ > > #define UART_DMACR 0x48 /* DMA control register */ > > +#define UART_PID0 0xfe0 /* Peripheral identification > > register 0 */ > > +#define UART_PID1 0xfe4 /* Peripheral identification > > register 1 */ > > +#define UART_PID2 0xfe8 /* Peripheral identification > > register 2 */ > > +#define UART_PID2_REV(x) (((x) & 0xf0) >> 4) > > +#define UART_PID3 0xfec /* Peripheral identification > > register 3 */ > > #define UART_SPACE 0x100 > > > > +#define UART_FIFO_SIZE 16 > > +#define UART_FIFO_SIZE_R3 32 > > + > > void pluartcnprobe(struct consdev *cp); > > void pluartcninit(struct consdev *cp); > > int pluartcngetc(dev_t dev); > > @@ -150,7 +165,31 @@ struct cdevsw pluartdev = > > void > > pluart_attach_common(struct pluart_softc *sc, int console) > > { > > - int maj; > > + int fifolen, maj; > > + int lcr; > > + > > + if ((sc->sc_hwflags & COM_HW_SBSA) == 0) { > > + int rev; > > + > > + rev = UART_PID2_REV(bus_space_read_4(sc->sc_iot, sc->sc_ioh, > > + UART_PID2)); > > + if (rev < 3) > > + fifolen = UART_FIFO_SIZE; > > + else > > + fifolen = UART_FIFO_SIZE_R3; > > + printf(": rev %d, %d byte fifo\n", rev, fifolen); > > + } else { > > + /* > > + * The SBSA UART is PL011 r1p5 compliant which implies revision > > + * 3 with a 32 byte FIFO. However, we cannot expect to configure > > + * RX/TX interrupt levels using the UARTIFLS register making it > > + * impossible to make assumptions about the number of available > > + * bytes in the FIFO. Therefore disable FIFO support for such > > + * devices. > > + */ > > + fifolen = 0; > > + printf("\n"); > > + } > > > > if (console) { > > /* Locate the major number. */ > > @@ -159,7 +198,7 @@ pluart_attach_common(struct pluart_softc *sc, int > > console) > > break; > > cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); > > > > - printf(": console"); > > + printf("%s: console\n", sc->sc_dev.dv_xname); > > SET(sc->sc_hwflags, COM_HW_CONSOLE); > > } > > > > @@ -171,13 +210,28 @@ pluart_attach_common(struct pluart_softc *sc, int > > console) > > panic("%s: can't establish soft interrupt.", > > sc->sc_dev.dv_xname); > > > > - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | > > UART_IMSC_TXIM)); > > + if (fifolen > 0) { > > + /* > > + * The transmit FIFO size is set to 3/4 of the actual size as > > + * interrupts can only be triggered when the FIFO is partially > > + * full. Once triggered, we know that 1/4 of the FIFO size is > > + * utilized. > > + */ > > + sc->sc_fifolen = (fifolen * 3)/4; > > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS, > > + (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) | > > + (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT)); > > + } > > + sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM | UART_IMSC_TXIM; > > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); > > bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff); > > - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, > > - bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) & > > - ~UART_LCR_H_FEN); > > - > > - printf("\n"); > > + lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H); > > + if (fifolen > 0) { > > + lcr |= UART_LCR_H_FEN; > > + } else { > > + lcr &= ~UART_LCR_H_FEN; > > + } > > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr); > > } > > > > int > > @@ -197,19 +251,26 @@ pluart_intr(void *arg) > > if (sc->sc_tty == NULL) > > return 0; > > > > - if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM)) > > + if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) && > > + !ISSET(is, UART_IMSC_TXIM)) > > return 0; > > > > - if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) { > > - CLR(tp->t_state, TS_BUSY | TS_FLUSH); > > - if (sc->sc_halt > 0) > > - wakeup(&tp->t_outq); > > - (*linesw[tp->t_line].l_start)(tp); > > + if (ISSET(is, UART_IMSC_TXIM)) { > > + /* Disable transmit interrupt. */ > > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, > > + sc->sc_imsc & ~UART_IMSC_TXIM); > > + > > + if (ISSET(tp->t_state, TS_BUSY)) { > > + CLR(tp->t_state, TS_BUSY | TS_FLUSH); > > + if (sc->sc_halt > 0) > > + wakeup(&tp->t_outq); > > + (*linesw[tp->t_line].l_start)(tp); > > + } > > } > > > > p = sc->sc_ibufp; > > > > - while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) { > > + while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) { > > c = bus_space_read_2(iot, ioh, UART_DR); > > if (c & UART_DR_BE) { > > #ifdef DDB > > @@ -325,7 +386,6 @@ pluart_start(struct tty *tp) > > struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; > > bus_space_tag_t iot = sc->sc_iot; > > bus_space_handle_t ioh = sc->sc_ioh; > > - u_int16_t fr; > > int s; > > > > s = spltty(); > > @@ -336,11 +396,26 @@ pluart_start(struct tty *tp) > > goto out; > > SET(tp->t_state, TS_BUSY); > > > > - fr = bus_space_read_4(iot, ioh, UART_FR); > > - while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) { > > - bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); > > + /* Enable transmit interrupt. */ > > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); > > + > > + if ((sc->sc_hwflags & COM_HW_SBSA) == 0) { > > + char buf[UART_FIFO_SIZE_R3]; /* fifo max size */ > > + int i, n; > > + > > + n = q_to_b(&tp->t_outq, buf, sc->sc_fifolen); > > + for (i = 0; i < n; i++) > > + bus_space_write_4(iot, ioh, UART_DR, buf[i]); > > + } else { > > + u_int16_t fr; > > + > > fr = bus_space_read_4(iot, ioh, UART_FR); > > + while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) { > > + bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); > > + fr = bus_space_read_4(iot, ioh, UART_FR); > > + } > > } > > I still think that checking TXFF and using the same code for both > SBSA and true PL011 UARTs would be the best choice. This would avoid > fragmenting the code and improve robustness by relying on functionality > that is common to the different controller variants.
Fair enough, new diff. diff --git sys/dev/acpi/pluart_acpi.c sys/dev/acpi/pluart_acpi.c index dc8ea5e9922..08ebe13ffbc 100644 --- sys/dev/acpi/pluart_acpi.c +++ sys/dev/acpi/pluart_acpi.c @@ -91,6 +91,8 @@ pluart_acpi_attach(struct device *parent, struct device *self, void *aux) return; } + sc->sc.sc_hwflags |= COM_HW_SBSA; + pluart_attach_common(&sc->sc, pluart_acpi_is_console(sc)); } diff --git sys/dev/fdt/pluart_fdt.c sys/dev/fdt/pluart_fdt.c index 7f17365f1d6..798250593bf 100644 --- sys/dev/fdt/pluart_fdt.c +++ sys/dev/fdt/pluart_fdt.c @@ -69,6 +69,9 @@ pluart_fdt_attach(struct device *parent, struct device *self, void *aux) return; } + if (OF_is_compatible(faa->fa_node, "arm,sbsa-uart")) + sc->sc_hwflags |= COM_HW_SBSA; + sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY, pluart_intr, sc, sc->sc_dev.dv_xname); diff --git sys/dev/ic/pluart.c sys/dev/ic/pluart.c index eaa11b6c44b..457c88d8cad 100644 --- sys/dev/ic/pluart.c +++ sys/dev/ic/pluart.c @@ -99,6 +99,13 @@ #define UART_CR_CTSE (1 << 14) /* CTS hardware flow control enable */ #define UART_CR_RTSE (1 << 15) /* RTS hardware flow control enable */ #define UART_IFLS 0x34 /* Interrupt FIFO level select register */ +#define UART_IFLS_RX_SHIFT 3 /* RX level in bits [5:3] */ +#define UART_IFLS_TX_SHIFT 0 /* TX level in bits [2:0] */ +#define UART_IFLS_1_8 0 /* FIFO 1/8 full */ +#define UART_IFLS_1_4 1 /* FIFO 1/4 full */ +#define UART_IFLS_1_2 2 /* FIFO 1/2 full */ +#define UART_IFLS_3_4 3 /* FIFO 3/4 full */ +#define UART_IFLS_7_8 4 /* FIFO 7/8 full */ #define UART_IMSC 0x38 /* Interrupt mask set/clear register */ #define UART_IMSC_RIMIM (1 << 0) #define UART_IMSC_CTSMIM (1 << 1) @@ -115,8 +122,16 @@ #define UART_MIS 0x40 /* Masked interrupt status register */ #define UART_ICR 0x44 /* Interrupt clear register */ #define UART_DMACR 0x48 /* DMA control register */ +#define UART_PID0 0xfe0 /* Peripheral identification register 0 */ +#define UART_PID1 0xfe4 /* Peripheral identification register 1 */ +#define UART_PID2 0xfe8 /* Peripheral identification register 2 */ +#define UART_PID2_REV(x) (((x) & 0xf0) >> 4) +#define UART_PID3 0xfec /* Peripheral identification register 3 */ #define UART_SPACE 0x100 +#define UART_FIFO_SIZE 16 +#define UART_FIFO_SIZE_R3 32 + void pluartcnprobe(struct consdev *cp); void pluartcninit(struct consdev *cp); int pluartcngetc(dev_t dev); @@ -150,7 +165,31 @@ struct cdevsw pluartdev = void pluart_attach_common(struct pluart_softc *sc, int console) { - int maj; + int fifolen, maj; + int lcr; + + if ((sc->sc_hwflags & COM_HW_SBSA) == 0) { + int rev; + + rev = UART_PID2_REV(bus_space_read_4(sc->sc_iot, sc->sc_ioh, + UART_PID2)); + if (rev < 3) + fifolen = UART_FIFO_SIZE; + else + fifolen = UART_FIFO_SIZE_R3; + printf(": rev %d, %d byte fifo\n", rev, fifolen); + } else { + /* + * The SBSA UART is PL011 r1p5 compliant which implies revision + * 3 with a 32 byte FIFO. However, we cannot expect to configure + * RX/TX interrupt levels using the UARTIFLS register making it + * impossible to make assumptions about the number of available + * bytes in the FIFO. Therefore disable FIFO support for such + * devices. + */ + fifolen = 0; + printf("\n"); + } if (console) { /* Locate the major number. */ @@ -159,7 +198,7 @@ pluart_attach_common(struct pluart_softc *sc, int console) break; cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); - printf(": console"); + printf("%s: console\n", sc->sc_dev.dv_xname); SET(sc->sc_hwflags, COM_HW_CONSOLE); } @@ -171,13 +210,28 @@ pluart_attach_common(struct pluart_softc *sc, int console) panic("%s: can't establish soft interrupt.", sc->sc_dev.dv_xname); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM)); + if (fifolen > 0) { + /* + * The transmit FIFO size is set to 3/4 of the actual size as + * interrupts can only be triggered when the FIFO is partially + * full. Once triggered, we know that 1/4 of the FIFO size is + * utilized. + */ + sc->sc_fifolen = (fifolen * 3)/4; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS, + (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) | + (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT)); + } + sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM | UART_IMSC_TXIM; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, - bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) & - ~UART_LCR_H_FEN); - - printf("\n"); + lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H); + if (fifolen > 0) { + lcr |= UART_LCR_H_FEN; + } else { + lcr &= ~UART_LCR_H_FEN; + } + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr); } int @@ -197,19 +251,26 @@ pluart_intr(void *arg) if (sc->sc_tty == NULL) return 0; - if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM)) + if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) && + !ISSET(is, UART_IMSC_TXIM)) return 0; - if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) { - CLR(tp->t_state, TS_BUSY | TS_FLUSH); - if (sc->sc_halt > 0) - wakeup(&tp->t_outq); - (*linesw[tp->t_line].l_start)(tp); + if (ISSET(is, UART_IMSC_TXIM)) { + /* Disable transmit interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, + sc->sc_imsc & ~UART_IMSC_TXIM); + + if (ISSET(tp->t_state, TS_BUSY)) { + CLR(tp->t_state, TS_BUSY | TS_FLUSH); + if (sc->sc_halt > 0) + wakeup(&tp->t_outq); + (*linesw[tp->t_line].l_start)(tp); + } } p = sc->sc_ibufp; - while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) { + while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) { c = bus_space_read_2(iot, ioh, UART_DR); if (c & UART_DR_BE) { #ifdef DDB @@ -325,7 +386,6 @@ pluart_start(struct tty *tp) struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - u_int16_t fr; int s; s = spltty(); @@ -336,11 +396,19 @@ pluart_start(struct tty *tp) goto out; SET(tp->t_state, TS_BUSY); - fr = bus_space_read_4(iot, ioh, UART_FR); - while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) { - bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); + /* Enable transmit interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); + + while (tp->t_outq.c_cc > 0) { + uint16_t fr; + fr = bus_space_read_4(iot, ioh, UART_FR); + if (ISSET(fr, UART_FR_TXFF)) + break; + + bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); } + out: splx(s); } diff --git sys/dev/ic/pluartvar.h sys/dev/ic/pluartvar.h index 8fcbed14d5c..ba9748286ba 100644 --- sys/dev/ic/pluartvar.h +++ sys/dev/ic/pluartvar.h @@ -38,6 +38,7 @@ struct pluart_softc { #define COM_HW_FIFO 0x02 #define COM_HW_SIR 0x20 #define COM_HW_CONSOLE 0x40 +#define COM_HW_SBSA 0x80 u_int8_t sc_swflags; #define COM_SW_SOFTCAR 0x01 #define COM_SW_CLOCAL 0x02 @@ -45,6 +46,7 @@ struct pluart_softc { #define COM_SW_MDMBUF 0x08 #define COM_SW_PPS 0x10 int sc_fifolen; + int sc_imsc; u_int8_t sc_initialize; u_int8_t sc_cua;