Seeking a Device

The difficult part of the chapter is over, and I’ll quickly detail the lseek method, which is useful and easy to implement. Note that the prototype of the method changed slightly in 2.1.0, as detailed in Section 17.2.1, in Chapter 17.

The lseek Implementation

I’ve already stated that if the lseek method is missing from the device’s operations, the default implementation in the kernel acknowledges seeks from the beginning of file and from the current position, by modifying filp->f_pos.

If seeking relative to the end-of-file makes sense for your device, you should offer your own method, which will look like the following code:

int scull_lseek (struct inode *inode, struct file *filp,
                 off_t off, int whence)
{
    Scull_Dev *dev = filp->private_data;
    long newpos;


    switch(whence) {
      case 0: /* SEEK_SET */
        newpos = off;
        break;

      case 1: /* SEEK_CUR */
        newpos = filp->f_pos + off;
        break;

      case 2: /* SEEK_END */
        newpos = dev->size + off;
        break;

      default: /* can't happen */
        return -EINVAL;
    }
    if (newpos<0) return -EINVAL;
    filp->f_pos = newpos;
    return newpos;
}

The only device-specific operation here is retrieving the file length from the device. For the lseek system call to work correctly, however, the read and write calls must cooperate by updating filp->f_pos whenever data is transferred; they should also use the f_pos field to locate the data they transfer. The implementation of scull includes these features, as shown in Section 3.7 in Chapter 3.

While the implementation shown above makes sense for scull, which handles a well-defined data area, most devices offer a data flow rather than a data area (just think about the serial ports or the keyboard), and seeking doesn’t make sense. If this is the case, you can’t just refrain from declaring the lseek operation, because the default method allows seeking. Instead, you should use the following code:

int scull_p_lseek (struct inode *inode, struct file *filp,
                   off_t off, int whence)
{
    return -ESPIPE; /* unseekable */
}

The function just shown comes from the scullpipe device, which isn’t seekable; the error code is translated to ``Illegal seek,'' though the symbolic name means ``is a pipe.'' Since the position-indicator filp->f_pos is meaningless for non-seekable devices, neither read nor write needs to update it during data transfer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.84.32