Listing 1: read, write, and llseek entry points
ssize_t
RobotArmController_read(struct file * apFile,
char * apBuffer, size_t aLength, loff_t * aOffset)
{
RobotArmControllerData * pDevice = 0;
ssize_t bytesRead = 0;
if( !apFile || !apFile->private_data )
{
printk(KERN_INFO "ERROR in RobotArmController_read: \
NULL input detected.\n");
return -EINVAL;
}
pDevice = apFile->private_data;
if( pDevice->mOffset > *aOffset )
{ *aOffset = pDevice->mOffset;
}
if( *aOffset >= pDevice->mSize )
{
*aOffset = 0;
pDevice->mOffset = *aOffset;
return 0;
}
if (down_interruptible(&gSem))
{
printk(KERN_INFO "Error in RobotArmController_read, \
down_interruptible call.\n");
return -ERESTARTSYS;
}
if (copy_to_user(apBuffer, &pDevice->mpBuffer[*aOffset],
pDevice->mSize - *aOffset))
{
printk(KERN_INFO "Error in RobotArmController_read, \
copy_from_user routine.\n");
up(&gSem);
return -EFAULT;
}
bytesRead = pDevice->mSize - *aOffset;
*aOffset += bytesRead;
pDevice->mOffset = *aOffset;
up(&gSem);
return bytesRead;
}
ssize_t
RobotArmController_write( struct file * apFile,
const char * apBuffer,
size_t aLength,
loff_t * aOffset)
{
RobotArmControllerData * pDevice = 0;
if( !apFile || !apFile->private_data )
{
printk(KERN_INFO "ERROR in RobotArmController_write: \
NULL input detected.\n");
return -EINVAL;
}
pDevice = apFile->private_data;
if( aLength > MAX_FULL_DRIVER_STORAGE - 1)
{
printk(KERN_INFO "ERROR in RobotArmController_write: \
Input is too long to accept.\n");
return -ENOMEM;
}
if (down_interruptible(&gSem))
{
printk(KERN_INFO "Error in RobotArmController_write, \
down_interruptible call.\n");
return -ERESTARTSYS;
}
if (copy_from_user(pDevice->mpBuffer, apBuffer, aLength))
{
printk(KERN_INFO "Error in RobotArmController_write, \
copy_from_user routine.\n");
up(&gSem);
return -EFAULT;
}
pDevice->mpBuffer[aLength] = '\0';
pDevice->mSize = aLength;
*aOffset += aLength;
up(&gSem);
return aLength;
}
loff_t RobotArmController_llseek(struct file * apFile,
loff_t aOffset, int whence)
{
// return -ESPIPE; //This is how to disable llseek.
RobotArmControllerData * pDevice = 0;
loff_t newPosition = 0;
if( !apFile || !apFile->private_data )
{
printk(KERN_INFO "ERROR in RobotArmController_llseek: \
NULL input detected.\n");
return -EINVAL;
}
pDevice = apFile->private_data;
switch(whence)
{
case 0: // SEEK_SET
newPosition = aOffset;
break;
case 1: // SEEK_CUR
newPosition = pDevice->mOffset + aOffset;
break;
case 2: // SEEK_END
newPosition = pDevice->mSize + aOffset;
break;
default:
return -EINVAL;
}
if( newPosition < 0 )
{ return -EINVAL;
}
pDevice->mOffset = newPosition;
return newPosition;
}