📄 can200.c
字号:
#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 + -