| #include <linux/wait.h> |
| |
| #define UART_CONFIG_TYPE (1 << 0) |
| #define UART_CONFIG_IRQ (1 << 1) |
| #define UPIO_PORT (0) |
| #define UPIO_HUB6 (1) |
| #define UPIO_MEM (2) |
| #define UPIO_MEM32 (3) |
| #define UPIO_AU (4) /* Au1x00 type IO */ |
| #define UPIO_TSI (5) /* Tsi108/109 type IO */ |
| #define UPF_FOURPORT (1 << 1) |
| #define UPF_SAK (1 << 2) |
| #define UPF_SPD_MASK (0x1030) |
| #define UPF_SPD_HI (0x0010) |
| #define UPF_SPD_VHI (0x0020) |
| #define UPF_SPD_CUST (0x0030) |
| #define UPF_SPD_SHI (0x1000) |
| #define UPF_SPD_WARP (0x1010) |
| #define UPF_SKIP_TEST (1 << 6) |
| #define UPF_AUTO_IRQ (1 << 7) |
| #define UPF_HARDPPS_CD (1 << 11) |
| #define UPF_LOW_LATENCY (1 << 13) |
| #define UPF_BUGGY_UART (1 << 14) |
| #define UPF_MAGIC_MULTIPLIER (1 << 16) |
| #define UPF_CONS_FLOW (1 << 23) |
| #define UPF_SHARE_IRQ (1 << 24) |
| #define UPF_BOOT_AUTOCONF (1 << 28) |
| #define UPF_DEAD (1 << 30) |
| #define UPF_IOREMAP (1 << 31) |
| #define UPF_CHANGE_MASK (0x17fff) |
| #define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY) |
| #define USF_CLOSING_WAIT_INF (0) |
| #define USF_CLOSING_WAIT_NONE (~0U) |
| |
| #define UART_XMIT_SIZE PAGE_SIZE |
| |
| #define UIF_CHECK_CD (1 << 25) |
| #define UIF_CTS_FLOW (1 << 26) |
| #define UIF_NORMAL_ACTIVE (1 << 29) |
| #define UIF_INITIALIZED (1 << 31) |
| #define UIF_SUSPENDED (1 << 30) |
| |
| #define WAKEUP_CHARS 256 |
| |
| #define uart_circ_empty(circ) ((circ)->head == (circ)->tail) |
| #define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0) |
| |
| #define uart_circ_chars_pending(circ) \ |
| (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) |
| |
| #define uart_circ_chars_free(circ) \ |
| (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) |
| |
| #define uart_tx_stopped(port) \ |
| ((port)->info->tty->stopped || (port)->info->tty->hw_stopped) |
| |
| #define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \ |
| (cflag) & CRTSCTS || \ |
| !((cflag) & CLOCAL)) |
| |
| |
| struct sb_uart_port; |
| struct sb_uart_info; |
| struct serial_struct; |
| struct device; |
| |
| struct sb_uart_ops { |
| unsigned int (*tx_empty)(struct sb_uart_port *); |
| void (*set_mctrl)(struct sb_uart_port *, unsigned int mctrl); |
| unsigned int (*get_mctrl)(struct sb_uart_port *); |
| void (*stop_tx)(struct sb_uart_port *); |
| void (*start_tx)(struct sb_uart_port *); |
| void (*send_xchar)(struct sb_uart_port *, char ch); |
| void (*stop_rx)(struct sb_uart_port *); |
| void (*enable_ms)(struct sb_uart_port *); |
| void (*break_ctl)(struct sb_uart_port *, int ctl); |
| int (*startup)(struct sb_uart_port *); |
| void (*shutdown)(struct sb_uart_port *); |
| void (*set_termios)(struct sb_uart_port *, struct MP_TERMIOS *new, |
| struct MP_TERMIOS *old); |
| void (*pm)(struct sb_uart_port *, unsigned int state, |
| unsigned int oldstate); |
| int (*set_wake)(struct sb_uart_port *, unsigned int state); |
| |
| const char *(*type)(struct sb_uart_port *); |
| |
| void (*release_port)(struct sb_uart_port *); |
| |
| int (*request_port)(struct sb_uart_port *); |
| void (*config_port)(struct sb_uart_port *, int); |
| int (*verify_port)(struct sb_uart_port *, struct serial_struct *); |
| int (*ioctl)(struct sb_uart_port *, unsigned int, unsigned long); |
| }; |
| |
| |
| struct sb_uart_icount { |
| __u32 cts; |
| __u32 dsr; |
| __u32 rng; |
| __u32 dcd; |
| __u32 rx; |
| __u32 tx; |
| __u32 frame; |
| __u32 overrun; |
| __u32 parity; |
| __u32 brk; |
| __u32 buf_overrun; |
| }; |
| typedef unsigned int upf_t; |
| |
| struct sb_uart_port { |
| spinlock_t lock; /* port lock */ |
| unsigned int iobase; /* in/out[bwl] */ |
| unsigned char __iomem *membase; /* read/write[bwl] */ |
| unsigned int irq; /* irq number */ |
| unsigned int uartclk; /* base uart clock */ |
| unsigned int fifosize; /* tx fifo size */ |
| unsigned char x_char; /* xon/xoff char */ |
| unsigned char regshift; /* reg offset shift */ |
| unsigned char iotype; /* io access style */ |
| unsigned char unused1; |
| |
| |
| unsigned int read_status_mask; /* driver specific */ |
| unsigned int ignore_status_mask; /* driver specific */ |
| struct sb_uart_info *info; /* pointer to parent info */ |
| struct sb_uart_icount icount; /* statistics */ |
| |
| struct console *cons; /* struct console, if any */ |
| #ifdef CONFIG_SERIAL_CORE_CONSOLE |
| unsigned long sysrq; /* sysrq timeout */ |
| #endif |
| |
| upf_t flags; |
| |
| unsigned int mctrl; /* current modem ctrl settings */ |
| unsigned int timeout; /* character-based timeout */ |
| unsigned int type; /* port type */ |
| const struct sb_uart_ops *ops; |
| unsigned int custom_divisor; |
| unsigned int line; /* port index */ |
| unsigned long mapbase; /* for ioremap */ |
| struct device *dev; /* parent device */ |
| unsigned char hub6; /* this should be in the 8250 driver */ |
| unsigned char unused[3]; |
| }; |
| |
| #define mdmode unused[2] |
| #define MDMODE_ADDR 0x1 |
| #define MDMODE_ENABLE 0x2 |
| #define MDMODE_AUTO 0x4 |
| #define MDMODE_ADDRSEND 0x8 |
| |
| struct sb_uart_state { |
| unsigned int close_delay; /* msec */ |
| unsigned int closing_wait; /* msec */ |
| |
| |
| int count; |
| int pm_state; |
| struct sb_uart_info *info; |
| struct sb_uart_port *port; |
| |
| struct mutex mutex; |
| }; |
| |
| typedef unsigned int uif_t; |
| |
| struct sb_uart_info { |
| struct tty_struct *tty; |
| struct circ_buf xmit; |
| uif_t flags; |
| |
| int blocked_open; |
| |
| struct tasklet_struct tlet; |
| |
| wait_queue_head_t open_wait; |
| wait_queue_head_t delta_msr_wait; |
| }; |
| |
| |
| struct module; |
| struct tty_driver; |
| |
| struct uart_driver { |
| struct module *owner; |
| const char *driver_name; |
| const char *dev_name; |
| int major; |
| int minor; |
| int nr; |
| struct console *cons; |
| |
| struct sb_uart_state *state; |
| struct tty_driver *tty_driver; |
| }; |
| |
| void sb_uart_write_wakeup(struct sb_uart_port *port) |
| { |
| struct sb_uart_info *info = port->info; |
| tasklet_schedule(&info->tlet); |
| } |
| |
| void sb_uart_update_timeout(struct sb_uart_port *port, unsigned int cflag, |
| unsigned int baud) |
| { |
| unsigned int bits; |
| |
| switch (cflag & CSIZE) |
| { |
| case CS5: |
| bits = 7; |
| break; |
| |
| case CS6: |
| bits = 8; |
| break; |
| |
| case CS7: |
| bits = 9; |
| break; |
| |
| default: |
| bits = 10; |
| break; |
| } |
| |
| if (cflag & CSTOPB) |
| { |
| bits++; |
| } |
| |
| if (cflag & PARENB) |
| { |
| bits++; |
| } |
| |
| bits = bits * port->fifosize; |
| |
| port->timeout = (HZ * bits) / baud + HZ/50; |
| } |
| unsigned int sb_uart_get_baud_rate(struct sb_uart_port *port, struct MP_TERMIOS *termios, |
| struct MP_TERMIOS *old, unsigned int min, |
| unsigned int max) |
| { |
| unsigned int try, baud, altbaud = 38400; |
| upf_t flags = port->flags & UPF_SPD_MASK; |
| |
| if (flags == UPF_SPD_HI) |
| altbaud = 57600; |
| if (flags == UPF_SPD_VHI) |
| altbaud = 115200; |
| if (flags == UPF_SPD_SHI) |
| altbaud = 230400; |
| if (flags == UPF_SPD_WARP) |
| altbaud = 460800; |
| |
| for (try = 0; try < 2; try++) { |
| |
| switch (termios->c_cflag & (CBAUD | CBAUDEX)) |
| { |
| case B921600 : baud = 921600; break; |
| case B460800 : baud = 460800; break; |
| case B230400 : baud = 230400; break; |
| case B115200 : baud = 115200; break; |
| case B57600 : baud = 57600; break; |
| case B38400 : baud = 38400; break; |
| case B19200 : baud = 19200; break; |
| case B9600 : baud = 9600; break; |
| case B4800 : baud = 4800; break; |
| case B2400 : baud = 2400; break; |
| case B1800 : baud = 1800; break; |
| case B1200 : baud = 1200; break; |
| case B600 : baud = 600; break; |
| case B300 : baud = 300; break; |
| case B200 : baud = 200; break; |
| case B150 : baud = 150; break; |
| case B134 : baud = 134; break; |
| case B110 : baud = 110; break; |
| case B75 : baud = 75; break; |
| case B50 : baud = 50; break; |
| default : baud = 9600; break; |
| } |
| |
| if (baud == 38400) |
| baud = altbaud; |
| |
| if (baud == 0) |
| baud = 9600; |
| |
| if (baud >= min && baud <= max) |
| return baud; |
| |
| termios->c_cflag &= ~CBAUD; |
| if (old) { |
| termios->c_cflag |= old->c_cflag & CBAUD; |
| old = NULL; |
| continue; |
| } |
| |
| termios->c_cflag |= B9600; |
| } |
| |
| return 0; |
| } |
| unsigned int sb_uart_get_divisor(struct sb_uart_port *port, unsigned int baud) |
| { |
| unsigned int quot; |
| |
| if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) |
| quot = port->custom_divisor; |
| else |
| quot = (port->uartclk + (8 * baud)) / (16 * baud); |
| |
| return quot; |
| } |
| |
| |
| |
| static inline int sb_uart_handle_break(struct sb_uart_port *port) |
| { |
| struct sb_uart_info *info = port->info; |
| |
| if (port->flags & UPF_SAK) |
| do_SAK(info->tty); |
| return 0; |
| } |
| |
| static inline void sb_uart_handle_dcd_change(struct sb_uart_port *port, unsigned int status) |
| { |
| struct sb_uart_info *info = port->info; |
| |
| port->icount.dcd++; |
| |
| if (info->flags & UIF_CHECK_CD) { |
| if (status) |
| wake_up_interruptible(&info->open_wait); |
| else if (info->tty) |
| tty_hangup(info->tty); |
| } |
| } |
| |
| static inline void sb_uart_handle_cts_change(struct sb_uart_port *port, unsigned int status) |
| { |
| struct sb_uart_info *info = port->info; |
| struct tty_struct *tty = info->tty; |
| |
| port->icount.cts++; |
| |
| if (info->flags & UIF_CTS_FLOW) { |
| if (tty->hw_stopped) { |
| if (status) { |
| tty->hw_stopped = 0; |
| port->ops->start_tx(port); |
| sb_uart_write_wakeup(port); |
| } |
| } else { |
| if (!status) { |
| tty->hw_stopped = 1; |
| port->ops->stop_tx(port); |
| } |
| } |
| } |
| } |
| |
| |
| |