serial167.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,382 行 · 第 1/5 页

C
2,382
字号
     * run at the speed specified in bootinfo, or at 19.2K */    /* Actually, it should run at whatever speed 166Bug was using */    /* Note info->timeout isn't used at present */    if (info != serial_console_info) {	info->tbpr = baud_bpr[i]; /* Tx BPR */	info->tco = baud_co[i]; /* Tx CO */	info->rbpr = baud_bpr[i]; /* Rx BPR */	info->rco = baud_co[i] >> 5; /* Rx CO */	if (baud_table[i] == 134) {            info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;            /* get it right for 134.5 baud */	} else if (baud_table[i]) {            info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;        /* this needs to be propagated into the card info */	} else {            info->timeout = 0;	}    }    /* By tradition (is it a standard?) a baud rate of zero       implies the line should be/has been closed.  A bit       later in this routine such a test is performed. */    /* byte size and parity */    info->cor7 = 0;    info->cor6 = 0;    info->cor5 = 0;    info->cor4 = (info->default_threshold		  ? info->default_threshold		  : baud_cor4[i]); /* receive threshold */    /* Following two lines added 101295, RGH. */    /* It is obviously wrong to access CyCORx, and not info->corx here,     * try and remember to fix it later! */    channel = info->line;    base_addr[CyCAR] = (u_char)channel;    if (C_CLOCAL(info->tty)) {	if (base_addr[CyIER] & CyMdmCh)	    base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */			       /* ignore 1->0 modem transitions */	if (base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD))	    base_addr[CyCOR4] &= ~(CyDSR|CyCTS|CyDCD);			       /* ignore 0->1 modem transitions */	if (base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD))	    base_addr[CyCOR5] &= ~(CyDSR|CyCTS|CyDCD);    } else {	if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)	    base_addr[CyIER] |= CyMdmCh; /* with modem intr */			       /* act on 1->0 modem transitions */	if ((base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD))	    base_addr[CyCOR4] |= CyDSR|CyCTS|CyDCD;			       /* act on 0->1 modem transitions */	if ((base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD))	    base_addr[CyCOR5] |= CyDSR|CyCTS|CyDCD;    }    info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;    info->cor2 = CyETC;    switch(cflag & CSIZE){    case CS5:        info->cor1 = Cy_5_BITS;        break;    case CS6:        info->cor1 = Cy_6_BITS;        break;    case CS7:        info->cor1 = Cy_7_BITS;        break;    case CS8:        info->cor1 = Cy_8_BITS;        break;    }    if (cflag & PARENB){        if (cflag & PARODD){            info->cor1 |= CyPARITY_O;        }else{            info->cor1 |= CyPARITY_E;        }    }else{        info->cor1 |= CyPARITY_NONE;    }	    /* CTS flow control flag */#if 0    /* Don't complcate matters for now! RGH 141095 */    if (cflag & CRTSCTS){	info->flags |= ASYNC_CTS_FLOW;	info->cor2 |= CyCtsAE;    }else{	info->flags &= ~ASYNC_CTS_FLOW;	info->cor2 &= ~CyCtsAE;    }#endif    if (cflag & CLOCAL)	info->flags &= ~ASYNC_CHECK_CD;    else	info->flags |= ASYNC_CHECK_CD;     /***********************************************	The hardware option, CyRtsAO, presents RTS when	the chip has characters to send.  Since most modems	use RTS as reverse (inbound) flow control, this	option is not used.  If inbound flow control is	necessary, DTR can be programmed to provide the	appropriate signals for use with a non-standard	cable.  Contact Marcio Saito for details.     ***********************************************/    channel = info->line;    local_irq_save(flags);	base_addr[CyCAR] = (u_char)channel;	/* CyCMR set once only in mvme167_init_serial() */	if (base_addr[CyLICR] != channel << 2)	    base_addr[CyLICR] = channel << 2;	if (base_addr[CyLIVR] != 0x5c)	    base_addr[CyLIVR] = 0x5c;       /* tx and rx baud rate */	if (base_addr[CyCOR1] != info->cor1)	    need_init_chan = 1;	if (base_addr[CyTCOR] != info->tco)	    base_addr[CyTCOR] = info->tco;	if (base_addr[CyTBPR] != info->tbpr)	    base_addr[CyTBPR] = info->tbpr;	if (base_addr[CyRCOR] != info->rco)	    base_addr[CyRCOR] = info->rco;	if (base_addr[CyRBPR] != info->rbpr)	    base_addr[CyRBPR] = info->rbpr;	/* set line characteristics  according configuration */	if (base_addr[CySCHR1] != START_CHAR(info->tty))	    base_addr[CySCHR1] = START_CHAR(info->tty);	if (base_addr[CySCHR2] != STOP_CHAR(info->tty))	    base_addr[CySCHR2] = STOP_CHAR(info->tty);	if (base_addr[CySCRL] != START_CHAR(info->tty))	    base_addr[CySCRL] = START_CHAR(info->tty);	if (base_addr[CySCRH] != START_CHAR(info->tty))	    base_addr[CySCRH] = START_CHAR(info->tty);	if (base_addr[CyCOR1] != info->cor1)	    base_addr[CyCOR1] = info->cor1;	if (base_addr[CyCOR2] != info->cor2)	    base_addr[CyCOR2] = info->cor2;	if (base_addr[CyCOR3] != info->cor3)	    base_addr[CyCOR3] = info->cor3;	if (base_addr[CyCOR4] != info->cor4)	    base_addr[CyCOR4] = info->cor4;	if (base_addr[CyCOR5] != info->cor5)	    base_addr[CyCOR5] = info->cor5;	if (base_addr[CyCOR6] != info->cor6)	    base_addr[CyCOR6] = info->cor6;	if (base_addr[CyCOR7] != info->cor7)	    base_addr[CyCOR7] = info->cor7;	if (need_init_chan)	    write_cy_cmd(base_addr,CyINIT_CHAN);	base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */	/* 2ms default rx timeout */	ti = info->default_timeout ? info->default_timeout : 0x02;	if (base_addr[CyRTPRL] != ti)	    base_addr[CyRTPRL] = ti;	if (base_addr[CyRTPRH] != 0)	    base_addr[CyRTPRH] = 0;	/* Set up RTS here also ????? RGH 141095 */	if(i == 0){ /* baud rate is zero, turn off line */	    if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)	        base_addr[CyMSVR2] = 0;#ifdef SERIAL_DEBUG_DTR            printk("cyc: %d: dropping DTR\n", __LINE__);            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif	}else{	    if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)	        base_addr[CyMSVR2] = CyDTR;#ifdef SERIAL_DEBUG_DTR            printk("cyc: %d: raising DTR\n", __LINE__);            printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif	}	if (info->tty){	    clear_bit(TTY_IO_ERROR, &info->tty->flags);	}    local_irq_restore(flags);} /* config_setup */static voidcy_put_char(struct tty_struct *tty, unsigned char ch){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  unsigned long flags;#ifdef SERIAL_DEBUG_IO    printk("cy_put_char %s(0x%02x)\n", tty->name, ch);#endif    if (serial_paranoia_check(info, tty->name, "cy_put_char"))	return;    if (!tty || !info->xmit_buf)	return;    local_irq_save(flags);	if (info->xmit_cnt >= PAGE_SIZE - 1) {	    local_irq_restore(flags);	    return;	}	info->xmit_buf[info->xmit_head++] = ch;	info->xmit_head &= PAGE_SIZE - 1;	info->xmit_cnt++;    local_irq_restore(flags);} /* cy_put_char */static voidcy_flush_chars(struct tty_struct *tty){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  unsigned long flags;  volatile unsigned char *base_addr = (u_char *)BASE_ADDR;  int channel;				#ifdef SERIAL_DEBUG_IO    printk("cy_flush_chars %s\n", tty->name); /* */#endif    if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))	return;    if (info->xmit_cnt <= 0 || tty->stopped    || tty->hw_stopped || !info->xmit_buf)	return;    channel = info->line;    local_irq_save(flags);	base_addr[CyCAR] = channel;	base_addr[CyIER] |= CyTxMpty;    local_irq_restore(flags);} /* cy_flush_chars *//* This routine gets called when tty_write has put something into    the write_queue.  If the port is not already transmitting stuff,    start it off by enabling interrupts.  The interrupt service    routine will then ensure that the characters are sent.  If the    port is already active, there is no need to kick it. */static intcy_write(struct tty_struct * tty, int from_user,           const unsigned char *buf, int count){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  unsigned long flags;  int c, total = 0;#ifdef SERIAL_DEBUG_IO    printk("cy_write %s\n", tty->name); /* */#endif    if (serial_paranoia_check(info, tty->name, "cy_write")){	return 0;    }	    if (!tty || !info->xmit_buf || !tmp_buf){        return 0;    }    if (from_user) {	    down(&tmp_buf_sem);	    while (1) {		    c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,					      SERIAL_XMIT_SIZE - info->xmit_head));		    if (c <= 0)			    break;		    c -= copy_from_user(tmp_buf, buf, c);		    if (!c) {			    if (!total)				    total = -EFAULT;			    break;		    }		    local_irq_save(flags);		    c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,					  SERIAL_XMIT_SIZE - info->xmit_head));		    memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);		    info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);		    info->xmit_cnt += c;		    local_irq_restore(flags);		    buf += c;		    count -= c;		    total += c;	    }	    up(&tmp_buf_sem);    } else {	    while (1) {		    local_irq_save(flags);		    c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,					      SERIAL_XMIT_SIZE - info->xmit_head));		    if (c <= 0) {			    local_irq_restore(flags);			    break;		    }		    memcpy(info->xmit_buf + info->xmit_head, buf, c);		    info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);		    info->xmit_cnt += c;		    local_irq_restore(flags);		    buf += c;		    count -= c;		    total += c;	    }    }    if (info->xmit_cnt    && !tty->stopped    && !tty->hw_stopped ) {        start_xmit(info);    }    return total;} /* cy_write */static intcy_write_room(struct tty_struct *tty){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  int	ret;				#ifdef SERIAL_DEBUG_IO    printk("cy_write_room %s\n", tty->name); /* */#endif    if (serial_paranoia_check(info, tty->name, "cy_write_room"))	return 0;    ret = PAGE_SIZE - info->xmit_cnt - 1;    if (ret < 0)	ret = 0;    return ret;} /* cy_write_room */static intcy_chars_in_buffer(struct tty_struct *tty){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;				#ifdef SERIAL_DEBUG_IO    printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */#endif    if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))	return 0;    return info->xmit_cnt;} /* cy_chars_in_buffer */static voidcy_flush_buffer(struct tty_struct *tty){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  unsigned long flags;				#ifdef SERIAL_DEBUG_IO    printk("cy_flush_buffer %s\n", tty->name); /* */#endif    if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))	return;    local_irq_save(flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;    local_irq_restore(flags);    tty_wakeup(tty);} /* cy_flush_buffer *//* This routine is called by the upper-layer tty layer to signal   that incoming characters should be throttled or that the   throttle should be released. */static voidcy_throttle(struct tty_struct * tty){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  unsigned long flags;  volatile unsigned char *base_addr = (u_char *)BASE_ADDR;  int channel;#ifdef SERIAL_DEBUG_THROTTLE  char buf[64];	    printk("throttle %s: %d....\n", tty_name(tty, buf),	   tty->ldisc.chars_in_buffer(tty));    printk("cy_throttle %s\n", tty->name);#endif    if (serial_paranoia_check(info, tty->name, "cy_nthrottle")){	    return;    }    if (I_IXOFF(tty)) {	info->x_char = STOP_CHAR(tty);	    /* Should use the "Send Special Character" feature!!! */    }    channel = info->line;    local_irq_save(flags);	base_addr[CyCAR] = (u_char)channel;	base_addr[CyMSVR1] = 0;    local_irq_restore(flags);    return;} /* cy_throttle */static voidcy_unthrottle(struct tty_struct * tty){  struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;  unsigned long flags;  volatile unsigned char *base_addr = (u_char *)BASE_ADDR;  int channel;#ifdef SERIAL_DEBUG_THROTTLE  char buf[64];	    printk("throttle %s: %d....\n", tty_name(tty, buf),	   tty->ldisc.chars_in_buffer(tty));    printk("cy_unthrottle %s\n", tty->name);#endif    if (serial_paranoia_check(info, tty->name, "cy_nthrottle")){	    return;    }    if (I_IXOFF(tty)) {	info->x_char = START_CHAR(tty);	/* Should use the "Send Special Character" feature!!! */    }    channel = info->line;    local_irq_save(flags);	base_addr[CyCAR] = (u_char)channel;	base_addr[CyMSVR1] = CyRTS;    local_irq_restore(flags);    return;} /* cy_unthrottle */static intget_serial_info(struct cyclades_port * info,                           struct serial_struct * retinfo){  struct serial_struct tmp;/* CP('g'); */    if (!retinfo)            return -EFAULT;    memset(&tmp, 0, sizeof(tmp));    tmp.type = info->type;    tmp.line = info->line;    tmp.port = info->line;    tmp.irq = 0;    tmp.flags = info->flags;

⌨️ 快捷键说明

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