static _INLINE_ void transmit_chars(struct bf535_serial *info) { int idx = info->hub2; if (info->x_char) { /* Send next char */ local_put_char(idx, info->x_char); info->x_char = 0; goto clear_and_return; } if((info->xmit_cnt <= 0) || info->tty->stopped) { /* TX ints off */ ACCESS_PORT_IER(idx) /* Change access to IER & data port */ UART_IER(idx) &= ~UART_IER_ETBEI; goto clear_and_return; } /* Send char */ local_put_char(idx,info->xmit_buf[info->xmit_tail++]); info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->xmit_cnt--; if (info->xmit_cnt < WAKEUP_CHARS) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); if(info->xmit_cnt <= 0) { /* All done for now... TX ints off */ ACCESS_PORT_IER(idx) /* Change access to IER & data port */ UART_IER(idx) &= ~UART_IER_ETBEI; goto clear_and_return; } clear_and_return: /* Clear interrupt (should be auto)*/ return; }
static void rs_start(struct tty_struct *tty) { struct bf535_serial *info = (struct bf535_serial *)tty->driver_data; unsigned long flags = 0; unsigned int idx = (unsigned int) info->hub2; if (serial_paranoia_check(info, tty->device, "rs_start")) return; save_flags(flags); cli(); ACCESS_PORT_IER(idx) /* Change access to IER & data port */ if (info->xmit_cnt && info->xmit_buf && !(UART_IER(idx) & UART_IER_ETBEI)) UART_IER(idx) |= UART_IER_ETBEI; restore_flags(flags); }
static int linux_uart_write(struct file *fp, const char __user *buff, size_t size, loff_t *off) { int wsize; if(buff == NULL) return 0; if(fp->private_data == NULL) return -EPERM; if( !is_bit_set(serial.out.serf->flag, RT_SERIAL_dom_WRITE)) { return -EPERM; } down_interruptible(&wsem); wsize = rt_serial_user_write(&serial.out, buff, size); up(&wsem); if(wsize > 0) { outb(0xB, UART_IER(uart)); outb(0x9, UART_MCR(uart)); } return wsize; }
/* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */ static void rs_stop(struct tty_struct *tty) { struct bf535_serial *info = (struct bf535_serial *)tty->driver_data; unsigned long flags = 0; unsigned int idx = (unsigned int) info->hub2; if (serial_paranoia_check(info, tty->device, "rs_stop")) return; save_flags(flags); cli(); ACCESS_PORT_IER(idx) /* Change access to IER & data port */ UART_IER(idx) = 0; restore_flags(flags); }
int rt_serial_write(const char *src, int size) { int ret; ret = dom_serial_fifo_write(&rt_serial.out, src, size); /* enable THRE interrupt */ if(ret > 0) { outb(0xB, UART_IER(uart)); outb(0x9, UART_MCR(uart)); } return ret; }
static void output_open(struct hfmodem_state *dev) { dev->ptt_out.flags = 0; if (dev->ptt_out.seriobase > 0) { if (!check_region(dev->ptt_out.seriobase, SER_EXTENT)) { request_region(dev->ptt_out.seriobase, SER_EXTENT, "hfmodem ser ptt"); dev->ptt_out.flags |= SP_SER; outb(0, UART_IER(dev->ptt_out.seriobase)); /* 5 bits, 1 stop, no parity, no break, Div latch access */ outb(0x80, UART_LCR(dev->ptt_out.seriobase)); outb(0, UART_DLM(dev->ptt_out.seriobase)); outb(1, UART_DLL(dev->ptt_out.seriobase)); /* as fast as possible */ /* LCR and MCR set by output_status */ } else printk(KERN_WARNING "%s: PTT output: serial port at 0x%x busy\n", hfmodem_drvname, dev->ptt_out.seriobase); } if (dev->ptt_out.pariobase > 0) { if (parport_claim(dev->ptt_out.pardev)) printk(KERN_WARNING "%s: PTT output: parallel port at 0x%x busy\n", hfmodem_drvname, dev->ptt_out.pariobase); else dev->ptt_out.flags |= SP_PAR; } if (dev->ptt_out.midiiobase > 0) { if (!check_region(dev->ptt_out.midiiobase, MIDI_EXTENT)) { request_region(dev->ptt_out.midiiobase, MIDI_EXTENT, "hfmodem midi ptt"); dev->ptt_out.flags |= SP_MIDI; } else printk(KERN_WARNING "%s: PTT output: midi port at 0x%x busy\n", hfmodem_drvname, dev->ptt_out.midiiobase); } output_status(dev, 0); printk(KERN_INFO "%s: PTT output:", hfmodem_drvname); if (dev->ptt_out.flags & SP_SER) printk(" serial interface at 0x%x", dev->ptt_out.seriobase); if (dev->ptt_out.flags & SP_PAR) printk(" parallel interface at 0x%x", dev->ptt_out.pariobase); if (dev->ptt_out.flags & SP_MIDI) printk(" mpu401 (midi) interface at 0x%x", dev->ptt_out.midiiobase); if (!dev->ptt_out.flags) printk(" none"); printk("\n"); }
/* * UART Init function */ void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits, uart_stopbit_t data_nb_stop, uart_parity_t data_parity, uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval) { uint32_t lcr_config; uint32_t uart_port; uart_port = uart_num; switch(uart_num) { case UART0_NUM: /* use PLL1 as clock source for UART0 */ CGU_BASE_UART0_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART1_NUM: /* use PLL1 as clock source for UART1 */ CGU_BASE_UART1_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART2_NUM: /* use PLL1 as clock source for UART2 */ CGU_BASE_UART2_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART3_NUM: /* use PLL1 as clock source for UART3 */ CGU_BASE_UART3_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; default: return; /* error */ } /* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared) */ UART_FCR(uart_port) = ( UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS); /* Disable FIFO */ UART_FCR(uart_port) = 0; // Dummy read (to clear existing data) while (UART_LSR(uart_port) & UART_LSR_RDR ) { dummy_read = UART_RBR(uart_port); } /* Wait end of TX & disable TX */ UART_TER(uart_port) = UART_TER_TXEN; /* Wait for current transmit complete */ while (!(UART_LSR(uart_port) & UART_LSR_THRE)); /* Disable Tx */ UART_TER(uart_port) = 0; /* Disable interrupt */ UART_IER(uart_port) = 0; /* Set LCR to default state */ UART_LCR(uart_port) = 0; /* Set ACR to default state */ UART_ACR(uart_port) = 0; /* Dummy Read to Clear Status */ dummy_read = UART_LSR(uart_port); /* Table 835. USART Fractional Divider Register: UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) ) The value of MULVAL and DIVADDVAL should comply to the following conditions: 1. 1 <= MULVAL <= 15 2. 0 <= DIVADDVAL <= 14 3. DIVADDVAL < MULVAL */ /* Set DLAB Bit */ UART_LCR(uart_port) |= UART_LCR_DLAB_EN; UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor); UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor); /* Clear DLAB Bit */ UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; UART_FDR(uart_port) = (UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval)) & UART_FDR_BITMASK; /* Read LCR config & Force Enable of Divisor Latches Access */ lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) & UART_LCR_BITMASK; lcr_config |= data_nb_bits; /* Set Nb Data Bits */ lcr_config |= data_nb_stop; /* Set Nb Stop Bits */ lcr_config |= data_parity; /* Set Data Parity */ /* Write LCR (only 8bits) */ UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK); /* Enable TX */ UART_TER(uart_port) = UART_TER_TXEN; }
static void sm_output_open(struct sm_state *sm, const char *ifname) { enum uart u = c_uart_unknown; struct parport *pp = NULL; sm->hdrv.ptt_out.flags = 0; if (sm->hdrv.ptt_out.seriobase > 0 && sm->hdrv.ptt_out.seriobase <= 0x1000-SER_EXTENT && ((u = check_uart(sm->hdrv.ptt_out.seriobase))) != c_uart_unknown) { sm->hdrv.ptt_out.flags |= SP_SER; request_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT, "sm ser ptt"); outb(0, UART_IER(sm->hdrv.ptt_out.seriobase)); /* 5 bits, 1 stop, no parity, no break, Div latch access */ outb(0x80, UART_LCR(sm->hdrv.ptt_out.seriobase)); outb(0, UART_DLM(sm->hdrv.ptt_out.seriobase)); outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */ /* LCR and MCR set by output_status */ } sm->pardev = NULL; if (sm->hdrv.ptt_out.pariobase > 0) { pp = parport_enumerate(); while (pp && pp->base != sm->hdrv.ptt_out.pariobase) pp = pp->next; if (!pp) printk(KERN_WARNING "%s: parport at address 0x%x not found\n", sm_drvname, sm->hdrv.ptt_out.pariobase); else if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) printk(KERN_WARNING "%s: parport at address 0x%x cannot be used\n", sm_drvname, sm->hdrv.ptt_out.pariobase); else { sm->pardev = parport_register_device(pp, ifname, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); if (!sm->pardev) { pp = NULL; printk(KERN_WARNING "%s: cannot register parport device (address 0x%x)\n", sm_drvname, sm->hdrv.ptt_out.pariobase); } else { if (parport_claim(sm->pardev)) { parport_unregister_device(sm->pardev); sm->pardev = NULL; printk(KERN_WARNING "%s: cannot claim parport at address 0x%x\n", sm_drvname, sm->hdrv.ptt_out.pariobase); } else sm->hdrv.ptt_out.flags |= SP_PAR; } } } if (sm->hdrv.ptt_out.midiiobase > 0 && sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && check_midi(sm->hdrv.ptt_out.midiiobase)) { sm->hdrv.ptt_out.flags |= SP_MIDI; request_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT, "sm midi ptt"); } sm_output_status(sm); printk(KERN_INFO "%s: ptt output:", sm_drvname); if (sm->hdrv.ptt_out.flags & SP_SER) printk(" serial interface at 0x%x, uart %s", sm->hdrv.ptt_out.seriobase, uart_str[u]); if (sm->hdrv.ptt_out.flags & SP_PAR) printk(" parallel interface at 0x%x", sm->hdrv.ptt_out.pariobase); if (sm->hdrv.ptt_out.flags & SP_MIDI) printk(" mpu401 (midi) interface at 0x%x", sm->hdrv.ptt_out.midiiobase); if (!sm->hdrv.ptt_out.flags) printk(" none"); printk("\n"); }