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