Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RS232 serial port communication in kernelspace

I'm writing a kernel module for Linux v3.2 to control an external laser, but I'm having trouble communicating signals through the RS232 serial port on the machine.

There seems to be a serial driver already compiled in my kernel holding ownership to the ioport addresses I want to access:

# cat /proc/ioports | grep serial
  02e8-02ef : serial
  02f8-02ff : serial
  03f8-03ff : serial

This makes sense since Linux allows userspace programs to use the /dev/ttyS* device nodes to communicate via the serial ports. For example, here's how I setup the device for an LCD panel:

#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

...

    /* Initialization and configuration */
    const char *const lcd_dev = "/dev/ttyS1";        
    int lcd_dev_fd = open(lcd_dev, O_RDWR | O_NOCTTY | O_NDELAY);
    fcntl(lcd_dev_fd, F_SETFL, 0);

    struct termios options;
    tcgetattr(lcd_dev_fd, &options);

    cfsetispeed(&options, B19200);
    cfsetospeed(&options, B19200);
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    options.c_oflag &= ~OPOST;

    tcsetattr(lcd_dev_fd, TCSANOW, &options);

    ...

    /* sending bytes */
    const unsigned char scls[] = {0xFE, 'X', 0xFE, 75, 0xFE, 84, 0xFE, 'H'};
    write(lcd_dev_fd, scls, sizeof(scls);

However, this is a userspace interface and thus incompatible with my kernelspace module. I need a way to produce the same effect (RS232 serial I/O) but from within kernelspace.

Although I can unload the default Linux serial driver and replace it with my own custom RS232 driver, I don't want to reinvent the wheel here -- the default Linux serial driver appears to support the functionality I require.

Is there a simple way to communicate via the RS232 serial ports in kernelspace (perhaps through this default Linux serial driver), or do I just have to program my own custom RS232 driver?

like image 662
Vilhelm Gray Avatar asked Mar 22 '23 05:03

Vilhelm Gray


1 Answers

Take a look at line disciplines. You can use it to attach a tty device to some read and write routines defined in kernelspace and thus write a driver using a serial line. The line discipline gets attached to it from user space and the kernel will do all the rest.

A good example is slcan (drivers/net/can/slcan.c). Examples for the libc calls handling this can be found in can-utils (https://gitorious.org/linux-can/can-utils). If you prefer working by book chapter 18 of Linux Device Drivers will give a good first step: http://www.makelinux.net/ldd3/chp-18, though the book is not very up to date. Some details may also be found at http://www.linusakesson.net/programming/tty/.

like image 82
Stephan Roslen Avatar answered Apr 07 '23 00:04

Stephan Roslen