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

📄 can200.c

📁 This version 0.2 of driver for a simple CAN bus interface. 一个CAN 总线接口程序
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif{        int bytes_read = 0;        int iii;        unsigned char msg[ CAN_MSG_LEN ];        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)        /* Don't use pread()/pwrite() system calls */        if ( offset != &file->f_pos )                return -ESPIPE;#endif        can_ena_irq( 0 );        if ( stuck_interrupt() ) { /* happens sometimes */                unsigned char can_ir = can_get_reg( CAN_IR ) & 0x1F;                can_irq_service( can_ir );                //printk( "can200_read(), can_ir = 0x%02x\n", can_ir);        }        can_ena_irq( 1 );        /* each read call gives one CAN msg */        if ( length < CAN_MSG_LEN )                return -EINVAL;                /* If there is no message, sleep until we got a message */        while ( 0 == RdFifo.size ) {                /* CAN bus error occured */                if ( can_is_resetted() )                        return -EIO;                                /* if opened nonblocking, return error (try again!)*/                if ( file->f_flags & O_NONBLOCK )                        return -EAGAIN;                /* This function puts the current process,                 * including any system calls, such as us, to sleep.                 * Execution will be resumed right after the function                 * call, either because somebody called                 * wake_up(&WaitQ) (only interrupt does that)                 * or when a signal, such as Ctrl-C,                 * is sent to the process                 */                                module_interruptible_sleep_on(&RdWaitQ);                /* If we woke up because we got a signal we're not                 * blocking, return  -EINTR (fail the system call).                 * This allows processes to be killed or stopped.                 */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)                if ( signal_pending( current ) )                        return -EINTR;#else                if ( current->signal & ~current->blocked )                        return -EINTR;#endif        }        /* Actually put one msg from fifo into the driver buffer */        can_ena_irq( 0 );        for ( iii = 0; iii < CAN_MSG_LEN; iii++ ) {                msg[iii] = RdFifo.buffer[RdFifo.tail];                RdFifo.tail++;                RdFifo.tail %= RD_FIFO_LEN; /* wrap around pointer */                RdFifo.size--;        }        /* enable CAN irq in case buffer is paged out */        can_ena_irq( 1 );                /* transfer the message into the user space */        for ( iii = 0; iii < CAN_MSG_LEN; iii++ ) {                put_user( msg[iii], buffer++ );                length --;                bytes_read ++;        }                /* fill with zero bytes */        while (length ) {                put_user( 0x00, buffer++ );                length --;                bytes_read ++;        }        return bytes_read;}/*******************************************************************//*******************************************************************//*******************************************************************/#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)static ssize_t can200_write(struct file *file,                            const char *buffer,    /* The buffer */                            size_t length,   /* The length of the buffer */                            loff_t *offset)  /* Our offset in the file */#elsestatic int can200_write(struct inode *inode,                        struct file *file,                        const char *buffer,                        int length)#endif{        int iii;        unsigned char msg[ CAN_MSG_LEN ];#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)        /* Don't use pread()/pwrite() system calls */        if ( offset != &file->f_pos )                return -ESPIPE;#endif        can_ena_irq( 0 );        if ( stuck_interrupt() ) {                int can_ir;                can_ir = can_get_reg( CAN_IR ) & 0x1F;                //printk( "can200_write(), can_ir = 0x%02x\n", can_ir);                can_irq_service( can_ir );        }        can_ena_irq( 1 );        /* CAN bus error occured */        if ( can_is_resetted() )                return -EIO;                        /* each read call give one CAN msg */        if ( length < CAN_MSG_LEN )                return -EINVAL;                /* Actually put the data into the driver buffer */        for ( iii = 0; iii < CAN_MSG_LEN; iii++ )  {                get_user( msg[iii], buffer++ );        }        /* No extended CAN frames allowed */        if ( msg[0] & CAN_INFO_EFF )                return -EINVAL;        /* If there is no room for a message, sleep until ready */        while ( WrFifo.size > WR_FIFO_LEN - CAN_MSG_LEN ) { /* fifo full */                /* CAN bus error occured */                if ( can_is_resetted() )                        return -EIO;                                /* if opened nonblocking, return error (try again!)*/                if ( file->f_flags & O_NONBLOCK )                        return -EAGAIN;                /* This function puts the current process,                 * including any system calls, such as us, to sleep.                 * Execution will be resumed right after the function                 * call, either because somebody called                 * wake_up(&WaitQ) (only interrupt does that)                 * or when a signal, such as Ctrl-C,                 * is sent to the process                 */                                module_interruptible_sleep_on(&WrWaitQ);                /* If we woke up because we got a signal we're not                 * blocking, return  -EINTR (fail the system call).                 * This allows processes to be killed or stopped.                 */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)                if ( signal_pending( current ) )                        return -EINTR;#else                if ( current->signal & ~current->blocked )                        return -EINTR;#endif        }        /* critical region         * don't use put/get_user() with disabled can irq here         * buffer may be paged out         */        can_ena_irq( 0 );        for ( iii = 0; iii < CAN_MSG_LEN; iii++ )  {                WrFifo.buffer[WrFifo.head] = msg[iii];                WrFifo.head++;                WrFifo.head %= WR_FIFO_LEN;                WrFifo.size++;        }        if ( WrFifo.size >= CAN_MSG_LEN ) {                /* the fifo is now NOT empty */                WrFifo.status = FIFO_OK;                /* init the first transmission after the fifo was empty */                can_tx_message();        }        can_ena_irq( 1 );                return CAN_MSG_LEN;}/* This function is called whenever a process tries to * do an ioctl on our device file. We get two extra * parameters (additional to the inode and file * structures, which all device functions get): the number * of the ioctl called and the parameter given to the * ioctl function. * * If the ioctl is write or read/write (meaning output * is returned to the calling process), the ioctl call * returns the output of this function. */static int can200_ioctl(                 struct inode *inode,                 struct file *file,                 unsigned int ioctl_num,                 unsigned long ioctl_param){        /* Switch according to the ioctl called */        switch (ioctl_num) {        case IOCTL_SET_SPEED:                can_setup( ioctl_param );                return SUCCESS;        }        return -EINVAL;}/*******************************************************************//*******************************************************************//*******************************************************************//* This structure will hold the functions to be * called when a process does something to the device * we created. Since a pointer to this structure is * kept in the devices table, it can't be local to * init_module. NULL is for unimplemented functions. */struct file_operations Fops = {        NULL,           /* seek */        can200_read,        can200_write,        NULL,           /* readdir */        NULL,           /* select */        can200_ioctl,        NULL,           /* mmap */        can200_open,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)        NULL,           /* flush */#endif        can200_release  /* a.k.a. close */};/*******************************************************************//*******************************************************************//*******************************************************************//* The kernel module interface functions: * init_module() and cleanup_module() *//* Initialize the module, called from insmod / modprobe / kerneld etc. * - find the CAN interface * - register the character device * - request the io region */int init_module( void ){        int retval = 0;                retval = check_region( can200_io, LP_PORT_SIZE );        if ( retval < 0 ) {                printk ("%s: check_region() failed with %d\n",                        DEVICE_NAME,                        retval);                return retval;        }        retval = can_find_chip();        if ( retval < 0 ) {                printk ("%s: can_find_chip() failed with %d\n",                        DEVICE_NAME,                        retval);                return -ENODEV;        }        #ifdef MAJOR_DYNAMIC        can200_major = retval = module_register_chrdev(0,                                                       DEVICE_NAME,                                                       &Fops);#else        retval = module_register_chrdev(can200_major,                                        DEVICE_NAME,                                        &Fops);#endif        /* Negative values signify an error */        if (retval < 0) {                printk ("%s: register_chrdev() failed with %d\n",                        DEVICE_NAME,                        retval);                return retval;        }        request_region( can200_io, LP_PORT_SIZE, DEVICE_NAME );#ifdef USE_EPP_MODE        printk ("%s-%s installed, using EPP mode\n",                DEVICE_NAME, DRIVER_VERSION );#else        printk ("%s-%s installed, using PS/2 mode\n",                DEVICE_NAME, DRIVER_VERSION );#endif        printk( "can200_major = %d\n",                can200_major );        printk( "can200_io = 0x%03x, can200_irq = %d\n",                can200_io, can200_irq );        return 0;}/*******************************************************************//*******************************************************************//*******************************************************************//* Cleanup, called from rmmod */void cleanup_module( void ){        int ret;        can_reset();        release_region( can200_io, LP_PORT_SIZE);        /* Unregister the device */        ret = module_unregister_chrdev(can200_major, DEVICE_NAME);        /* If there's an error, report it */        if (ret < 0)                printk("Error in unregister_chrdev(): %d\n", ret);}

⌨️ 快捷键说明

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