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?
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/.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With