I want to write a linux kernel module which sends a character over tty to another PC.
Before anyone asks: Yes, it has to be a kernel module. User space isn't available at the point the "message" is send.
What I've got so far is:
I'm using kernel 4.14.
The device file is /dev/ttyS0
The major number for the driver is 4.
I've got a self written kernel module consisting of a function which is executed at the right time.
The problem at hand is, that I don't know how to access the tty driver using the name "ttyS0".
There are so many functions inside the tty driver and I haven't either the tty_struct nor the index (minor number) of the device...
The goal is probrably something like this pseudocode:
void MyFunction(void)
{
tty_struct MyStruct* = get_tty_struct("ttyS0");
char message = 'A';
write_to_tty(MyStruct, message);
}
Any help on the subject is appreciated.
Greetings
Related
I am writing a device driver in linux for PCIe endpoint implemented on Xilinx UltrascaleMPSoC FPGA part. I have implemented the remove function correctly. I connect my device using an adapter to my PC, turn on device, enable its Endpoint and then turn on PC and everything works correctly. However, when I try to unload the driver module using rmmod command, the process hangs.
I went through Linux documentation and for pci_disable_device() documentation, it says
Note we don't actually disable the device until all callers of pci_enable_device() have called pci_disable_device().
Does it mean, my driver has to wait untill every other pcie driver in linux calls pci_disable_device() and only then device gets disabled? I really doubt upon this :(
I tried using modprobe -r and also listed the module usage count using "lsmod". lsmod shows usage count as "0". But still I am not able to unload the module :( I also added print statements.
void remove(struct pci_dev pdev)
{
pci_unmap_single(pdev, privdata->dma_mem,
PAGE_SIZE * (1 << memorder),
PCI_DMA_FROMDEVICE);
printk(KERN_INFO"unmap_single() complete\n");
free_pages ((unsigned long) privdata->mem, memorder);
printk(KERN_INFO"free_pages() complete\n");
free_irq(pdev->irq, privdata);
printk(KERN_INFO"free_irq() complete\n");
pci_disable_msi(pdev);
printk(KERN_INFO"MSI disable complete\n");
pci_clear_master(pdev); /* Nobody seems to do this */
printk(KERN_INFO"clear_master() complete\n");
pci_iounmap(pdev, privdata->registers);
printk(KERN_INFO"iounmap() complete\n");
pci_disable_device(pdev);
printk(KERN_INFO"disable_device() complete\n");
pci_release_regions(pdev);
printk(KERN_INFO"release_regions() complete\n");
}
Expected: The device must get disabled. I can't conclude. When I do a dmesg in another terminal, I get prints till "disable_device() complete" and the terminal hangs.Also,I checked the files: /proc/iomem and /proc/interrupts-> when I unload the module, corresponding entries of my device is removed in both of my files! I only complete the execution of pci_disable_device() and the process hangs.
Note: Only the rmmod process hangs and I cannot use the current terminal, but I can open another terminal, do all things.
Finally, when the do a restart, the system hangs again and everytime, I am doing force restart by holding power button for 10-15 seconds.
Check this reboot_hang
Why is the pci_release_regions() hanging my system even though lsmod shows my module usage count as "0".
Thanks in advance :)
Also, should I interchange pci_disable_device() and pci_release_regions() methods in above code? -> I tried this as well, but then I get prints till release_regions() complete but disable_device complete is not printed. And process hangs :(
Please help
Difficult to answer without more information on what you really use on your driver.
But, I will try to give you an answer.
Does it mean, my driver has to wait untill every other pcie driver in linux calls pci_disable_device() and only then device gets disabled?
No, this would make impractical and not very modular.
It seems you're freeing the DMA pages. How are you allocating them ? Are you using coherent allocation? Take a look here to see how to use properly the DMA.
For the remainder, can you try to move release regions before clear_master? Example :
pci_disable_msi(pdev);
ioummap(ADDRESS);
pci_release_regions(pdev);
pci_clear_master(pdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
For more information on how to write PCI Drivers, check the documentation here. It provides a lot of information.
While searching for techniques to debugging a Linux kernel, one of the ways is to use the dev_*() family functions.
These functions are defined in the /include/linux/device.h file.
The function list is as below:
`dev_emerge()`<br>
`dev_alert()`<br>
`dev_crit()`<br>
`dev_err()`<br>
`dev_warning()`<br>
`dev_notice()`<br>
`dev_info()`<br>
I have already experimented with the pr_*()[pr_emerge(), pr_alert(), pr_crit()...] family functions, which are similar to printk() in some way.
An experiment is done using simple kernel modules where I'm calling these functions. Furthermore I have also gone through a priority of messages displayed in syslog and dmesg (kernel ring buffer depending console_loglevel-a kernel variable).
But I'm unable to understand the use of dev_*() family. I mean, how do I use it in a program to debug kernel functionality?
The pr_*() functions are the same as plain printk(), but with the KERN_xxx log level already included.
The dev_*() functions are the same as the corresponding pr_*() functions, but also print identifying information about the struct device.
If your message is related to some device (which is normally the case in drivers), you should use dev_*().
For example, in a USB driver:
struct usb_device *usb_dev;
dev_info(&usb_dev->dev, "hello\n");
struct usb_interface *usb_intf;
dev_info(&usb_intf->dev, "hello\n");
or in a PCI driver:
struct pci_dev *pci;
dev_info(&pci->dev, "hello\n");
dev_* functions are similar to pr_*, but also print some information about device(struct device), passed to them as the first argument. This information may help to filter system log for messages, belonging to concrete device.
So, you can use dev_* function instead of pr_* whenever message is applicable to concrete device(and you have destriptor of it).
Check what it prints yourself with QEMU
This is what it prints for a PCI device:
<6>lkmc_pci 0000:00:04.0: pci_probe
which is of format:
<level><kernel-module> <pci-address>: <message>
So as others said, it gives extra device information compared to a simple printk, namely:
kernel module name
PCI address
I tested that with QEMU's "edu" device, which is simple educational PCI device, for which I wrote a minimal Linux kernel module.
The key module code is:
static int pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
dev_info(&(dev->dev), "pci_probe\n");
Character devices don't expose a struct device apparently, so you can't test it that way: How do you get a struct device for a Linux character device
client and server communication in rt linux. client is sending the data and server is the receiver.UDP is used for communication between client and the server.
When the server(rt linux) receives the data from the client the kernel should stop what it is doing and start executing the newly arrived data. I want to calculate the time when the interrupt occurs in kernel (timestamp).
In rt-linux all the operating system operation takes place in kernel. So i am calculating the interrupt time in kernel source code. So i modified the kernel source code in the location /usr/src/linux-version/net/core/dev.c as shown below :
I am calculating the time and storing in a buffer skb.
//this code is at network device driver level.
int netif_rx(struct sk_buff *skb)
{
__net_timestamp(skb);//I modify the code in kernel to get the timestamp and store in buffer
}
// after storing the data to the buffer. kernel will send it to the upper layers like IP, UDP, INET and finally SOCKET of the kernel space.
but I want to read the timestamp packet from the kernel space by the user space. i.e. my program .
I am using recvfrom api to read the data from kernel spacce (which is in kernel memory)
QUESTION : could someone tell me how to access the kernel memory which contains the timestamp data by the user program ??
You can't access kernel memory from userspace directly - you have to use some sort of API.
You can:
Export timestamp through sysfs or debugfs and read it as regular file
Add syscall so kernel will return current timestamp value
Bunch of other crazy variants like netlink socket or shared memory
Example: I use sensor TMP421 which driver is linux/drivers/hwmon/tmp421.c. It will export to /sys/class/hwmon/hwon0/.... And user can use cat command to read the temperatures. But my is request: I want to read it at kernel space to control some thing when the temperature reach to MAX values (example).
So how I can attach to get the device context to use the function
tmp421_data *tmp421_update_device(struct device *dev)
to read the temperature ?
Or is there another way ?
I don't want to use the cat command at my code.
Thanks
Just do bus_find_device_by_name on an i2c_bus_type. It should give you the correct device pointer relatively easily. You will also have to change the tmp421_update_device function from "static" to "exported" (and move tmp421_data structure to an external header).
If you don't want to alter drivers not of your own, you can still try to emulate the approach sysfs takes when accessing device information. The sysfs dirent will be accessible to you at the dev->kobj.sd field and it's a fairly simple data structure.
Critically, you need to call put_device() on the received device handle after you've finished with it (otherwise you will end up with kernel lock-up down the line because of "unreleasable" objects). If you're using the kobj.sd accessor, then sysfs_get()/sysfs_put() on it will also be required.
As said in https://stackoverflow.com/a/4407051/196561 ("How to use sysfs inside kernel module?") by shodanex
it is a Bad Idea (tm)
with link http://www.linuxjournal.com/article/8110
Driving Me Nuts - Things You Never Should Do in the Kernel - From Issue #133 Linux Journal, 2005 By Greg Kroah-Hartman
The article says that it is possible to use sys_open and sys_read from modules to open and read files:
old_fs = get_fs();
set_fs(KERNEL_DS);
fd = sys_open(filename, O_RDONLY, 0);
if (fd >= 0) {
/* read the file here */
sys_close(fd);
}
set_fs(old_fs);
Don't know will it work with files in /sys or not.
And Greg warns us:
I Never Told You about This.
In conclusion, reading and writing a file from within the kernel is a bad, bad thing to do. Never do it. Ever.
Better way may be to learn inter module communications, possibly with modifying the hwmon/tmp421.c.
I want to add a char device to /devices in my Linux directory via C code. Since I'm creating fictitious drivers that should only exist when I insmod my_module.ko, I want my module to create a device for me. Below is the part of my code which should add the device, but I only initialize my cdev struct and tell the kernel about it.
int start_mod(void){
//Because we are dealing with a fictitious device, I want
//the driver to create my two devices with arbitrarly
//assigned major numbers.
alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); // This assigns my device name
// as well as asign Major # my driver uses
cdev_init(&(my_dev->my_cdev), &fops);// This initializes my cdev struct that the kernel uses to keep track of my device
my_dev->my_cdev.owner = THIS_MODULE;
my_dev->my_cdev.ops = &fops;// fops is my file operations struct
int err = cdev_add(&(my_dev->my_cdev), dev_num, COUNT);// this in theory should give a pointer to the kernel
// to my cdev struct that I have setup to exist in my other structure.
// Now I need to officially add my device to /devices folder.
return 0;
}
I'm not to sure what I need to do to officially add the char device to the kernel.
What you do is you use some of the newer registration functions in the kernel like class_create and device_create. This will allow udev to create your device.
Are you saying you wrote a driver without looking at any other drivers?
Because there is no shortage of examples about how to register a character device.
Look in
drivers/char
Those aforementioned functions are GPL-only, by the way, which has implications if you want to redistribute the code.
The mknod() system call used to be used...but only a root-privileged process can create devices in /dev usually.