2

I am trying to implement a SPI driver for custom hardware. I have started with a copy of the spidev driver, which has support for almost everything I need.

We're using a protocol that has three parts: a command bit (read / write) an address, and an arbitrary amount of data.

I had assumed that simply adding lseek capabilities would be the best way to do this. "Seek" to the desired address, then read or write any number of bytes. I created a custom .llseek in the new driver's file_operations, but I have never seen that function even be called. I have tried using fseek(), lseek(), and pread() and none of those functions seem to call the new my_lseek() function. Every call reports "errno 29 ESPIPE Illegal Seek"

The device is defined in the board.c file:

static struct spi_board_info my_spi_board_info[] __initdata = {
[0] = {
    .modalias      = "myspi",
    .bus_num        = 1,
    .chip_select    = 0,
    .max_speed_hz   = 3000000,
    .mode           = SPI_MODE_0,
    .controller_data = &spidev_mcspi_config,
}, ...

I suspect there might be something with the way that the dev files get created, mainly because the example that I found references filp->f_pos

static int myspi_llseek(struct file *filp, loff_t off, int whence)
{
    ...
    newpos = filp->f_pos + off;
    ...
}

So my questions are: Is there a way to have this driver (lightly modified spidev) support the "seek" call? At what point does this get defined to return errno 29? Will I have to start from a new driver and not be able to rely on the spi_board_info() and spi_register_board_info() setup?

Only one driver in the /drivers/spi directory (spi-dw) references lseek, and they use the default_llseek implementation. There are a couple of "hacks" that we've come up with to get everything up and running, but I tend to be a person who wants to learn to get it done the right way.

Any suggestions are greatly appreciated! (PS, the kernel version is 3.4.48 for an OMAP Android system)

  • I suspect that somewhere, you need to set the *initial* position to `0` instead of `-1`, but I've never done this stuff. – o11c Jun 03 '16 at 07:44
  • *"Only one driver in the /drivers/spi directory (spi-dw) references lseek..."* -- That's a completely irrelevant fact. That directory (except for spidev.c) is for SPI master controllers, and not for SPI slave devices. The SPI protocol drivers for SPI slave devices are stored in their respective subsystem directory. IOW by their *functionality*, and not their (SPI) interface. *"At what point does this get defined to return errno 29?"* -- Did you try greping for ESPIPE? Are you forgetful, and still have the call to **no_llseek()** in your code? – sawdust Jun 04 '16 at 20:06
  • @sawdust I certainly did implement the "my_llseek()" function in the file_operations struct. – ColoradoIcculus Jun 06 '16 at 14:21
  • @o11c I'll definitely look into that, thanks! – ColoradoIcculus Jun 06 '16 at 14:22
  • After changing from the `nonseekable_open(inode, filp);` to `generic_file_open(inode, filp)` I had much more success. I think I have enough to go on right now, but I'm now seeing issues with the file size. I have thrown in an `i_size_write` command to make the file be seekable to the proper range, but only `pread` succeeds as I would expect. I'll update any findings when I come across them. – ColoradoIcculus Jun 06 '16 at 22:35

1 Answers1

4

Spi driver dose not support any llseek or fseek functionality. It has these many call back functions.

 struct spi_driver {
    const struct spi_device_id *id_table;
    int                     (*probe)(struct spi_device *spi);
    int                     (*remove)(struct spi_device *spi);
    void                    (*shutdown)(struct spi_device *spi);
    int                     (*suspend)(struct spi_device *spi, pm_message_t mesg);
    int                     (*resume)(struct spi_device *spi);
    struct device_driver    driver;

};

Now drivers/spi/spi-dw.c is register as a charter-driver(debugfs_create_file("registers", S_IFREG | S_IRUGO, dws->debugfs, (void *)dws, &dw_spi_regs_ops);). So they implement to create a file in the debugfs filesystem. they implement lseek callback function.

static const struct file_operations dw_spi_regs_ops = {
    .owner          = THIS_MODULE,
    .open           = simple_open,
    .read           = dw_spi_show_regs,
    .llseek         = default_llseek,

}; The file_operations structure is defined in linux/fs.h, and holds pointers to functions defined by the driver that perform various operations on the device. Each field of the structure corresponds to the address of some function defined by the driver to handle a requested operation

lseek -: lseek is a system call that is used to change the location of the read/write pointer of a file descriptor.

SPI -: The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial link used to connect microcontrollers to sensors, memory, and peripherals. SPI can not provide any lseek and fseek functionlity.

There are two type of SPI driver (https://www.kernel.org/doc/Documentation/spi/spi-summary)

Controller drivers ... controllers may be built into System-On-Chip processors, and often support both Master and Slave roles. These drivers touch hardware registers and may use DMA. Or they can be PIO bitbangers, needing just GPIO pins.

Protocol drivers ... these pass messages through the controller driver to communicate with a Slave or Master device on the other side of an SPI link.

If you want to user read, write and llseek then you will have to register a charter-driver on top of SPI. Then you will able to achieve your acquirement.

Arvind Yadav
  • 441
  • 2
  • 4
  • -1 for obviously not having read the Linux documents on SPI (e.g. [Documentation/spi/spi-summary](https://www.kernel.org/doc/Documentation/spi/spi-summary). *"Spi driver dose [sic] not support ..."* -- Since there are two kinds of SPI drivers, your statement is ambiguous, and therefore misleading. – sawdust Jun 05 '16 at 09:29
  • Yes there is two type of spi driver but both will not support lseek, SPI Protocal driver has implement file_operations. The file_operations structure is defined in linux/fs.h, and holds pointers to functions defined by the driver that perform various operations on the device. Each field of the structure corresponds to the address of some function defined by the driver to handle a requested operation. – Arvind Yadav Jun 05 '16 at 10:26
  • I thought by using spidev.c as my base, I was using a generic character driver on top of SPI. I just did a little more digging this morning and noticed the following line: `nonseekable_open(inode, filp);` It would seem that is likely the culprit at bay! – ColoradoIcculus Jun 06 '16 at 14:28