📄 read.c
字号:
/** read.c * * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de * Version 1.0 04 Feb 2003 */#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#define EXPORT_SYMTAB#include "../include/candrv.h"#include "../include/hms30c7202_can.h"#include "../include/c_can.h"////////////////////////////////////////////////////////////////////////////////* * can_read * * Read function called by user through device file. User gets the specified * number of messages from the fifo of the message object. */ssize_t can_read( struct file *filp, char *buffer, size_t length, loff_t *offset){ struct msgobj_t *pmsgobj; struct canmsg_t read_msg; int ret=0; if ( offset != &filp->f_pos ) return -ESPIPE; if ( length < sizeof( struct canmsg_t )) { CANMSG("Trying to read less bytes than a CAN message,"); CANMSG("this will always return zero."); return 0; } if ( NULL == ( pmsgobj = filp->private_data )) { CANMSG("Device is not correctly configured."); CANMSG("Please reload the driver."); return -1; } if (!(pmsgobj->hostchip->flags & CHANNEL_CONFIGURED)) { CANMSG("Device is not correctly configured, please reopen."); return -1; } /* Copy one message from userspace, to find out if a RTR-Frame should be sent. */ copy_from_user( &read_msg, buffer, sizeof(struct canmsg_t) ); if ( read_msg.flags & MSG_RTR ) ret = can_rtr_read( pmsgobj, buffer); else ret = can_std_read( filp, pmsgobj, buffer, length ); return ret;}////////////////////////////////////////////////////////////////////////////////* * can_std_read * * This is the 'Normal' read handler for normal transmission messages */inline ssize_t can_std_read( struct file *filp, struct msgobj_t *pmsgobj, char *buffer, size_t length ){ int ret = 0; int bytes_to_read = length; unsigned long irqflags; if ( NULL == pmsgobj ) return 0; spin_lock_irqsave( &pmsgobj->hostchip->sprlock, irqflags ); /* Logic for Circular buffer ========================= empty if rxrp == rxwp full if abs( rxrp - rxwp ) == 1 */ while ( pmsgobj->fifo->rxrp == pmsgobj->fifo->rxwp ) { /* Receive buffer is empty */ spin_unlock_irqrestore( &pmsgobj->hostchip->sprlock, irqflags ); if ( filp->f_flags & O_NONBLOCK ) { DEBUGMSG("Non Blocking read. Returning EAGAIN"); return -EAGAIN; } pmsgobj->rv = 0; /* Wait for messages. */ if ( wait_event_interruptible( pmsgobj->fifo->readq, ( pmsgobj->fifo->rxrp != pmsgobj->fifo->rxwp ))) { return -ERESTARTSYS; } if ( pmsgobj->rv < 0 ) { return pmsgobj->rv; } spin_lock_irqsave( &pmsgobj->hostchip->sprlock, irqflags ); } /* Calculate number of messages to be transfered */ /* write pointer behind read pointer */ if ( pmsgobj->fifo->rxwp > pmsgobj->fifo->rxrp ) { bytes_to_read = min( bytes_to_read, pmsgobj->fifo->rxwp - pmsgobj->fifo->rxrp ); /* Copy messages to userspace */ if ( copy_to_user( buffer, pmsgobj->fifo->rxrp, bytes_to_read )) { DEBUGMSG( "Failed to copy data to user space. b=%lx p=%lx %d", ( unsigned long )buffer, ( unsigned long )pmsgobj->fifo->rxrp, bytes_to_read); spin_unlock_irqrestore( &pmsgobj->hostchip->->sprlock, irqflags ); return -EFAULT; } /* Remove messages from buffer */ pmsgobj->fifo->rxrp += bytes_to_read; ret = bytes_to_read; if ( pmsgobj->fifo->rxrp >= ( pmsgobj->fifo->prxbuf + pmsgobj->fifo->rxsize ) ) { pmsgobj->fifo->rxrp = pmsgobj->fifo->prxbuf; /* wrapped */ } /* write pointer before read pointer */ } else { /* The write pointer has wrapped, return data up to end */ bytes_to_read = min( bytes_to_read, pmsgobj->fifo->prxbuf + pmsgobj->fifo->rxsize - pmsgobj->fifo->rxrp ); /* Copy messages to userspace */ if ( copy_to_user( buffer, pmsgobj->fifo->rxrp, bytes_to_read )) { DEBUGMSG( "Failed to copy data to user space. b=%lx p=%lx %d", ( unsigned long )buffer, ( unsigned long )pmsgobj->fifo->rxrp, bytes_to_read); spin_unlock_irqrestore( &pmsgobj->hostchip->->sprlock, irqflags ); return -EFAULT; } /* Remove messages from buffer */ pmsgobj->fifo->rxrp += bytes_to_read; ret = bytes_to_read; if ( pmsgobj->fifo->rxrp >= ( pmsgobj->fifo->prxbuf + pmsgobj->fifo->rxsize ) ) { pmsgobj->fifo->rxrp = pmsgobj->fifo->prxbuf; /* wrapped */ } /* all requested bytes read ? */ if ( length > bytes_to_read ) { /* move forward pointer to user buffer */ buffer += bytes_to_read; /* calc new byte count */ bytes_to_read = min( (int)length - bytes_to_read, pmsgobj->fifo->rxwp - pmsgobj->fifo->prxbuf ); /* Copy messages to userspace */ if ( copy_to_user( buffer, pmsgobj->fifo->rxrp, bytes_to_read )) { DEBUGMSG( "Failed to copy data to user space. b=%lx p=%lx %d", ( unsigned long )buffer, ( unsigned long )pmsgobj->fifo->rxrp, bytes_to_read); spin_unlock_irqrestore( &pmsgobj->hostchip->->sprlock, irqflags ); return -EFAULT; } /* Remove messages from buffer */ pmsgobj->fifo->rxrp += bytes_to_read; ret += bytes_to_read; } } spin_unlock_irqrestore( &pmsgobj->sprlock, irqflags ); return ret;}////////////////////////////////////////////////////////////////////////////////* * can_rtr_read * * This is the 'RTR' read handler for remote transmission request messages */inline ssize_t can_rtr_read( struct msgobj_t *pmsgobj, char *buffer ){ unsigned long flags; struct rtr_id *prtr_current = NULL, *pnew_rtr_entry = NULL; struct canmsg_t read_msg; return -ERESTARTSYS; if ( NULL == pmsgobj ) return 0; DEBUGMSG("Remote transmission request"); spin_lock_irqsave( &pmsgobj->hostchip->rtr_lock, flags); // Add element to the RTR-Queue if ( pmsgobj->hostchip->prtr_queue == NULL ) { //No remote messages pending pnew_rtr_entry = (struct rtr_id *)kmalloc( sizeof( struct rtr_id), GFP_ATOMIC); if ( NULL == pnew_rtr_entry ) { spin_unlock_irqrestore( &pmsgobj->hostchip->rtr_lock, flags); return -ENOMEM; } pmsgobj->hostchip->prtr_queue = pnew_rtr_entry; } else { prtr_current = pmsgobj->hostchip->prtr_queue; while ( prtr_current->next != NULL ) prtr_current = prtr_current->next; pnew_rtr_entry = (struct rtr_id *)kmalloc( sizeof( struct rtr_id ), GFP_ATOMIC); prtr_current->next = pnew_rtr_entry; } init_waitqueue_head( &pnew_rtr_entry->rtr_wq ); pnew_rtr_entry->id = read_msg.id; pnew_rtr_entry->rtr_message = &read_msg; pnew_rtr_entry->next = NULL; spin_unlock_irqrestore( &pmsgobj->hostchip->rtr_lock, flags ); // Send remote transmission request pmsgobj->hostchip->remote_request( pmsgobj ); pmsgobj->rv = 0; // Wait for reception of the answer interruptible_sleep_on( &pnew_rtr_entry->rtr_wq ); // Copy answer into userspace spin_lock_irqsave( &pmsgobj->hostchip->rtr_lock, flags ); copy_to_user( buffer, &read_msg, sizeof(struct canmsg_t) ); // Remove element from RTR-Queue if ( pmsgobj->hostchip->prtr_queue == pnew_rtr_entry ) { if ( pnew_rtr_entry->next != NULL ) pmsgobj->hostchip->prtr_queue = pnew_rtr_entry->next; else pmsgobj->hostchip->prtr_queue = NULL; } else { prtr_current = pmsgobj->hostchip->prtr_queue; while ( prtr_current->next != pnew_rtr_entry ) prtr_current = prtr_current->next; if ( pnew_rtr_entry->next != NULL ) prtr_current->next = pnew_rtr_entry->next; else prtr_current->next = NULL; } spin_unlock_irqrestore( &pmsgobj->hostchip->rtr_lock, flags); kfree( pnew_rtr_entry ); return pmsgobj->rv;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -