tty_tiocmset in linux kernel masks desired modem signal - c

I am running an embedded linux kernel on hardware that can be configured as DTE/DCE. In the tty/serial drivers in a file called tty_io.c there is a function tty_tiocmset() which takes a bit pattern from the tty_ioctl for setting/clearing specific modem control signals. Interestingly, the tty_tiocmset() function masks all other modem signals besides TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP (this mask is shown in the code below). However, if you look at the documentation it appears that all modem signals should be able to be set/cleared http://www.kernel.org/doc/man-pages/online/pages/man4/tty_ioctl.4.html scroll down to "Modem Control".
Does anybody simply know why this mask is present without other signals such as RI, CD, CTS, DSR? Also is there another way to use the unmodified driver to control the other modem signals?

Linux was originally hosted on the x86 PC platform, which used 8250-type UARTs. The modem signal names OUT1 & OUT2 are not EIA/RS-232 names but do appear in the Western Digital 8250 data sheet! Those 5 bits listed for tty_tiocmset() match (by name & function) the 5 bits available in the 8250 Modem Control Register. Any additional control lines would have to be implemented by logic external to the 8250.
Does anybody simply know why this mask is present without other signals such as RI, CD, CTS, DSR?
Those four that you mention are input signals to a DTE port, and PCs are normally configured (or assume/default) to be DTE.
Input signals would not appear in an output control register.
Maybe this is a bug when Linux is embedded in a device for a DCE port?
These input signals do appear in the Modem Status Register.
Also is there another way to use the unmodified driver to control the other modem signals?
You could remap OUT1 and OUT2 to whatever additional DTE signal(s) you need to output.
If you need to setup the port for DCE, then you may have to remap all four control lines.
For a DCE port (i.e. modem) there are typically only 4 output control lines: DCD, CTS, DSR, and RI. And there are exactly 4 output control bits (besides loopback) in the 8250 MCR!

Related

RS485 communication not supported using FTDI cable

I'm trying to port a program, which communicates over RS485 half-duplex UART, to Raspberry Pi. Since Pi's built-in UARTs don't support the RS485 standard, I'm using the USB-RS485-WE-1800-BT FTDI cable.
When connected, I can confirm that the cable's FTDI chip shows up in dmesg, the ftdi_sio driver is loaded, and properly exposes the /dev/ttyUSB0 serial terminal to the rest of the system. However, when I attempt to enable RS485 mode from a simple C program:
struct serial_rs485 config = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
.delay_rts_before_send = 0,
.delay_rts_after_send = 0
};
if (ioctl(fd, TIOCSRS485, &config) < 0) {
fprintf(stderr, "ioctl failed (%d): %s\n", errno, strerror(errno));
exit(0);
}
... I get the following error:
ioctl failed (25): Inappropriate ioctl for device
Looking into a schematic, I realized that the FTDI cable internally uses 2 components:
the FT232R chip, which is controlled by the ftdi_sio driver over USB and produces conventional serial output, and
the ZT485EEN chip, which transforms conventional serial comms to RS485.
So, given that FT232R doesn't technically emit RS485, I understand why its driver complains when asked to enable RS485 mode. What it doesn't know, though, is that the second chip takes care of format conversion transparently.
Having researched this topic for a bit and read answers to a similar question, I'm now curious how to proceed. Should I change the request ID in my ioctl() call to something else than TIOCSRS485? Should I remove the ioctl() call entirely? And if I do that, how can RS485 flags and RTS delays be set? Finally, if this means that enabling RS485 mode is not required in this configuration, can the FTDI cable be bypassed entirely by using Raspberry Pi's built-in UARTs combined with a chip like ZT485EEN?
Should I change the request ID in my ioctl() call to something else than TIOCSRS485? Should I remove the ioctl() call entirely?
Removing the ioctl() would be the appropriate thing to do in this case, as the serial converter is handling it entirely for you. As far as you are concerned, it is just a serial port that you read and write to.
And if I do that, how can RS485 flags and RTS delays be set?
You can't set any flags or delay using the FTDI cable. However, since the data that comes out of the cable is already RS485, there's no need to set anything. As long as whatever it is you're talking to is half-duplex(it does not talk at the same time as you do), this isn't an issue, and you can use it just like an RS232 cable. This depends on your specific use-case though. I have never encountered the need to have an RTS delay.
Finally, if this means that enabling RS485 mode is not required in this configuration, can the FTDI cable be bypassed entirely by using Raspberry Pi's built-in UARTs combined with a chip like ZT485EEN?
Sure, you can do that. There are also many different models of RS485 transcievers that you could use; Electronics.SE would the the place to ask for more information on that. You may need to enable RS485 at that point with TIOCSRS485, but that's going to be driver-dependent. I don't know about the Pi, but at least on some Atmel chips that I have used before setting the RS485 mode sets a certain bit in the peripheral on the chip that automatically toggles the RTS pin to enable/disable the RS485 transciever; otherwise, Linux needs to toggle a GPIO in order to set the transciever into the correct state.
Specifically on the FTDI, there are GPIOs that can be set that will turn on/off at appropriate times. One of these is the TXDEN signal, which controls the transciever for you automatically. Others are used for the Tx/Rx LEDs.
There’s no “rs485” mode. Just forget about it and everything will be OK. RS485 is just an electrical standard, and the ZT485 does the electrical translation from logic levels to differential signaling and back. You could use that chip (or any equivalent) directly with the UART pins on the Raspberry PI: those are not RS232 nor RS485, just bare asynchronous logic level UART pins. Your assertion that Raspberry PI “doesn’t support” RS485 is meaningless: it doesn’t support RS232 either, and it’s not supposed to. Those electrical standards require level translation/interface chips, and the “other side” is always the same: logic level asynchronous serial streams and control lines. The only “pitfall” is choosing the proper logic levels (3.3V be 5V - I don’t offhand remember what does RPI support).

How to call Linux kernel driver functions from a userspace program?

How can I write a C program (in userspace) to call functions that are part of a kernel driver? If it's not possible to do directly, how else do I do it?
CONTEXT: I am trying to use the PWM pins of my single-board computer (Intel NUC DE3815TYBE) so that I can control fans. A linux driver called pwm_lpss allows control of these pins (driver developed by Intel, source code here). I have verified that this driver is installed by using the lsmod command. Here is the driver information after typing modinfo pwm_lpss:
filename: /lib/modules/3.19.0-25-generic/kernel/drivers/pwm/pwm-lpss.ko
license: GPL v2
author: Mika Westerberg <mika.westerberg#linux.intel.com>
description: PWM driver for Intel LPSS
srcversion: 44AA14AF3E2F96C813770A8
depends:
intree: Y
vermagic: 3.19.0-25-generic SMP mod_unload modversions
signer: Magrathea: Glacier signing key
sig_key: 6A:AA:11:D1:8C:2D:3A:40:B1:B4:DB:E5:BF:8A:D6:56:DD:F5:18:38
sig_hashalgo: sha512
So I know where the driver module is (the pwm-lpss.ko file) and I have the source code which I know has a function in it called pwm_lpss_config() that I'd like to use. How do I call the function from my userspace C program? How would I go about #including it? Or is this not possible to do from userspace?
Unfortunately Intel has provided zero documentation for how to use this driver. I thought drivers normally map their functionality to some user-accessible file. I was able to find some PWM-related files after some digging, but I haven't been able to find a file that looks like it can set PWM duty cycle/frequency.
It's a standard Linux PWM driver, so no special documentation is necessary.
Check the /sys/class/pwm/ directory. (/sys is the interface the kernel provides for access to its data structures. It just looks and acts like a filesystem.) You should have something like /sys/class/pwm/pwmchip0/. Each such directory corresponds to a PWM chip.
The directory will have the following entries. You may need superuser privileges to access these (as you wouldn't want everybody to mess with them):
npwm: Read this to find out how many PWM channels this chip has.
export: Write a channel number (0 to whatever-the-number-in-npwm-1) to make that channel available via this sysfs interface
unexport: Write a channel number to remove the channel from sysfs interface control
Each PWM channel exported to be used via the sysfs interface will show up as a subdirectory named pwmN, where N is the channel number. Here, you can read and write to entries
period: Total period (off + on) in nanoseconds.
duty_cycle: On time in nanoseconds. Must be less than period.
polarity: If the chip supports reversing the signal polarity, you can write inversed here to invert the polarity; normal is the default/normal polarity.
enable: 1 if enabled, 0 if disabled.
When reading or writing to these entries, no special locking is necessary. The kernel will receive all data in one write(), and return all data in one read() operation. When a write() succeeds, the kernel has applied the setting.
some ioctl ? The ioctl() function manipulates the underlying device parameters of special files.
Along the lines
fd = open("/dev/pwm0", O_RDONLY); // put whatever device you've got
if (ioctl(fd, STATUSGET, &status) == -1) // magic constant should be set
....
} else {
....
}

where is the interrupt handler of can bus driver on BeagleBone black

I am trying to use the CAN bus and PRU on BBB to do some real time control, but I have checked the $KERNEL/net/can/ and $KERNEL/driver/net/can, such as af_can.c and raw.c but can not find the request_irq(), but I do find the interrupt number 52 in device tree and cat /proc/interrupts.
I do this because that I not want the ethernet have any influence on my application.
1, Does the ethernet traffic will affect the CAN bus?
2, Where can I register my interrupt handler for the CAN bus?
though it is a year ago, I want to answer as much as I know
Ethernet is only affected like anything else, cause the CPU is working on the can bus.
If you use SocketCAN, CAN-Bus will be processed like Ethernet: by sockets. So you don't need to register an interrupt handler. Your Program will be interrupted by the socket, if you write your program right. For this search for handling sockets. There are other CAN-Bus handler, which are not used by default and shouldn't be anymore, cause they are outdated.

RS232 Serial Pin Read in C in Linux

Ist there any possibility to read values from the pins of the COM Port? Any solution in C under Linux is appreciated!
Yes, see for instance this guide.
You use the ioctl() function, to read the various control pins. Data is, of course, best read through the normal read() handling, you don't want to be polling asynchronuous serial data.
I don't think your assumption (expressed in a comment) that the driver must check the pin-states to handle data is correct, normally a serial port is "backed" by an UART and that typically handles the RX/TX pins in hardware.
Am pretty sure , you can't read/write pins of UART.
Even at the hardware level , you have to read/write an entire byte.There is no bit access or read/write pin access.
The Byte is read/written in the Receive/Transmit UART buffer .
In either ways you can't just access the buffer directly , on your behalf the linux driver will do the job. You just have to make use of the driver in your application , to work with the UART , the linux driver for UART provides , standard API's like open(),read(),write(),ioctl() through which you interact the UART device.
If you want to work with drivers , and new to this field , the best place to start will be
this book.
The exact answer to this question depends on the precise hardware in question. I know of a piece of code where I worked, based on receiving the letter 'a' as the indication of bitrate, and it would poll the RX pin to detect the transitions between 0 and 1 to detect the "width" of the bits, and it would then calculate the correct clock-rate for the serial port and configure the serial port to match the bitrate of the other end.
A "PC" type hardware solution will not be able to read the RX/TX pins. In other hardware, it may be possible to do so. Many embedded systems allow various pins to be configured as inputs, outputs or "have a function" (in our case, RX, TX, CTS, RTS, etc) - so for example, you could configure the RX pin to be a input, and thus read the state of it. Of course, the normal serial port drivers will probably set these pins to "have a function" [or expect the boot code running before the kernel is started to have configure it this way]. So you would have to reconfigure the pins in some kernel code of your own, most likely. Beware that this may cause unexpected side-effects with the driver for the actual serial port - it may "get upset" when it tries to do things to the serial port and it's "not working as expected" because it's been "misconfigured".
You can almost certainly read (and/or write) the state of the control pins, such as CTS, RTS via IOCTL calls.

Init a serial communication with c library open() causes TX to send one bit on RPi

I'm trying to set up a serial communication between the RPI and an FPGA. However, there is an issue when using the standard C library open() to init the serial interface: I'm using a scope to monitor what is sent and received via the RX and TX lines. A call to open causes the TX line of the RPI to go low for the length of one bit. I do not see this behavior with other computers/linux PCs. The point is, the FPGA assumes a valid transmission, since he thinks it's a start bit, but it's not.
I checked with minicom installed on the RPI. Same thing. Starting minicom causes the TX line sending one bit. Once minicom has started, the communication runs as expected and all bytes have the correct frame size. Is there any way to suppress the TX line going low upon the open call to init the serial communication? Is this an expected behavior?
This is a super far-fetched hunch, but this code seems a bit suspicious, from the pl011_startup() function in the PL011 serial port driver:
/*
* Provoke TX FIFO interrupt into asserting.
*/
It seems as if it's twiddling the TX line when starting up the port, which would explain the pulse you're seeing. More investigation would surely be needed before concluding this is what happens, of course.
So, I guess my "answer" boils down to: that sounds weird, perhaps it's something with the driver?
Of course, one way of working around this is to apply some care in the FPGA end, assuming you have more control over it. "Proper" framing would take care of this, and make it clear that the spurious send can be discarded.
UPDATE: I meant that if "proper" messages were to be always framed by some sequence of bytes, the FPGA might be able to discard invalid ("unframed") data anyway, and thus become immune to the random pulse. For instance, messages could be defined to always start with SOH (start of header) or SOT (start of text) symbols (bytes with the values 0x01 and 0x02, respectively).

Resources