How to use a FIFO in a Linux char device driver so that two process that uses the driver can communicate

3k views Asked by At

I have a char device driver that for a virtual device. I want a FIFO in the device driver so that 2 process using the device driver can transfer characters between them. I tried kfifo but I am new to this and find it difficult to use. Can any body please suggest some other way to implement the FIFO in Linux driver.

1

There are 1 answers

0
mcleod_ideafix On BEST ANSWER

If you are only going to allow two processes to use the driver, then you can do as this: In your open handler, make sure that two and only two processes can enter the driver:

If access mode = READ and not alreadyreading then
  alreadyreading = 1
else
  return -EBUSY

If access mode = WRITE and not alreadywritting then
  alreadywritting = 1
else
  return -EBUSY

In the same handler, initialize your FIFO, which could be just a single global character variable, and two wait queues: one for read, and one for write. Associated with these queues will be two variables: ready_to_read and ready_to_write. At the beginning, ready_to_read = 0 and ready_to_write = 1.

Then, in the release handler:

If access mode = READ
  alreadyreading = 0;
If access mode = WRITE
  alreadywritting = 0

To allow a new process to open the device in read or write mode.

In the write handler:

If access mode = READ then  // we only support writting if the access mode is write
  return -EINVAL
Else
  res = wait_event_interruptible (write_queue, ready_to_write);
  if (res)
    return res;  // if process received a signal, exit write
  Take a single character from user space (copy_from_user() )
  Copy it to the FIFO (the global character variable)
  ready_to_write = 0;  // no more writtings until a read is performed
  ready_to_read = 1;   // ready to read! wake up the reading process
  wake_up_interruptible (&read_queue);
  return 1;  // 1 byte written

And finally, in the read handler:

If access mode = READ then  // we only support reading if the access mode is read
  return -EINVAL
Else
  res = wait_event_interruptible (read_queue, ready_to_read);
  if (res)
    return res;  // if process received a signal, exit write
  Take character from global variable (our FIFO) and send it to userspace (copy_to_user() )
  ready_to_read = 0;  // no more reads until a write is performed
  ready_to_write = 1;   // ready to write! wake up the writting process
  wake_up_interruptible (&write_queue);
  return 1;  // 1 byte read

You can extend this example to allow a FIFO or more than one character: you would need an array of chars, and two indexes: one to know where to read from, and one to know where to write to.

To test your driver, you can open two xterms and do

cat /dev/mydriver

in one, and:

cat > /dev/mydriver

In the oher one. Then, every line you write in the second xterm will be shown in the first one.

You can even modify the driver so when the writting process closes the file, a flag is set so the next time the read process waits to read something, it detects that the write process is ended and then it returns 0 as well (to signal an EOF to the user), so when you press Ctrl-D in the second xterm to end input, the first one ends automatically too. Something like:

(read handler)

res = wait_event_interruptible (read_queue, ready_to_read || write_process_ended);
if (res)
  return res;  // -ERSTARTSYS if signal
if (write_process_ended)
{
  ready_to_write = 1;
  return 0;    // if write process ended, send an EOF to the user
}
else
{
  ...
  ... get byte from FIFO, send to the user, etc.
  ...
  return number_of_bytes_sent_to_user;
}