Register level access in linux device driver - linux

I have only 2 weeks experience in linux driver development, but have good experience on embedded c programming. I have only tried character device driver in linux. Now i wish to try a device driver for a set of LED's connected to GPIO. I am using BeagleBone Black. I wish to access it from the register level and not by just calling any driver. (I am doing this to learn the basics)
I wish my driver GPIO access code to be somewhat like below
void SetLED(unsigned char LED,unsigned char Status){
//Read the port register
//BitWise Operation according to function parameters
//Write back to the register
}
But i need some help on how to access the registers directly in linux. I have got the actual address of the port OUT register from the datasheet as 0x4804C13C
Pardon me if i am breaking any basics in my question. I am really new to linux.

Your driver has to call
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);
to register exclusive access to that region of memory.
Then it must use ioread8(),ioread16(), etc. and iowrite8(),iowrite16(), etc.

Related

Disabling input devices from a Linux kernel module

I am writing a kernel module for detecting the tablet mode from a 2-in-1 laptop.
The module is accessing industrial I/O (or sensors) and needs to disable input devices (ex: internal keyboard and mouse). I would like doing it in kernel space to early disable the inputs (or the devices itself) if the laptop is powered on in tablet mode, avoiding users removing the splash screen at startup (for instance). Until now I have not found a way to disable the inputs without modifying the kernel sources.
1st idea:
Without modifying the kernel source,
my first attempt was to call the following function from linux/input.h, which "disables" a given input by ignoring its events:
void input_set_ignore_events(struct input_dev *dev, bool ignored)
I have found a way to get a struct device * device with its name as following, but I cannot find a way to get a struct input_dev * pointer from struct device *:
bus_find_device_by_name(&platform_bus_type, NULL, name);
Another idea would be to externaly access the static LIST_HEAD(input_dev_list); located into drivers/input/input.c.
2nd idea:
Do not try to access the kernel input abstraction but instead leverage offline() and suspend() functions of struct bus_type * from include/linux/device.h. According to the Documentation/ABI/testing/sysfs-devices-online it might work. I will try it soon.
Questions:
Is it possible to disable properly events or inputs from any external module ?
Is it possible to retrieve to a struct input_dev * from any external module ?
Thanks for your time.

How to set chip select in SPI programming for multipleslaves ? (struct spi_ioc_transfer)

Maybe I am asking the wrong question actually but I am just making my first steps in the embedded world. So I am sorry if the question is somehow stupid.
I am trying to program a software for 9DOF IMU in c++ and linux environment.
As far as I understood the SPI, the SS pin has to be low active in order for a transmission to occur. I have seen multiple reading or writing bytes function examples and all using the struct spi_ioc_transfer but they were all single slave examples and there is no mention about setting or configuring the SS in the code. Also When I check the structre of spi_ioc_transfer there is the cs_change however, how does it know which cs we are dealing with from the beginning ?
The chip select (CS or SS) to use is determined by which device node you open.
To talk to a SPI chip with the Linux spidev driver, you open a device such as /dev/spidev0.1. The numbers in the device node file name refer to the bus and chip select, respectively — in this example it would be the first bus (0) and the second CS (1). If you want to talk to devices on different chip-selects, you have to open different device nodes and do ioctls on the appropriate one.

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 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

Creating a device file: Linux device driver

How to create a device file when I do not know the minor and major number (i.e. by using dynamic registration) without using mknod or MAKEDEV.
Say you want to dynamically assign a major number to a char device on insertion, use:
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
From Linux Device Drivers 3rd Edition. Google it you can get the entire book for free along with tons of great source code for messing with drivers.
Also, the codes provided in the LDD3 are obsolete now. So, use this github repo to download example codes of LDD3: https://github.com/martinezjavier/ldd3

Resources