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

📄 can200.c

📁 This version 0.2 of driver for a simple CAN bus interface. 一个CAN 总线接口程序
💻 C
📖 第 1 页 / 共 3 页
字号:
        can_put_reg( CAN_AMR, 0xFF );  // accept all        can_put_reg( CAN_BTR0, btr0 );        can_put_reg( CAN_BTR1, btr1 );        can_put_reg( CAN_OCR, 0x1A ); // normal mode, push/pull        can_put_reg( CAN_CDR, 0 ); // divide by 2        can_put_reg( CAN_CR, CAN_IRQ_ENA );        can_ena_irq( 1 );        return SUCCESS;}/* Check if one or more messages are available in the RX buffer * called from can200_irq with LP irq disabled */static inline int can_rx_status( void ){        return can_get_reg( CAN_SR ) & CAN_RECEIVE_BUFFER_STATUS;}/* Check if the transmit buffer is accessable * called from can200_irq and can200_write with LP irq disabled */static inline int can_tx_status( void ){        return can_get_reg( CAN_SR ) & CAN_TRANSMIT_BUFFER_ACCESS;}/* Check if the controller is resetted */static int can_is_resetted( void ){        int can_cr;        unsigned long flags;        save_flags( flags ); cli();        can_cr = can_get_reg( CAN_CR );        restore_flags( flags );        return can_cr & CAN_RESET_REQUEST;}/*******************************************************************//*******************************************************************//*******************************************************************//* Transmit and receive a complete message * Transfer between CAN RX/TX buffer and fifos *//* called from irq_handler with LP irq disabled */static int can_rx_message( void ){        if ( can_get_reg( CAN_SR ) & CAN_RECEIVE_BUFFER_STATUS ) {                /* message available */                int iii, len;                static unsigned char pad = 0;                can_msg_t *msg;                msg = (can_msg_t *)&RdFifo.buffer[RdFifo.head];                msg->id0 = can_get_reg( CAN_RX + 0 );                msg->id1 = can_get_reg( CAN_RX + 1 );                msg->id2 = 0;                msg->id3 = 0;                                if ( msg->id1 & CAN_ID1_RTR ) {                        msg->info = CAN_INFO_RTR;                        len = 0;                }                else {                        msg->info = len = msg->id1 & CAN_INFO_LEN_MASK;                        if ( len > 8 )                                len = 8;                }                msg->id1 &= ( CAN_ID1_MASK | CAN_ID1_RTR );                for ( iii = 0; iii < len; iii++ )                        msg->data[iii] = can_get_reg( CAN_RX + iii + 2 );                for ( iii = len; iii < 8; iii++ )                        msg->data[iii] = 0;                msg->pad = pad++;                msg->status = SUCCESS;                msg->timestamp = jiffies;                                RdFifo.head += CAN_MSG_LEN;                RdFifo.head %= RD_FIFO_LEN;                                if ( RdFifo.size <= RD_FIFO_LEN-CAN_MSG_LEN ) {                        /* fifo is not full */                        RdFifo.size += CAN_MSG_LEN;                } else {                        /* the oldest msg was overwritten */                        /* mark fifo overflow, not (yet) used */                        RdFifo.status = FIFO_OVERFLOW;                }                //printk( "can_sr = 0x%02x\n", can_get_reg( CAN_SR ) );                /* free the RX buffer, avoid CAN overrun */                can_put_reg( CAN_CMR, CAN_RELEASE_RECEIVE_BUFFER );                return 1;        } else                return 0;}/* called from irq_handler AND from can200_write with LP irq disabled */static int can_tx_message( void ){        if ( can_get_reg( CAN_SR ) & CAN_TRANSMIT_BUFFER_ACCESS ) {                /* transmit buffer is available */                if ( WrFifo.size >= CAN_MSG_LEN ) {                        /* there is at least one message */                        int iii, len;                        can_msg_t *msg;                        msg = (can_msg_t *)&WrFifo.buffer[WrFifo.tail];                        msg->id1 &= CAN_ID1_MASK;                        msg->id1 |= ( msg->info & CAN_INFO_LEN_MASK);                        if ( msg->info & CAN_INFO_RTR ) {                                msg->id1 |= CAN_ID1_RTR;                                len = 0;                        } else {                                len = msg->info & CAN_INFO_LEN_MASK;                                if ( len > 8 )                                        len = 8;                        }                        can_put_reg( CAN_TX + 0, msg->id0 );                        can_put_reg( CAN_TX + 1, msg->id1 );                        for ( iii = 0; iii < len; iii++ )                                can_put_reg( CAN_TX + iii + 2,                                             msg->data[iii] );                        WrFifo.size -= CAN_MSG_LEN;                        WrFifo.tail += CAN_MSG_LEN;                        WrFifo.tail %= WR_FIFO_LEN;                        can_put_reg( CAN_CMR, CAN_TRANSMISSION_REQUEST );                        return 1;                } else {                        /* The fifo is now REALLY empty                         * this was the last TX interrupt unless we                         * restart the transfer.                         */                        WrFifo.status = FIFO_EMPTY;                        return 0;                }        }        else                return 0;}/*******************************************************************//*******************************************************************//*******************************************************************//* Sometimes an interrupt was not serviced by the irq_handler. * I don't know if it's a buggy parallel port or a bad cable. * So I check in can200_read() and can200_write() if there is an * interrupt pending and call the can_irq_service(). */static void can_irq_service( int can_ir ) {        int got_message = 0;                /* ========== error interrupt */        if ( can_ir & CAN_ERROR_INT ) {                /* We got a can bus error.                 * Reset the controller and                 * wake up all sleeping processes.                 * The processes will return with -EIO                 */                unsigned char can_sr = can_get_reg( CAN_SR );                printk( "can200 error, status reg = 0x%02x\n", can_sr );                can_reset();                                /* the error should be handled in the user program */                //can_setup( Minor & 0x0f );                /* wake up sleeping user program, return with EIO */                module_wake_up(&RdWaitQ);                module_wake_up(&WrWaitQ);                return;        }        /* ========== receive interrupt */        /* get all pending messages */        while ( can_rx_message() )                got_message++;        /* wake up the process blocked by read (if data available)*/        if ( got_message )                module_wake_up(&RdWaitQ);        /* ========== transmit interrupt */        /* transmit the next message */        if ( can_tx_message() )                /* wake up the process blocked by write */                module_wake_up(&WrWaitQ);}/* INTERRUPT HANDLER *//* LP irq is disabled */static void can200_irq_handler( int irq, void *dev_id, struct pt_regs *regs ){        unsigned char can_ir;        if ( (can_ir = can_get_reg( CAN_IR ) ) & 0x1F ) {                can_irq_service( can_ir );        }}/*******************************************************************//*******************************************************************//*******************************************************************/static int can200_open(struct inode *inode,                       struct file *file){        int err;        /* We don't want to talk to two processes at the same time */        if ( MOD_IN_USE )                return -EBUSY;        Minor = inode->i_rdev & 0xFF; // major = inode->i_rdev >> 8;        err = can_setup( Minor & 0x0f ); /* Bitrate 10, 20, ... */        if ( err < 0 ) {                printk ("%s: can_setup) failed with %d\n",                        DEVICE_NAME,                        err);                return err;        }                can_init_fifos();        err = request_irq(LP_IRQ,                          can200_irq_handler,                          0, /* or SA_INTERRRUPT or SH_INTERRUPT */                          DEVICE_NAME,                          NULL);        if ( err < 0 ) {                printk ("%s: request_irq() failed with %d\n",                        DEVICE_NAME,                        err);                return err;        }        MOD_INC_USE_COUNT;        return SUCCESS;}/*******************************************************************//*******************************************************************//*******************************************************************//* This function is called when a process closes the * device file. It doesn't have a return value in * version 2.0.x because it can't fail (you must ALWAYS * be able to close a device). In version 2.2.x it is * allowed to fail - but we won't let it. */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)static int can200_release(struct inode *inode,                          struct file *file)#elsestatic void can200_release(struct inode *inode,                           struct file *file)#endif{        /* If there are messages pending,         * sleep until ready, timed out or error.         * The longest CAN message is about 130 bits,         * at 20 kBit/s -> 6.5 ms.         * Transmitting the full fifo (100 msg) takes         * 0.65 seconds at bus idle.         * A timeout of 2 seconds should be ok.         */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)        long timeout = 2*HZ;#else        current->timeout = jiffies + (2*HZ);#endif        //printk( "can200_close()\n" );        while ( ( WrFifo.status != FIFO_EMPTY ) ) {                /* CAN bus error occured ? */                if ( can_is_resetted() )                        break;                #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)                timeout = interruptible_sleep_on_timeout( &WrWaitQ, timeout );                if ( 0 == timeout )                        break; /* timed out */                if ( signal_pending( current ) )                        break; /* interrupted */#else                interruptible_sleep_on( &WaitQ );                if ( 0 == current->timeout )                        break; /* timed out */                if ( current->signal & ~current->blocked )                        break; /* interrupted */#endif        }        can_reset();        free_irq( LP_IRQ, NULL );        MOD_DEC_USE_COUNT;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)        return 0;#endif}/*******************************************************************//*******************************************************************//*******************************************************************/#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)static ssize_t can200_read(struct file *file,                           char *buffer,                           size_t length,                           loff_t *offset)#elsestatic int can200_read(struct inode *inode,                       struct file *file,                       char *buffer,                       int length)

⌨️ 快捷键说明

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