📄 serial.c
字号:
{#ifdef CONFIG_ETRAX_SERIAL_PORT2 E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), E100_STRUCT_MASK(2,DTR), E100_STRUCT_MASK(2,RI), E100_STRUCT_MASK(2,DSR), E100_STRUCT_MASK(2,CD)#else CONTROL_PINS_PORT_NOT_USED(2)#endif }, /* Ser 3 */ {#ifdef CONFIG_ETRAX_SERIAL_PORT3 E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), E100_STRUCT_MASK(3,DTR), E100_STRUCT_MASK(3,RI), E100_STRUCT_MASK(3,DSR), E100_STRUCT_MASK(3,CD)#else CONTROL_PINS_PORT_NOT_USED(3)#endif }};#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */#define E100_RTS_MASK 0x20#define E100_CTS_MASK 0x40/* All serial port signals are active low: * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level * * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip *//* Output */#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)/* Input */#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK)/* These are typically PA or PB and 0 means 0V, 1 means 3.3V *//* Is an output */#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)/* Normally inputs */#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)/* Input */#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)/* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ports, since it significantly saves * memory if large numbers of serial ports are open. */static unsigned char *tmp_buf;#ifdef DECLARE_MUTEXstatic DECLARE_MUTEX(tmp_buf_sem);#elsestatic struct semaphore tmp_buf_sem = MUTEX;#endif/* Calculate the chartime depending on baudrate, numbor of bits etc. */static void update_char_time(struct e100_serial * info){ tcflag_t cflags = info->tty->termios->c_cflag; int bits; /* calc. number of bits / data byte */ /* databits + startbit and 1 stopbit */ if ((cflags & CSIZE) == CS7) bits = 9; else bits = 10; if (cflags & CSTOPB) /* 2 stopbits ? */ bits++; if (cflags & PARENB) /* parity bit ? */ bits++; /* calc timeout */ info->char_time_usec = ((bits * 1000000) / info->baud) + 1; info->flush_time_usec = 4*info->char_time_usec; if (info->flush_time_usec < MIN_FLUSH_TIME_USEC) info->flush_time_usec = MIN_FLUSH_TIME_USEC;}/* * This function maps from the Bxxxx defines in asm/termbits.h into real * baud rates. */static int cflag_to_baud(unsigned int cflag){ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 }; static int ext_baud_table[] = { 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000, 0, 0, 0, 0, 0, 0, 0, 0 }; if (cflag & CBAUDEX) return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; else return baud_table[cflag & CBAUD];}/* and this maps to an etrax100 hardware baud constant */static unsigned char cflag_to_etrax_baud(unsigned int cflag){ char retval; static char baud_table[] = { -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; static char ext_baud_table[] = { -1, 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, -1 }; if (cflag & CBAUDEX) retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; else retval = baud_table[cflag & CBAUD]; if (retval < 0) { printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); retval = 5; /* choose default 9600 instead */ } return retval | (retval << 4); /* choose same for both TX and RX */}/* Various static support functions *//* Functions to set or clear DTR/RTS on the requested line *//* It is complicated by the fact that RTS is a serial port register, while * DTR might not be implemented in the HW at all, and if it is, it can be on * any general port. */static inline void e100_dtr(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM unsigned char mask = e100_modem_pins[info->line].dtr_mask;#ifdef SERIAL_DEBUG_IO printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); printk("ser%i shadow before 0x%02X get: %i\n", info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info));#endif /* DTR is active low */ { unsigned long flags; save_flags(flags); cli(); *e100_modem_pins[info->line].dtr_shadow &= ~mask; *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; restore_flags(flags); } #ifdef SERIAL_DEBUG_IO printk("ser%i shadow after 0x%02X get: %i\n", info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info));#endif#endif}/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive * 0=0V , 1=3.3V */static inline void e100_rts(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM unsigned long flags; save_flags(flags); cli(); info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ info->port[REG_REC_CTRL] = info->rx_ctrl; restore_flags(flags);#ifdef SERIAL_DEBUG_IO printk("ser%i rts %i\n", info->line, set);#endif#endif}/* If this behaves as a modem, RI and CD is an output */static inline void e100_ri_out(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM /* RI is active low */ { unsigned char mask = e100_modem_pins[info->line].ri_mask; unsigned long flags; save_flags(flags); cli(); *e100_modem_pins[info->line].ri_shadow &= ~mask; *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; restore_flags(flags); }#endif}static inline void e100_cd_out(struct e100_serial *info, int set){#ifndef CONFIG_SVINTO_SIM /* CD is active low */ { unsigned char mask = e100_modem_pins[info->line].cd_mask; unsigned long flags; save_flags(flags); cli(); *e100_modem_pins[info->line].cd_shadow &= ~mask; *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; restore_flags(flags); }#endif}static inline voide100_disable_rx(struct e100_serial *info){#ifndef CONFIG_SVINTO_SIM /* disable the receiver */ info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));#endif}static inline void e100_enable_rx(struct e100_serial *info){#ifndef CONFIG_SVINTO_SIM /* enable the receiver */ info->port[REG_REC_CTRL] = (info->rx_ctrl |= IO_MASK(R_SERIAL0_REC_CTRL, rec_enable));#endif}/* the rx DMA uses both the dma_descr and the dma_eop interrupts */static inline voide100_disable_rxdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR printk("rxdma_irq(%d): 0\n",info->line);#endif DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line)); *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);}static inline voide100_enable_rxdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR printk("rxdma_irq(%d): 1\n",info->line);#endif DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line)); *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);}/* the tx DMA uses only dma_descr interrupt */static _INLINE_ voide100_disable_txdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR printk("txdma_irq(%d): 0\n",info->line);#endif DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line)); *R_IRQ_MASK2_CLR = info->irq;}static _INLINE_ voide100_enable_txdma_irq(struct e100_serial *info) {#ifdef SERIAL_DEBUG_INTR printk("txdma_irq(%d): 1\n",info->line);#endif DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line)); *R_IRQ_MASK2_SET = info->irq;}static _INLINE_ voide100_disable_txdma_channel(struct e100_serial *info){ unsigned long flags; /* Disable output DMA channel for the serial port in question * ( set to something other then serialX) */ save_flags(flags); cli(); DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line)); if (info->line == 0) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) == IO_STATE(R_GEN_CONFIG, dma6, serial0)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); } } else if (info->line == 1) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) == IO_STATE(R_GEN_CONFIG, dma8, serial1)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); } } else if (info->line == 2) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) == IO_STATE(R_GEN_CONFIG, dma2, serial2)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); } } else if (info->line == 3) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) == IO_STATE(R_GEN_CONFIG, dma4, serial3)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); } } *R_GEN_CONFIG = genconfig_shadow; restore_flags(flags);}static _INLINE_ voide100_enable_txdma_channel(struct e100_serial *info){ unsigned long flags; save_flags(flags); cli(); DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line)); /* Enable output DMA channel for the serial port in question */ if (info->line == 0) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); } else if (info->line == 1) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); } else if (info->line == 2) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); } else if (info->line == 3) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); } *R_GEN_CONFIG = genconfig_shadow; restore_flags(flags);}static _INLINE_ voide100_disable_rxdma_channel(struct e100_serial *info){ unsigned long flags; /* Disable input DMA channel for the serial port in question * ( set to something other then serialX) */ save_flags(flags); cli(); if (info->line == 0) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) == IO_STATE(R_GEN_CONFIG, dma7, serial0)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused); } } else if (info->line == 1) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) == IO_STATE(R_GEN_CONFIG, dma9, serial1)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb); } } else if (info->line == 2) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) == IO_STATE(R_GEN_CONFIG, dma3, serial2)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); } } else if (info->line == 3) { if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) == IO_STATE(R_GEN_CONFIG, dma5, serial3)) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); } } *R_GEN_CONFIG = genconfig_shadow; restore_flags(flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -