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

📄 rt_com.c

📁 fsmlabs的real time linux的内核
💻 C
📖 第 1 页 / 共 2 页
字号:
	}    }    return( done );}/** Get first byte from the write buffer. * * @param p  rt_com_struct of the line we are writing to. * @param c  Address to put the char in. * @return   Number of characters we actually got. * * @author Jens Michaelsen, Jochen K黳per * @version 1999/10/01 */static inline int rt_com_irq_get( struct rt_com_struct *p, unsigned char *c ){    struct rt_buf_struct *b = &( p->obuf );    if( b->head != b->tail ) {	*c = b->buf[ b->tail++ ];	b->tail &= ( RT_COM_BUF_SIZ - 1 );	return( 1 );    }    return( 0 );}/** Concatenate a byte to the read buffer. * * @param p   rt_com_struct of the line we are writing to. * @param ch  Byte to put into buffer. * * @author Jens Michaelsen, Jochen K黳per * @version 1999/07/20 */static inline void rt_com_irq_put( struct rt_com_struct *p, unsigned char ch ){    struct rt_buf_struct *b = &( p->ibuf );    b->buf[ b->head++ ] = ch;    b->head &= ( RT_COM_BUF_SIZ - 1 );}/** Registered interrupt handlers. * * These simply call the general interrupt handler for the current * line to do the work. * * @author Jens Michaelsen, Jochen K黳per, Hua Mao * @version 1999/11/11 */#if defined RTLINUX_V1 || defined RTAIstatic void rt_com0_isr( void ){    rt_com_isr( 0 );}static void rt_com1_isr( void ){    rt_com_isr( 1 );}#elsestatic unsigned int rt_com0_isr( unsigned int num, struct pt_regs *r ){    return rt_com_isr( 0, NULL );}static unsigned int rt_com1_isr( unsigned int num, struct pt_regs *r ){    return rt_com_isr( 1, NULL );}#endif/** Real interrupt handler. * * Called by the registered ISRs to do the actual work. * * @param com Port to use corresponding to internal numbering scheme. * * @author Jens Michaelsen, Jochen K黳per, Hua Mao, Renoldi Giuseppe * @version 2000/10/02 */#if defined RTLINUX_V1 || defined RTAIstatic inline void rt_com_isr( unsigned int com )#elseunsigned int rt_com_isr( unsigned int com, struct pt_regs *r )#endif{    struct rt_com_struct *p = &(rt_com_table[com]);    struct rt_buf_struct *b = &(p->ibuf); //!!    unsigned int B = p->port;    unsigned char data, sta;    int buff,t;    char loop = 4;    char toFifo = 16;    int rxd_bytes = 0;    do {	/* get available data from port */	sta = inb( B + RT_COM_LSR );	if( 0x1e & sta)	    p->error = sta & 0x1e;	while( RT_COM_DATA_READY & sta ) {	    data = inb( B + RT_COM_RXB );	    rt_com_irq_put( p, data );	    rxd_bytes = 1;	    sta = inb( B + RT_COM_LSR );	    if( 0x1e & sta )		p->error = sta & 0x1e;	}	/* controls on buffer full and RTS clear on hardware flow control */	buff = rt_com_buff_free( b->head, b->tail );	if (buff < RT_COM_BUF_FULL)	    p->error = RT_COM_BUFFER_FULL;	if ( ( p->mode & 0x02 ) && ( buff < RT_COM_BUF_LOW ) ) {	    p->mcr &= ~0x02;	    outb( p->mcr, p->port+RT_COM_MCR );	}	/* if possible, put data to port */	sta = inb( B + RT_COM_MSR );	if ( ( ( 0x20 & sta )	       && ( ( 0x10 & sta ) || ( 0 == ( p->mode & 0x02 ) ) ) ) || ( p->mode & 0x01 ) ) {	    /* (DSR && (CTS || Mode==no hw flow)) or Mode==no hand shake */            if ( ( sta = inb(B + RT_COM_LSR) ) & 0x20 ) { // if (THRE==1) i.e. transmitter empty	    	if( 0 != ( t = rt_com_irq_get( p, &data ) ) ) { /* if data in output buffer */		    do {			outb( data, B + RT_COM_TXB );		    } while( ( --toFifo > 0 ) && ( 0 != ( t = rt_com_irq_get( p, &data ) ) ) );		}		if( ! t ) {		    /* no more data in output buffer, disable Transmitter Holding Register Empty Interrupt */		    p->ier &= ~0x02;		    outb( p->ier, B + RT_COM_IER );	        }	    }	}      /* check the low nibble of IIR to check if there is another pending interrupt */      /* Note: why is it done at most 4 times ? */    } while( 1 != ( ( inb( B + RT_COM_IIR ) & 0x0f ) ) && ( --loop > 0 ) );    if (rxd_bytes) {	/* We received 1+ bytes. If user requested a callback, invoke it. */	if (p->callback)	    (*(p->callback)) (com);    }#if defined RTLINUX_V1 || defined RTAI    return;#else    rtl_hard_enable_irq( p->irq );    return 0;#endif}/** Setup one port * * Calls from init_module + cleanup_module have baud == 0; in these * cases we only do some cleanup. * * To allocate a port, give usefull setup parameter, to deallocate * give negative baud. * * @param com        Number corresponding to internal port numbering scheme. *                   This is esp. the index of the rt_com_table to use. * @param baud       Data transmission rate to use [Byte/s]. * @param parity     Parity for transmission protocol. *                   (RT_COM_PARITY_EVEN, RT_COM_PARITY_ODD or RT_COM_PARITY_NONE) * @param stopbits   Number of stopbits to use. 1 gives you one stopbit, 2 *                   actually gives really two stopbits for wordlengths of *                   6 - 8 bit, but 1.5 stopbits for a wordlength of 5 bits. * @param wordlength Number of bits per word (5 - 8 bits). * @return           -1 if error, 0 if all right * * @author Jens Michaelsen, Jochen K黳per * @version 1999/07/20 */int rt_com_setup( unsigned int com, int baud, unsigned int parity,		  unsigned int stopbits, unsigned int wordlength ){    if ( com < RT_COM_CNT ) {  //!!	struct rt_com_struct  *p = &( rt_com_table[ com ] );	unsigned int base = p->port, divider, par = parity;	if( 0 == p->used )	    return( -EBUSY );	/* Stop everything, set DLAB */	outb( 0x00, base + RT_COM_IER );	outb( 0x80, base + RT_COM_LCR );	/* clear irq */	inb( base + RT_COM_IIR );	inb( base + RT_COM_LSR );	inb( base + RT_COM_RXB );	inb( base + RT_COM_MSR );	p->error = 0; //!! init. last error code	p->callback = 0;	if( 0 == baud ) {	    /* return */	} else if( 0 > baud ) {	    MOD_DEC_USE_COUNT;	} else {	    MOD_INC_USE_COUNT;	    divider = p->baud_base / baud;	    outb( divider % 256, base + RT_COM_DLL );	    outb( divider / 256, base + RT_COM_DLM );	    /* bits 3,4 + 5 determine parity - clear all other bits */	    par &= 0x38;	    /* set transmission parameters and clear DLAB */	    outb( ( wordlength - 5 ) + ( ( stopbits - 1 ) << 2 ) + par, base + RT_COM_LCR );	    p->mcr = RT_COM_DTR + RT_COM_RTS + RT_COM_Out1 + RT_COM_Out2;	    outb( p->mcr , base + RT_COM_MCR );	    if (p->mode & 0x01) p->ier = 0x05; /* if no hs signals enable only receiver interrupts  */	    else p->ier = 0x0D;                /* else enable receiver and modem interrupts */	    outb( p->ier, base + RT_COM_IER );	    rt_com_enable_fifo( base, RT_COM_FIFO_TRIGGER, 0 );	    p->used |= 0x02; /* mark setup done */	}	return( 0 );    }    return( -ENODEV );}/** Optional callback function. * * If the user supplies a callback function, it is called whenever * characters are received. * * *** NOTE *** The callback function is called in the context of the * interrupt handler! * * @param com	Port to use; corresponding to internal numbering scheme. * @param fn	Callback function (0 = de-register callback function). * @return	Pointer to previously-installed callback function. * * @author James Puttick * @version 2000/02/08 */IRQ_CALLBACK_FN rt_com_set_callback (unsigned int com, IRQ_CALLBACK_FN fn){    struct rt_com_struct *p;    IRQ_CALLBACK_FN	old_fn;    if( com >= RT_COM_CNT )	return( 0 );    p = &( rt_com_table[ com ] );    old_fn = p->callback;    p->callback = fn;    return( old_fn );}/** Port and irq setting for a specified COM. * * This must run in standard Linux context ! * * @param com    Port to use; corresponding to internal numbering scheme. * @param port   port address, if zero, use standard value from rt_com_table, *               if negative, deinitialize. * @param irq    irq address, if zero, use standard value from rt_com_table * @return       0 if all right, -1 if port is used yet, -2 if error on port region request * * @author Roberto Finazzi * @version 1999/10/31 */int rt_com_set_param( unsigned int com, int port, int irq ){    if( com >= RT_COM_CNT ) {	return( -ENODEV );    } else {	struct rt_com_struct *p = &( rt_com_table[ com ] );	if( 0 == p->used ) {	    if( 0 != port )		p->port = port;	    if( 0 != irq )		p->irq = irq;	    if( -EBUSY == check_region( p->port, 8 ) ) {		return( -EBUSY );	    }	    request_region( p->port, 8, "rt_com" );	    rt_com_request_irq( p->irq, p->isr );	    rt_com_setup( com, 0, 0, 0, 0 );	    p->used = 1;	} else {	    if( 0 > port ) {		rt_com_setup( com, 0, 0, 0, 0 );		rt_com_free_irq( p->irq );		release_region( p->port, 8 );		p->used = 0;	    } else {		return( -EBUSY );	    }	}    }    return( 0 );}/** Initialization * * Request port memory and register ISRs, if we cannot get the memory * of all ports, release all already requested ports and return an * error. * * @return Success status, zero on success. * * @author Jochen K黳per, Hua Mao * @version 2000/05/05 */int init_module( void ){    struct rt_com_struct *p;    int errorcode = 0, i, j;    for( i=0; i<RT_COM_CNT; i++ ) {	p = &( rt_com_table[ i ] );	if( p->used > 0 ) {	    if(-EBUSY == check_region( p->port, 8 ) ) {		errorcode = 1;		break;	    }	    request_region( p->port, 8, "rt_com" );	    rt_com_request_irq( p->irq, p->isr );	    rt_com_setup( i, 0, 0, 0, 0 );	}    }    if( 0 == errorcode ) {	printk( KERN_INFO "rt_com: RT-Linux serial port driver (version "		VERSION ") sucessfully loaded.\n"		KERN_INFO "rt_com: Copyright (C) 1997-2000 Jochen K黳per et al.\n" );    } else {	printk( KERN_WARNING "rt_com: cannot request all port regions,\nrt_com: giving up.\n" );	for( j=0; j<i; j++ ) {	    p = &( rt_com_table[ j ] );	    if( 0 < p->used ) {		rt_com_free_irq( p->irq );		release_region( p->port, 8 );	    }	}    }    return( errorcode );}/** Cleanup * * Unregister ISR and releases memory for all ports * * @author Jochen K黳per, Hua Mao * @version 1999/10/01 */void cleanup_module( void ){    struct rt_com_struct *p;    int i;    for( i=0; i<RT_COM_CNT; i++ ) {	p = &( rt_com_table[ i ] );	if( p->used > 0 ) {	    rt_com_free_irq( p->irq );	    rt_com_setup( i, 0, 0, 0, 0 );	    release_region( p->port, 8 );	}    }    printk( KERN_INFO "rt_com unloaded.\n" );    return;}/** * Local Variables: * mode: C * c-file-style: "Stroustrup" * End: */

⌨️ 快捷键说明

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