⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sio_ioc4.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			  ports[1],			  ports[1]->ip_port_vhdl,			  intr_dev_vhdl);    }    {	/* Port 2 */	port = ports[2];	port->ip_hooks = &hooks_array[2];	/* Get direct hooks to the serial regs and uart regs	 * for this port	 */	port->ip_serial = &(port->ip_ioc4->port_2);	port->ip_uart = &(port->ip_ioc4->uart_2);#ifdef IOC4_SIO_DEBUG	printk("==== %s : serial port 2 address 0x%p uart address 0x%p\n",				__FUNCTION__, (void *)port->ip_serial, (void *)port->ip_uart);#endif	/* If we don't already have a ring buffer,	 * set one up.	 */	if (port->ip_ring_buf_k0 == 0) {#if PAGE_SIZE >= TOTAL_RING_BUF_SIZE	    if ((port->ip_ring_buf_k0 = kvpalloc(1, VM_DIRECT, 0)) == 0)		panic("ioc4_uart driver cannot allocate page\n");#else	    /* We need to allocate a chunk of memory on a	     * TOTAL_RING_BUF_SIZE boundary.	     */	    {		pgno_t pfn;		caddr_t vaddr;		if ((pfn = contig_memalloc(TOTAL_RING_BUF_SIZE / PAGE_SIZE,					   TOTAL_RING_BUF_SIZE / PAGE_SIZE,					   VM_DIRECT)) == 0)		    panic("ioc4_uart driver cannot allocate page\n");		ASSERT(small_pfn(pfn));		vaddr = small_pfntova_K0(pfn);		(void) COLOR_VALIDATION(pfdat + pfn,					colorof(vaddr),					0, VM_DIRECT);		port->ip_ring_buf_k0 = vaddr;	    }#endif	}	ASSERT((((int64_t)port->ip_ring_buf_k0) &		(TOTAL_RING_BUF_SIZE - 1)) == 0);	memset(port->ip_ring_buf_k0, 0, TOTAL_RING_BUF_SIZE);	port->ip_inring = RING(port, RX_0_OR_2);	port->ip_outring = RING(port, TX_0_OR_2);	/* Initialize the hardware for IOC4 */	hardware_init(port);	if (hwgraph_edge_get(ports[0]->ip_port_vhdl, "d", &intr_dev_vhdl) !=							GRAPH_SUCCESS) {	    intr_dev_vhdl = ports[2]->ip_port_vhdl;	}	/* Attach interrupt handler */	ioc4_intr_connect(conn_vhdl,			  ioc4_sio_intr_type,			  IOC4_SIO_IR_S2,			  ioc4_serial_intr,			  ports[2],			  ports[2]->ip_port_vhdl,			  intr_dev_vhdl);	ioc4_intr_connect(conn_vhdl,			  ioc4_other_intr_type,			  IOC4_OTHER_IR_S2_MEMERR,			  ioc4_dma_error_intr,			  ports[2],			  ports[2]->ip_port_vhdl,			  intr_dev_vhdl);    }    {	/* Port 3 */	port = ports[3];	port->ip_hooks = &hooks_array[3];	port->ip_serial = &(port->ip_ioc4->port_3);	port->ip_uart = &(port->ip_ioc4->uart_3);#ifdef IOC4_SIO_DEBUG	printk("==== %s : serial port 3 address 0x%p uart address 0x%p\n",				__FUNCTION__, (void *)port->ip_serial, (void *)port->ip_uart);#endif	port->ip_ring_buf_k0 = ports[2]->ip_ring_buf_k0;	port->ip_inring = RING(port, RX_1_OR_3);	port->ip_outring = RING(port, TX_1_OR_3);	/* Initialize the hardware for IOC4 */	hardware_init(port);	if (hwgraph_edge_get(ports[3]->ip_port_vhdl, "d", &intr_dev_vhdl) !=							GRAPH_SUCCESS) {	    intr_dev_vhdl = ports[3]->ip_port_vhdl;	}	/* Attach interrupt handler */	ioc4_intr_connect(conn_vhdl,		          ioc4_sio_intr_type,		          IOC4_SIO_IR_S3,		          ioc4_serial_intr,		          ports[3],		          ports[3]->ip_port_vhdl,		          intr_dev_vhdl);	ioc4_intr_connect(conn_vhdl,			  ioc4_other_intr_type,			  IOC4_OTHER_IR_S3_MEMERR,			  ioc4_dma_error_intr,			  ports[3],			  ports[3]->ip_port_vhdl,			  intr_dev_vhdl);    }#ifdef	DEBUG    idbg_addfunc( "ioc4dump", idbg_ioc4dump );#endif    return 0;}/* Shut down an IOC4 *//* ARGSUSED1 */voidioc4_serial_kill(ioc4port_t *port){    DEBUGINC(killed, 1);    /* Notify upper layer that this port is no longer usable */    UP_DETACH(GPORT(port));    /* Clear everything in the sscr */    PCI_OUTW(&port->ip_serial->sscr, 0);    port->ip_sscr = 0;#ifdef DEBUG    /* Make sure nobody gets past the lock and accesses the hardware */    port->ip_ioc4 = 0;    port->ip_serial = 0;#endif}/* * Open a port */static intioc4_open(sioport_t *port){    ioc4port_t *p = LPORT(port);    int         spin_success;#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_OPEN));#endif    p->ip_flags = 0;    p->ip_modem_bits = 0;    /* Pause the DMA interface if necessary */    if (p->ip_sscr & IOC4_SSCR_DMA_EN) {	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr | IOC4_SSCR_DMA_PAUSE);	SPIN((PCI_INW(&p->ip_serial->sscr) & IOC4_SSCR_PAUSE_STATE) == 0,             spin_success);	if (!spin_success) {		NOT_PROGRESS();		return(-1);	}    }    /* Reset the input fifo.  If the uart received chars while the port     * was closed and DMA is not enabled, the uart may have a bunch of     * chars hanging around in its RX fifo which will not be discarded     * by rclr in the upper layer. We must get rid of them here.     */    PCI_OUTB(&p->ip_uart->i4u_fcr, FCR_FIFOEN | FCR_RxFIFO);    /* Set defaults */    SET_BAUD(p, 9600);    PCI_OUTB(&p->ip_uart->i4u_lcr, LCR_BITS8 | LCR_1_STOP_BITS);    /* Re-enable DMA, set default threshold to intr whenever there is     * data available.     */    p->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;    p->ip_sscr |= 1; /* default threshold */    /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE     * flag if it was set above     */    PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr);    PCI_OUTW(&p->ip_serial->srtr, 0);    p->ip_tx_lowat = 1;    dprintf(("ioc4 open successful\n"));    return(0);}/* * Config hardware */static intioc4_config(sioport_t *port,	    int baud,	    int byte_size,	    int stop_bits,	    int parenb,	    int parodd){    ioc4port_t *p = LPORT(port);    char        lcr, sizebits;    int         spin_success;#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_CONFIG));#endif    if (SET_BAUD(p, baud))	return(1);    switch(byte_size) {      case 5:	sizebits = LCR_BITS5;	break;      case 6:	sizebits = LCR_BITS6;	break;      case 7:	sizebits = LCR_BITS7;	break;      case 8:	sizebits = LCR_BITS8;	break;      default:	dprintf(("invalid byte size port 0x%x size %d\n", port, byte_size));	return(1);    }    /* Pause the DMA interface if necessary */    if (p->ip_sscr & IOC4_SSCR_DMA_EN) {	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr | IOC4_SSCR_DMA_PAUSE);	SPIN((PCI_INW(&p->ip_serial->sscr) & IOC4_SSCR_PAUSE_STATE) == 0,             spin_success);	if (!spin_success) 		return(-1);    }    /* Clear relevant fields in lcr */    lcr = PCI_INB(&p->ip_uart->i4u_lcr);    lcr &= ~(LCR_MASK_BITS_CHAR | LCR_EPS |             LCR_PEN | LCR_MASK_STOP_BITS);    /* Set byte size in lcr */    lcr |= sizebits;    /* Set parity */    if (parenb) {	lcr |= LCR_PEN;	if (!parodd)	    lcr |= LCR_EPS;    }    /* Set stop bits */    if (stop_bits)	lcr |= LCR_2_STOP_BITS;    PCI_OUTB(&p->ip_uart->i4u_lcr, lcr);    dprintf(("ioc4_config: lcr bits 0x%x\n", lcr));    /* Re-enable the DMA interface if necessary */    if (p->ip_sscr & IOC4_SSCR_DMA_EN) {	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr);    }    p->ip_baud = baud;    /* When we get within this number of ring entries of filling the     * entire ring on TX, place an EXPLICIT intr to generate a lowat     * notification when output has drained.     */    p->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;    if (p->ip_tx_lowat == 0)	p->ip_tx_lowat = 1;    ioc4_rx_timeout(port, p->ip_rx_timeout);    return(0);}/* * Enable hardware flow control */static intioc4_enable_hfc(sioport_t *port, int enable){    ioc4port_t *p = LPORT(port);#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_ENABLE_HFC));#endif    dprintf(("enable hfc port 0x%p, enb %d\n", (void *)port, enable));    if (enable)	p->ip_sscr |= IOC4_SSCR_HFC_EN;    else	p->ip_sscr &= ~IOC4_SSCR_HFC_EN;    PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr);    return(0);}/* * Set external clock *//*ARGSUSED*/static intioc4_set_extclk(sioport_t *port, int clock_factor){#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_SET_EXTCLK));    /* XXX still todo */#endif    /* only support 0 (no external clock) */    return(clock_factor);}/* * Write bytes to the hardware.  Returns the number of bytes * actually written. */static intdo_ioc4_write(sioport_t *port, char *buf, int len){    int                prod_ptr, cons_ptr, total;    struct ring       *outring;    struct ring_entry *entry;    ioc4port_t        *p = LPORT(port);    struct hooks      *hooks = p->ip_hooks;    DEBUGINC(write_bytes, len);    DEBUGINC(write_cnt, 1);    dprintf(("write port 0x%p, len %d\n", (void *)port, len));    ASSERT(len >= 0);    prod_ptr = p->ip_tx_prod;    cons_ptr = PCI_INW(&p->ip_serial->stcir) & PROD_CONS_MASK;    outring = p->ip_outring;    /* Maintain a 1-entry red-zone.  The ring buffer is full when     * (cons - prod) % ring_size is 1.  Rather than do this subtraction     * in the body of the loop, I'll do it now.     */    cons_ptr = (cons_ptr - (int) sizeof(struct ring_entry)) & PROD_CONS_MASK;    total = 0;    /* Stuff the bytes into the output */    while ((prod_ptr != cons_ptr) && (len > 0)) {	int x;	/* Go 4 bytes (one ring entry) at a time */	entry = (struct ring_entry*) ((caddr_t)outring + prod_ptr);	/* Invalidate all entries */	entry->ring_allsc = 0;	/* Copy in some bytes */	for(x = 0; (x < 4) && (len > 0); x++) {	    entry->ring_data[x] = *buf++;	    entry->ring_sc[x] = IOC4_TXCB_VALID;	    len--;	    total++;	}	DEBUGINC(tx_buf_used, x);	DEBUGINC(tx_buf_cnt, 1);	/* If we are within some small threshold of filling up the entire	 * ring buffer, we must place an EXPLICIT intr here to generate	 * a lowat interrupt in case we subsequently really do fill up	 * the ring and the caller goes to sleep.  No need to place	 * more than one though.	 */	if (!(p->ip_flags & LOWAT_WRITTEN) &&	    ((cons_ptr - prod_ptr) & PROD_CONS_MASK) <=	    p->ip_tx_lowat * (int)sizeof(struct ring_entry)) {	    p->ip_flags |= LOWAT_WRITTEN;	    entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;	    dprintf(("write placing TX_EXPLICIT\n"));	}	/* Go on to next entry */	prod_ptr = (prod_ptr + (int) sizeof(struct ring_entry)) & PROD_CONS_MASK;    }    /* If we sent something, start DMA if necessary */    if (total > 0 && !(p->ip_sscr & IOC4_SSCR_DMA_EN)) {	p->ip_sscr |= IOC4_SSCR_DMA_EN;	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr);    }    /* Store the new producer pointer.  If TX is disabled, we stuff the     * data into the ring buffer, but we don't actually start TX.     */    if (!(p->ip_flags & TX_DISABLED)) {	PCI_OUTW(&p->ip_serial->stpir, prod_ptr);	/* If we are now transmitting, enable TX_MT interrupt so we	 * can disable DMA if necessary when the TX finishes.	 */	if (total > 0)	    enable_intrs(p, H_INTR_TX_MT);    }    p->ip_tx_prod = prod_ptr;    dprintf(("write port 0x%p, wrote %d\n", (void *)port, total));    DEBUGINC(wrote_bytes, total);    return(total);}/* Asynchronous write */static intioc4_write(sioport_t *port, char *buf, int len){#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_WRITE));#endif    return(do_ioc4_write(port, buf, len));}/* Synchronous write */static intioc4_sync_write(sioport_t *port, char *buf, int len){    int bytes;    ASSERT(sio_port_islocked(port));    bytes = do_ioc4_write(port, buf, len);    /* Don't allow the system to hang if XOFF is in force */    if (len > 0 && bytes == 0 && (LPORT(port)->ip_flags & TX_DISABLED))	ioc4_enable_tx(port, 1);    return(bytes);}/* Write flush */static voidioc4_wrflush(sioport_t *port){    ioc4port_t *p = LPORT(port);    ASSERT(sio_port_islocked(port));    /* We can't flush if TX is disabled due to XOFF. */    if (!(PCI_INW(&p->ip_ioc4->sio_ir) & IOC4_SIO_IR_S0_TX_MT) &&	(p->ip_flags & TX_DISABLED))	ioc4_enable_tx(port, 1);    /* Spin waiting for TX_MT to assert only if DMA is enabled.  If we     * are panicking and one of the other processors is already in     * symmon, DMA will be disabled and TX_MT will never be asserted.     * There may also be legitimate cases in the kernel where DMA is     * disabled and we won't flush correctly here.     */    while ((PCI_INW(&p->ip_serial->sscr) & (IOC4_SSCR_DMA_EN |           IOC4_SSCR_PAUSE_STATE)) == IOC4_SSCR_DMA_EN &&	   !(PCI_INW(&p->ip_ioc4->sio_ir) & IOC4_SIO_IR_S0_TX_MT)) {	udelay(5);    }}/* * Set or clear break condition on output */static intioc4_break(sioport_t *port, int brk){    ioc4port_t *p = LPORT(port);    char        lcr;    int         spin_success;#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_BREAK));#endif    /* Pause the DMA interface if necessary */    if (p->ip_sscr & IOC4_SSCR_DMA_EN) {	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr | IOC4_SSCR_DMA_PAUSE);	SPIN((PCI_INW(&p->ip_serial->sscr) & IOC4_SSCR_PAUSE_STATE) == 0,             spin_success);	if (!spin_success)		return(-1);    }    lcr = PCI_INB(&p->ip_uart->i4u_lcr);    if (brk) {	/* Set break */        PCI_OUTB(&p->ip_uart->i4u_lcr, lcr | LCR_SNDBRK);    }    else {	/* Clear break */        PCI_OUTB(&p->ip_uart->i4u_lcr, lcr & ~LCR_SNDBRK);    }    /* Re-enable the DMA interface if necessary */    if (p->ip_sscr & IOC4_SSCR_DMA_EN) {	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr);    }    dprintf(("break port 0x%p, brk %d\n", (void *)port, brk));    return(0);}static intioc4_enable_tx(sioport_t *port, int enb){    ioc4port_t   *p = LPORT(port);    struct hooks *hooks = p->ip_hooks;    int           spin_success;#ifdef NOT_YET    ASSERT(L_LOCKED(port, L_ENABLE_TX));#endif    /* If we're already in the desired state, we're done */    if ((enb && !(p->ip_flags & TX_DISABLED)) ||	(!enb && (p->ip_flags & TX_DISABLED)))	return(0);    /* Pause DMA */    if (p->ip_sscr & IOC4_SSCR_DMA_EN) {	PCI_OUTW(&p->ip_serial->sscr, p->ip_sscr | IOC4_SSCR_DMA_PAUSE);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -