Setting termios linux kernel - linux

I'm trying to describe my problem from the beginning. I'm a newbie in linux diver development, so please point out my problems about my consideration in my project.
I'm now developing a linux driver for a modem, but not a typical one. I hope it can work as a net adapter, rather than a modem. It is connected with computer with serial port. Because of the nature of my problem, I have to use a USB-serial converter. Most of the answer suggest to use a user space driver instead. However, as I want to provide a networking interface like eth0, I have to make it in the kernel. Besides open/read/write ttyUSB0 file, I do not have any other idea solving this problem.
I'm now using code like this
struct file *f;
mm_segment_t oldfs;
struct tty_struct *tty;
struct termios term;
unsigned char buffer[255];
f=filp_open("/dev/ttyS0",O_RDWR | O_NDELAY,0);
oldfs=getfs();
set_fs(KERNEL_DS);
f->f_pos=0;
tty=(struct tty_struct*)f->private_data;
tty->termios->c_flag=B9600 | CRTSCTS | CS8 | CLOCAL | CREAD;
At this time, tty->termios is NULL, so I can not do the last step. What I do is:
struct ktermio term;
//setting the termio
tty->termios = &term;
And the result of this is that the setting is not applied to the serial port. Even if I change it to a absolutely wrong baud rate, I still receive fragments. Some of them are correct, while some are not. What is the problem, and what should I do.

Related

Change the ifindex of netdev

I have the following requirement. I want with a kernel module to change the ifindex of a netdev with one of my choice. I know that it acts as a key and cannot be change during runtime. Created interfaces are based on Intel e1000 driver.
In order to achieve the change the following has been thought:
unregister_netdev(dev);
//Change the dev->ifindex
//bring back network device to operational state somehow, tried register_netdev but this results in kernel panic of course
Can you please inform me if this is somehow possible? I am very new to linux kernel drivers.
Thank you!
I think I have found a trick/way to tackle this issue:
create a dummy network namespace
use dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) to move device to this namespace
then use __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, int new_ifindex) to move dev to init_net with the
desired new_ifindex
delete dummy network namespace
In my kernel __dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat, int new_ifindex) does not exist but it is not though so hard to be created since it only pickups a new_ifindex in case it is not provided, or checks the provided one if it is currently used inside namespace
Not tested yet, but it will be very soon.

Need to find and open a USB serial device on linux

I'm writing a small C application to run on my (Linux) QNAP NAS that will talk to an Arduino (I have no difficulty with any of the USB code for the arduino). (The arduino has a trusted application on it that accepts text commands via USB serial.)
My wish was to find it using the USB vendor/product IDs (only half implemented at the moment). What I have so far (see below) works quite nicely in that it does find the device.
// runs on NAS
#include <stdio.h>
#include <usb.h>
main () {
struct usb_bus *bus;
struct usb_device *dev;
usb_init();
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
printf("Trying %s/%s\n", bus->dirname, dev->filename);
printf("\tVendor = 0x%04x\n", dev->descriptor.idVendor);
printf("\tBus = 0x%03x\n", bus->location);
printf("\tFile = %s\n", dev->filename);
if (dev->descriptor.idVendor==0x403) {
printf("\t HEY, THIS IS MINE!\n");
usb_dev_handle *handle = usb_open(dev);
printf("\t HANDLE 0x%08x\n", (int) handle);
//printf(handle, "1,5,62,75\n");
usb_close(handle);
}
}
}
}
The trouble is that now I want to send/receive a little bit of text with the device and I don't know how to do that.
I have expected I should be generating a device name from something in the usb_device struct and then open it like a file (like one would do on Windows).
If that's correct, I need to know the correct way to find out the device name...
I believe I'm using libusb.
I happen to know that -- as currently configured/connected -- it's ttyUSB0 but I'd like to know that using code.
thank you!
I suggest using libusbp. It is a C library with a C++ wrapper, and there is example code showing how to get the name of a serial port based on the vendor ID and product ID of the USB device:
https://github.com/pololu/libusbp/blob/master/examples/port_name/port_name.cpp
libusb is a library used for low level communication with USB devices. But when your communication is limited just to reading device's USB descriptor - libusb is not the best tool.
Linux systems use udev subsystem to manage hot-plug devices. udev reads descriptors of all plugged USB devices and stores them in its database. libudev is the library that you should use to get such info like device names of enumerated devices. In your case you need to remember that usb_device and usb_interface are separate things - only the latter would have the tty device file assigned to it.
Alternatively you could just use udev config to assign a constant device name to your specific device. So you would not have to be looking for it.

How to extract the MAC address of an interface from witthin a driver code

I'm new to Linux Kernel programming and driver programming. I'm working with madwifi drivers, on Linux with kernel version 2.6.32-37 and wish to extract the MAC address of an interface inside the driver code. I know this information supposed to be found in the netdevice structure fields, but not quite sure which one of them is the right one.
My questions are:
What is the difference between the *dev an the *real?
Which one of them should I use? (they're both in use in different parts of the code and I don't understand when should I use the former and when the latter).
Quoting from http://www.makelinux.net/ldd3/chp-17-sect-3:
unsigned char dev_addr[MAX_ADDR_LEN];
Hardware (MAC) address length and device hardware addresses. The Ethernet address length is six octets (we are referring to the hardware ID of the interface board), and the broadcast address is made up of six 0xff octets; ether_setup arranges for these values to be correct. The device address, on the other hand, must be read from the interface board in a device-specific way, and the driver should copy it to dev_addr. The hardware address is used to generate correct Ethernet headers before the packet is handed over to the driver for transmission. The snull device doesn't use a physical interface, and it invents its own hardware address.
Hope that helps.
There is code in a network driver to access/set MAC address.
There is even a callback defined in net_device_ops
.ndo_set_mac_address = netdev_set_mac_address
It is handled differently on each network device depending on HW registers architecture.
For example for Xilinx AXI MAC address is written to net_device structure and specific HW registers of network controller:
static void axienet_set_mac_address(struct net_device *ndev, void *address)
{
struct axienet_local *lp = netdev_priv(ndev);
if (address)
memcpy(ndev->dev_addr, address, ETH_ALEN);
if (!is_valid_ether_addr(ndev->dev_addr))
eth_random_addr(ndev->dev_addr);
/* Set up unicast MAC address filter set its mac address */
axienet_iow(lp, XAE_UAW0_OFFSET,
(ndev->dev_addr[0]) |
(ndev->dev_addr[1] << 8) |
(ndev->dev_addr[2] << 16) |
(ndev->dev_addr[3] << 24));
axienet_iow(lp, XAE_UAW1_OFFSET,
(((axienet_ior(lp, XAE_UAW1_OFFSET)) &
~XAE_UAW1_UNICASTADDR_MASK) |
(ndev->dev_addr[4] |
(ndev->dev_addr[5] << 8))));
}
So once MAC address is set, commands like ifconfig don't get it from device driver accessing HW registers, but from net_device structure.

How can I set a custom baud rate on Linux?

I want to communicate over my serial port on Linux to a device with a non-standard-baud rate that is not defined in termios.h.
I tried the "baud rate aliasing"-method from this post, but when I execute my C-program (I’ve named it "testprogram"), Linux says "testprogram sets custom speed on ttyS0. This is deprecated."
I did some search on Google, and it seems that there is another (newer?) method to change the baud rate to a non-standard-value: On http://sourceware.org/ml/libc-help/2009-06/msg00016.html the author says that the c_flag of struct termios must be OR’d with BOTHER (=CBAUDEX | B0).
With this method the baud rates are set directly in the c_ispeed and c_ospeed-members of the struct termios. However, I don’t know how I use this method in my C program. Like the author said, there is no BOTHER defined/available when I include termios.h, so what should be done to set the baud rate this way?
How can I set the baud rate to a non-standard-value without changing the kernel?
I noticed the same thing about BOTHER not being defined. Like Jamey Sharp said, you can find it in <asm/termios.h>. Just a forewarning, I think I ran into problems including both it and the regular <termios.h> file at the same time.
Aside from that, I found with the glibc I have, it still didn't work because glibc's tcsetattr was doing the ioctl for the old-style version of struct termios which doesn't pay attention to the speed setting. I was able to set a custom speed by manually doing an ioctl with the new style termios2 struct, which should also be available by including <asm/termios.h>:
struct termios2 tio;
ioctl(fd, TCGETS2, &tio);
tio.c_cflag &= ~CBAUD;
tio.c_cflag |= BOTHER;
tio.c_ispeed = 12345;
tio.c_ospeed = 12345;
ioctl(fd, TCSETS2, &tio);
You can set a custom baud rate using the stty command on Linux. For example, to set a custom baud rate of 567890 on your serial port /dev/ttyX0, use the command:
stty -F /dev/ttyX0 567890
dougg3 has this pretty much (I can't comment there). The main additional thing you need to know is the headers which don't conflict with each other but do provide the correct prototypes. The answer is
#include <stropts.h>
#include <asm/termios.h>
After that you can use dougg3's code, preferably with error checking round the ioctl() calls. You will probably need to put this in a separate .c file to the rest of your serial port code which uses the normal termios to set other parameters. Doing POSIX manipulations first, then this to set the custom speed, works fine on the built-in UART of the Raspberry Pi to get a 250k baud rate.
BOTHER appears to be available from <asm/termios.h> on Linux. Pulling the definition from there is going to be wildly non-portable, but I assume this API is non-portable anyway, so it's probably no big loss.
For Mac users (possibly also for some Linux distributions)
stty ospeed 999999
stty ispeed 999999
You can just use the normal termios header and normal termios structure (it's the same as the termios2 when using header asm/termios).
So, you open the device using open() and get a file descriptor, then use it in tcgetattr() to fill your termios structure.
Then clear CBAUD and set CBAUDEX on c_cflag.
CBAUDEX has the same value as BOTHER.
After setting this, you can set a custom baud rate using normal functions, like cfsetspeed(), specifying the desired baud rate as an integer.
There is an serial I/O chip on your motherboard's CPU (16650 UART).
This chip uses 8-bit port as control and data bus, and thus you can issue a command to it through writing to this chip through the control and data bus.
Usually, an application did the following steps on the serial port
Set baud rate, parity, encoding, flow control, and starting / ending sequence length during program start. This setup can be done via ioctl to the serial device or 'stty' command. In fact, the stty command uses ioctl to that serial device.
Write characters of data to the serial device and the driver will be writing data charaters to the UART chip through its 8-bit data bus.
In short, you can specify the baud rate only in the STTY command, and then all other options would be kept as default, and it should enough to connect to ohter devices.

how to know the Interrupt/GPIO number for a specific pin in linux

i'm doing a project in which i need to handle an interrupt in Linux.
the board i'm using is an ARM9Board based on the s3c6410 MCU by Samsung (arm 11 processor) and it has the following I/O interface :
as the image shows i have EINTx pins for external interrupts and GPxx pins as GPIO pins and i don't mind using any of them but i don't have their numbers !
For EINTx pins :
when i call
int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
unsigned long flags, const char *device);
i need the interrupt number to pass it as the first paramter of the function , so how can i get the irq number for example the EINT16 pin ?
For GPxx pins :
the same story as i need the GPIO pin nuumber to pass it to those functions
int gpio_request(unsigned gpio, const char *label);
int gpio_direction_input(unsigned gpio);
int gpio_to_irq(unsigned gpio);
i.e how do i know the GPIO number for the GPP8 pin ?
i searched the board documents and datasheet but it doesn't contain anything about how to get those numbers , any idea or help on where to look ?
The Embedded Linux you are using should have a GPIO driver that has #define statements for the GPIO pins. You can then get the IRQ number of the specific GPIO using something like:
irq_num = gpio_to_irq(S3C64XX_GPP(8));
The Linux GPIO lib support for that particular chip is available in the following file:
linux/arch/arm/mach-s3c6400/include/mach/gpio.h
There you will find all the #define statements for the various GPIO.
See the section on GPIO Conventions in their documentation:
http://www.kernel.org/doc/Documentation/gpio/gpio.txt
I was doing some work on the GPIO pin as well but it's on a different board, AM335x. Just to let you know, there's quite few of way to do it. One of the method we are using is using memory board to access (write or read) the GPIO pin.
This is a really good article to help me to get things working. Register access to the GPIOs of the Beaglebone via memory mapping

Resources