how to get struct device's private data in the Linux's chrdev ->open() function? - linux

I'm a beginnig learner of linux driver, so far I've studied how to write an basic char device driver and platform driver. I'm pricticing on the led example, I want to improve it from basic char device driver model to platform driver model.
In the earlier practice, I define a global int gpio_num[MAX_LED_NUM] array to keep the led's gpio. It's easy because I can indentify the led by device's minor number, and operate the corresponding led by referencing gpio_num[minor];
But in this improvement, I don't want to use global array to keep led's gpio because I can't predict how many leds on the board. So I malloc a structure for every platform device in the probe function to keep their own gpio, and call device_create() to create device node. It seems good so far because how many leds are there, there are how many structures and device nodes in the /dev directory, and there is no global variables.
In order to seperate led operation functions from char device driver, I define the led operaions functions in the platform driver part(driver.c) and pass the function sets to the char device driver part(leds.c). for example , I define the alpha_led_init(struct drv_priv *priv) in the driver.c, and call it from char device's open function(in leds.c) .
in order to call alpha_led_init(struct drv_priv *priv), the open function needs the parameter *priv(the private data of platform device which contains led_gpio). I've pass the private data to the char device by using device_create()'s third parameter. But how can I get it from the open function ? I can't get the struct device *pdev in the open function, so I can't call dev_get_drvdata(pdev) to get the platform device's private data , so there's no way to call alpha_led_init(struct drv_priv *priv).
Is my program model very bad? Any good way to pass platform device's private data to char device ? Any help or advice would be appreciating.
Below is my practicing code, for simplicity, some header files're omitted.
alpha_led.h
#ifndef __ALPHA_LED_H__
#define __ALPHA_LED_H__
#define LED_OFF (1)
#define LED_ON (0)
#define LED_MAX_NUM (10)
struct drv_priv
{
int led_gpio;
};
struct alpha_led_operations
{
int inited;
int (*alpha_led_init)(struct drv_priv *pdev);
};
#endif
driver.c
#include "alpha_led.h"
static int led_count;
static int alpha_led_init(struct drv_priv *priv)
{
int err;
char name[64];
if(!priv)
return -1;
memset(name, 0, sizeof(name));
snprintf(name, sizeof(name), "alpha-led-pin-%d", priv->led_gpio);
err = gpio_request(priv->led_gpio, name);
if(err)
return -1;
err = gpio_direction_output(priv->led_gpio, LED_OFF);
if(err) {
gpio_free(priv->led_gpio);
return -1;
}
return 0;
}
static int alpha_led_probe(struct platform_device *pdev)
{
int err, gpio;
const char *status = NULL;
struct drv_priv *priv = NULL;
struct device_node *np = pdev->dev.of_node;
if(!np)
return -1;
err = of_property_read_string(np, "status", &status);
if(err || (strcmp(status, "okay") != 0))
return -1;
gpio = of_get_named_gpio(np, "led-gpio", 0);
if(gpio < 0)
return -1;
// I malloc a drv_priv structure for every platform device to keep their private data
priv = devm_kzalloc(&pdev->dev, sizeof(struct drv_priv), GFP_KERNEL);
if(!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
// for every platform device, the gpio number is their private data.
priv->led_gpio = gpio;
// I call self-defined function in leds.c to create device node in /dev directory
// and pass the platform device's private data(priv) to the device_create()
return create_led_device_node(led_count++, np->name, priv);
}
static int alpha_led_remove(struct platform_device *pdev)
{
// get the platform device's private data
struct drv_priv *priv = platform_get_drvdata(pdev);
gpio_free(priv->led_gpio);
}
static const struct of_device_id alpha_led_of_match[] = {
{ .compatible = "alientek-alpha,led" },
{}
};
static struct platform_driver alpha_led_driver = {
.probe = alpha_led_probe,
.remove = alpha_led_remove,
.driver = {
.name = "alpha-led",
.of_match_table = alpha_led_of_match,
}
};
static int __init platform_driver_led_init(void)
{
int rc;
struct alpha_led_operations *ops;
rc = platform_driver_register(&alpha_led_driver);
// pass the lower led control functions to leds.c
ops = get_alpha_led_ops();
ops->alpha_led_init = alpha_led_init;
ops->inited = 1;
return 0;
}
static void __exit platform_driver_led_exit(void)
{
platform_driver_unregister(&alpha_led_driver);
}
module_init(platform_driver_led_init);
module_exit(platform_driver_led_exit);
MODULE_AUTHOR("David");
MODULE_LICENSE("GPL");
leds.c
#include "alpha_led.h"
#define LED_DEV_NAME ("alpha-led")
#define LED_CLASS_NAME ("alpha-led-class")
static int led_major;
static struct cdev led_cdev;
static struct class *led_class;
static int led_open(struct inode *inode, struct file *filp);
static int led_close(struct inode *inode, struct file *filp);
static struct alpha_led_operations alpha_led_ops;
static const struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_close,
};
static int led_open(struct inode *inode, struct file *filp)
{
int err, minor;
if(!inode || !filp)
return -1;
if(!alpha_led_ops.inited)
return -1;
if(!alpha_led_ops.alpha_led_init)
return -1;
//Question: here I want to call alpha_led_init(struct drv_priv *priv) defined in the driver.c
//But how can I get the parameter priv ? I know I have set it in the device_create(), but how can I fetch it here?
//Or Am writing a very bad platform driver model?
return alpha_led_ops.alpha_led_init(...);
}
static int led_close(struct inode *inode, struct file *filp)
{
return 0;
}
static int __init chrdev_led_init(void)
{
dev_t devid;
int i, rc, major, minor;
struct device *pdev;
if (led_major) {
devid = MKDEV(led_major, 0);
rc = register_chrdev_region(devid, LED_MAX_NUM, LED_DEV_NAME);
} else {
rc = alloc_chrdev_region(&devid, 0, LED_MAX_NUM, LED_DEV_NAME);
led_major = MAJOR(devid);
}
if(rc < 0)
goto chrdev_failed;
cdev_init(&led_cdev, &led_fops);
rc = cdev_add(&led_cdev, devid, LED_MAX_NUM);
if(rc < 0)
goto cdev_failed;
led_class = class_create(THIS_MODULE, LED_CLASS_NAME);
if(IS_ERR(led_class))
goto class_failed;
return 0;
class_failed:
cdev_del(&led_cdev);
cdev_failed:
unregister_chrdev_region(devid, LED_MAX_NUM);
chrdev_failed:
return -1;
}
static void __exit chrdev_led_exit(void)
{
class_destroy(led_class);
cdev_del(&led_cdev);
unregister_chrdev_region(MKDEV(led_major, 0), LED_MAX_NUM);
}
int create_led_device_node(int minor, const char *name, void *priv)
{
struct device *dev = NULL;
if(minor >= LED_MAX_NUM)
return NULL;
//device_create take the platform device's private data(priv) as it's own private data.
if(name)
dev = device_create(led_class, NULL, MKDEV(led_major, minor), priv, "%s", name);
else
dev = device_create(led_class, NULL, MKDEV(led_major, minor), priv, "led-%d", minor);
if(!dev)
return -1;
return 0;
}
void destroy_led_device_node(int minor)
{
device_destroy(led_class, MKDEV(led_major, minor));
}
struct alpha_led_operations * get_alpha_led_ops(void)
{
return &alpha_led_ops;
}
EXPORT_SYMBOL(create_led_device_node);
EXPORT_SYMBOL(destroy_led_device_node);
EXPORT_SYMBOL(get_alpha_led_ops);
module_init(chrdev_led_init);
module_exit(chrdev_led_exit);
MODULE_AUTHOR("David");
MODULE_LICENSE("GPL");

Related

Linux custom device driver probe and init functions are not being called

I have built a custom hardware configuration in Vivado for Xilinx SoC board, and used petalinux to create a custom driver to control the hardware logic. It seems like after running insmod command, the driver is never initialized and the ->probe() function is not called.
I am new to this domain, and wondering if anyone ran into a similar issue and has some pointers on where and what to check in order to see where the issue is. Any advice would be very helpful!
Running the dmesg command after inserting the driver into the kernel:
root#plzwork3:/proc/device-tree/amba_pl#0/simpleMultiplier#a0000000# dmesg
[ 3351.680317] <1>Hello module world.
[ 3351.683735] <1>Module parameters were (0xdeadbeef) and "default"
Device Tree entity created by Vivado:
/ {
amba_pl: amba_pl#0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
simpleMultiplier_0: simpleMultiplier#a0000000 {
clock-names = "axiliteregport_aclk";
clocks = <&zynqmp_clk 71>;
compatible = "xlnx,simpleMultiplier-1.0";
reg = <0x0 0xa0000000 0x0 0x10000>;
xlnx,axiliteregport-addr-width = <0x4>;
xlnx,axiliteregport-data-width = <0x20>;
};
};
};
Device driver code snippets:
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
Full device driver code:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/fs.h>
/* Standard module information, edit as appropriate */
MODULE_LICENSE("GPL");
MODULE_AUTHOR
("Xilinx Inc.");
MODULE_DESCRIPTION("simpmod - loadable module template generated by petalinux-create -t modules");
#define DRIVER_NAME "simpmod"
#define CLASS_NAME "CLASS_TUT"
static char ker_buf[100];
static int currLen = 0;
// Parts of the math operation (2,2,+) is 2+2
static int operand_1 = 0;
static int operand_2 = 0;
static int result = 0;
static struct class *driver_class = NULL;
static dev_t first;
static struct cdev c_dev; // Global variable for the character device
static struct device *ourDevice;
// Pointer to the IP registers
volatile unsigned int *regA;
volatile unsigned int *regB;
volatile unsigned int *regC;
// Structure to hold device specific data
struct simpmod_local {
int irq;
unsigned long mem_start;
unsigned long mem_end;
void __iomem *base_addr;
};
// Character callbacks prototype
static int dev_open(struct inode *inod, struct file *fil);
static ssize_t dev_read(struct file *fil, char *buf, size_t len, loff_t *off);
static ssize_t dev_write(struct file *fil, const char *buf, size_t len, loff_t *off);
static int dev_release(struct inode *inod, struct file *fil);
static struct file_operations fops = {
.read=dev_read,
.write=dev_write,
.open=dev_open,
.release=dev_release,
};
static irqreturn_t simpmod_irq(int irq, void *lp){
printk("simpmod interrupt\n");
return IRQ_HANDLED;
}
static int simpmod_probe(struct platform_device *pdev){
struct resource *r_irq; /* Interrupt resources */
struct resource *r_mem; /* IO mem resources */
struct device *dev = &pdev->dev;
static struct simpmod_local *lp = NULL;
int rc = 0;
printk("Device Tree Probing\n");
// Get data of type IORESOURCE_MEM(reg-addr) from the device-tree
// Other types defined here:
// http://lxr.free-electrons.com/source/include/linux/ioport.h#L33
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r_mem) {
dev_err(dev, "invalid address\n");
return -ENODEV;
}
// Allocate memory (continuous physical)to hold simpmod_local struct
lp = (struct simpmod_local *) kmalloc(sizeof(struct simpmod_local), GFP_KERNEL);
if (!lp) {
printk("Cound not allocate simpmod device\n");
return -ENOMEM;
}
dev_set_drvdata(dev, lp);
// Save data on simpmod_local strucutre
lp->mem_start = r_mem->start;
lp->mem_end = r_mem->end;
// Ask the kernel the memory region defined on the device-tree and
// prevent other drivers to overlap on this region
// This is needed before the ioremap
if (!request_mem_region(lp->mem_start,
lp->mem_end - lp->mem_start + 1,
DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at %p\n",
(void *)lp->mem_start);
rc = -EBUSY;
goto error1;
}
// Get an virtual address from the device physical address with a
// range size: lp->mem_end - lp->mem_start + 1
lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
if (!lp->base_addr) {
dev_err(dev, "simpmod: Could not allocate iomem\n");
rc = -EIO;
goto error2;
}
// ****************** NORMAL Device diver *************************
// register a range of char device numbers
if (alloc_chrdev_region(&first, 0, 1, "Leonardo") < 0){
printk(KERN_ALERT "alloc_chrdev_region failed\n");
return -1;
}
// Create class (/sysfs)
driver_class = class_create(THIS_MODULE, CLASS_NAME);
if (driver_class == NULL) {
printk(KERN_ALERT "Create class failed\n");
unregister_chrdev_region(first, 1);
return -1;
}
ourDevice = device_create(driver_class, NULL, first, NULL, "tutDevice");
if ( ourDevice == NULL){
printk(KERN_ALERT "Create device failed\n");
class_destroy(driver_class);
unregister_chrdev_region(first, 1);
return -1;
}
// Create a character device /dev/tutDevice
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, first, 1) == -1){
printk(KERN_ALERT "Create character device failed\n");
device_destroy(driver_class, first);
class_destroy(driver_class);
unregister_chrdev_region(first, 1);
return -1;petalinux-config -c rootfs
}
// Create the attribute file on /sysfs/class/CLASS_TUT/ called
// parCrtl and isBusy
// Get data of type IORESOURCE_IRQ(interrupt) from the device-tree
r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!r_irq) {
printk("no IRQ found\n");
printk("simpmod at 0x%08x mapped to 0x%08x\n",
(unsigned int __force)lp->mem_start,
(unsigned int __force)lp->base_addr);
// Configuring pointers to the IP registers
regA = (unsigned int __force)lp->base_addr + 0x10;
regB = (unsigned int __force)lp->base_addr + 0x18;
regC = (unsigned int __force)lp->base_addr + 0x26;
printk("regA: 0x%08x\n",(unsigned int)regA);
printk("regB: 0x%08x\n",(unsigned int)regB);
printk("regC: 0x%08x\n",(unsigned int)regC);
return 0;
}
lp->irq = r_irq->start;
rc = request_irq(lp->irq, &simpmod_irq, 0, DRIVER_NAME, lp);
if (rc) {
dev_err(dev, "testmodule: Could not allocate interrupt %d.\n",
lp->irq);
goto error3;
}
return 0;
error3:
free_irq(lp->irq, lp);
error2:
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
kfree(lp);
dev_set_drvdata(dev, NULL);
return rc;
}
static int simpmod_remove(struct platform_device *pdev){
struct device *dev = &pdev->dev;
struct simpmod_local *lp = dev_get_drvdata(dev);
free_irq(lp->irq, lp);
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
kfree(lp);
dev_set_drvdata(dev, NULL);
return 0;
}
// Indicate which type of hardware we handle on this case(simpleAlu-1.0)
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, simpmod_of_match);
#else
# define simpmod_of_match
#endif
static struct platform_driver simpmod_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = simpmod_of_match,
},
.probe = simpmod_probe,
.remove = simpmod_remove,
};
static int __init simpmod_init(void)
{
printk("<1>Simple device driver.\n");
printk("Hussam was here, and he init the module\n");
return platform_driver_register(&simpmod_driver);
}
static void __exit simpmod_exit(void)
{
platform_driver_unregister(&simpmod_driver);
printk(KERN_ALERT "Goodbye module world.\n");
}
static int dev_open(struct inode *inod, struct file *fil){
printk(KERN_ALERT "Character device opened\n");
return 0;
}
// Just send to the user a string with the value of result
static ssize_t dev_read(struct file *fil, char *buf, size_t len, loff_t *off){
// Return the result only once (otherwise a simple cat will loop)
// Copy from kernel space to user space
printk(KERN_ALERT "Reading device rx: %d\n",(int)len);
int n = sprintf(ker_buf, "%d\n", *regC);
// Copy back to user the result (to,from,size)
copy_to_user(buf,ker_buf,n);
printk(KERN_ALERT "Returning %s rx: %d\n",ker_buf,n);
return n;
}
// Parse the input stream ex: "50,2,*" to some operand variables.
static ssize_t dev_write(struct file *fil, const char *buf, size_t len, loff_t *off){
// Get data from user space to kernel space
copy_from_user(ker_buf,buf,len);
sscanf (ker_buf,"%d,%d,%c",&operand_1,&operand_2);
ker_buf[len] = 0;
// Change the IP registers to the parsed operands (on rega and regb)
*regA = (unsigned int)operand_1;
*regB = (unsigned int)operand_2;
printk(KERN_ALERT "Receiving math operation <%d %d>\n",operand_1,operand_2);
return len;
}
static int dev_release(struct inode *inod, struct file *fil){
printk(KERN_ALERT "Device closed\n");
return 0;
}
module_init(simpmod_init);
module_exit(simpmod_exit);
the problem is, that the (compatible) names in your device tree does not match with those in your code:
Device Tree
compatible = "simple-bus";
Code:
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
Put your device tree:
compatible = "xlnx,simpleMultiplier-1.0";
Both entries should match!
Now your "probe" function should be called!
BR
Andreas
your of_match table section in the driver code:
// Indicate which type of hardware we handle on this case(simpleAlu-1.0)
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, simpmod_of_match);
#else
# define simpmod_of_match
#endif
should be like this:
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, simpmod_of_match);
and make sure the compatible line strings have to match in the pl.dtsi and of_match table

i2c kernel driver - Binding between sysfs kobject and i2c_client

I am working on an I2C kernel driver and would like to provide a sysfs file interface in a new folder - /sys/devices/MySensor. However, when I do this I don't know how to associate the i2c client with the new kobject.
Consequently, when my device attribute functions are called, the device object passed in does not allow me to retrieve the registered i2c client.
I declare my attribute as follows:
static ssize_t my_sensor_do_something(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client;
struct my_sensor_data *data;
int size = 0;
client = to_i2c_client(dev);
my_sensor_dbgmsg("Client Address:0x%02x\n", client->addr);
data = i2c_get_clientdata(client);
return 0
}
static DEVICE_ATTR(do_something, S_IRUGO, my_sensor_do_something, NULL);
static struct attribute *my_sensor_attributes[] = {
&dev_attr_do_something.attr,
NULL
};
static const struct attribute_group my_sensor_attr_group = {
.attrs = my_sensor_attributes,
};
Then, in my probe function, create my subfolder
struct device *my_dev = root_device_register("my_sensor");
err = sysfs_create_group(&my_dev->kobj, &my_sensor_attr_group);
The sub-folder and do_something file is created in /sys/kernel/, however when do_something() is called, the attempt to retrieve the I2C client fails - client->addr is 0 and i2c_get_client_data returns null.
For info, the i2c device is defined in a device tree and I can successfully add device attributes to the existing folder
err = sysfs_create_group(client->dev.kobj, &my_sensor_attr_group);
/sys/bus/i2c/devices/i2c-7/7-004c/
Apologies if this question is vague or lacking sufficient detail. I'm relatively new to this.
Does anyone have an idea what I am missing when I create a new sysfs folder, to associate this with my registered i2c client?
Thanks
You can put the client on my_dev at initialization time.
dev_set_drvdata(my_dev, client);
Then in the my_sensor_do_something function, use dev_get_drvdata to take the client out
client = dev_get_drvdata(dev);
The complete example is as follows
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
static ssize_t my_sensor_do_something(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client;
void *data;
client = dev_get_drvdata(dev);
data = i2c_get_clientdata(client);
pr_info("Client Address:0x%02x Data:%p\n", client->addr, data);
return 0;
}
static DEVICE_ATTR(do_something, 0444, my_sensor_do_something, NULL);
static struct attribute *my_sensor_attributes[] = {
&dev_attr_do_something.attr,
NULL
};
static const struct attribute_group my_sensor_attr_group = {
.attrs = my_sensor_attributes,
};
static struct device *my_dev;
static void my_sensor_create(struct i2c_client *client)
{
int err;
my_dev = root_device_register("my_sensor");
dev_set_drvdata(my_dev, client);
err = sysfs_create_group(&my_dev->kobj, &my_sensor_attr_group);
if (err)
pr_info("sysfs_create_group failure.\n");
}
struct test_device {
struct i2c_client *client;
};
static int test_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct test_device *dev;
dev = kzalloc(sizeof(struct test_device), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
dev->client = client;
i2c_set_clientdata(client, dev);
my_sensor_create(client);
return 0;
}
static int test_i2c_remove(struct i2c_client *client)
{
struct test_client *dev = i2c_get_clientdata(client);
if (my_dev)
root_device_unregister(my_dev);
kfree(dev);
return 0;
}
static const struct i2c_device_id test_i2c_id[] = {
{"test_i2c_client", 0},
{}
};
static struct i2c_driver test_i2c_driver = {
.driver = { .name = "test_i2c_client", },
.probe = test_i2c_probe,
.remove = test_i2c_remove,
.id_table = test_i2c_id,
};
static int __init test_i2c_init_driver(void)
{
return i2c_add_driver(&test_i2c_driver);
}
static void __exit test_i2c_exit_driver(void)
{
i2c_del_driver(&test_i2c_driver);
}
module_init(test_i2c_init_driver);
module_exit(test_i2c_exit_driver);
MODULE_LICENSE("GPL");

How are the steps to access GPIOs in linux kernel modules?

I am struggling to find out, what steps are necessary to access a gpio-pin from a linux kernel module.
Maybe someone can explain it to me by a simple example. I like to use pin 4(input) and 33(output). My steps so far:
1.) Device Tree(dts): I leave the dts file untouched - Do I need to setup the pin 4 and 33 via pin control?
2.) kernel module: some pseudo code
gpio_is_valid(4)
gpio_request_one(4, GPIOF_DIR_IN | GPIOF_EXPORT_DIR_FIXED , "myPin4")
gpio_export(4, false)
gpio_get_value(4)
gpio_is_valid(33)
gpio_request_one(33, GPIOF_DIR_OUT | GPIOF_INIT_LOW | GPIOF_OPEN_SOURCE | GPIOF_EXPORT_DIR_FIXED , "myPin33")
gpio_export(33, false)
gpio_set_value(33, 1)
How to do it in a proper way?
I would suggest the combination of an own device tree file + a platform driver + character driver
0.) RTF
check how device trees(dts) are working
check how a platform device works
check how a character device works
gain some knowledge about gpios and dts
#gpio mappings
#subsystems using gpios
#Specifying GPIO information for devices
Read the informations provided by your SOC manufacturer.
The state-of-the-art way to access the gpios is via struct gpio_desc variables. They are created form the device tree.
1.) approach
To toggle a pin under linux you need to make shure, that 3 units are working togehter.
The pin-controller(pinctrl) defines how the output is driven. Open source, pull up etc.
The pin-multiplexer(pinmux) defines different functions for the pin.
The gpio-controller(gpioctrl) translates the gpio number. p.E.: 44 -> GPIO A 11
These components are implemented by the SOC manufacturer. For each platform there are differences. An example for the SAMA5D35xxx follows.
#the device tree
Define the pin controller
pinctrl#fffff200 {
pinctrl_myPins: myPins {
atmel,pins = <AT91_PIOA 2 AT91_PERIPH_GPIO AT91_PINCTRL_NONE // pin 1
AT91_PIOD 19 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>; // pin 2
};
};
Create a node witch is linked to the own platform device:
myPins {
compatible = "myPlatformDevice";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_myPins>;
pin1 = <&pioA 2 GPIO_ACTIVE_HIGH>;
pin2 = <&pioD 19 GPIO_ACTIVE_HIGH>;
};
#create platform + char driver (pseudo code):
// ----------------------
// kernel message support(via dmesg)
// ----------------------
#define KMSG_DEBUG(fmt,args...) printk(KERN_DEBUG "myDrv" ": "fmt"\n", ##args)
#define KMSG_PERR(fmt,args...) printk(KERN_ERR "myDrv" ": "fmt"\n", ##args)
#define KMSG_PINFO(fmt,args...) printk(KERN_INFO "myDrv" ": "fmt"\n", ##args)
// ----------------------
// trace support via defining dMyDrvTrace
// ----------------------
#ifndef dMyDrvTrace
#define TRACE(...)
#else
#define TRACE(fmt,args...) printk(KERN_INFO "myDrv" ": [%s] "fmt"\n", __FUNCTION__, ##args)
#endif
typedef struct SMyDrvDrvData {
struct platform_device *pdev; //!< next device
// here goes the local/private data
int gpiod_pin1;
int gpiod_pin2;
u32 pin1;
u32 pin2;
} TMyDrvDrvData;
static struct dentry * gmyPlattformDrvDebugfsRootDir; //!< root dir at debugfs
static int myPlattformDrv_probe(struct platform_device *pdev);
static int myPlattformDrv_remove(struct platform_device *pdev);
#if defined(CONFIG_OF)
//! filter for the device tree class
static struct of_device_id gMyPlattformDrvdtsFilter[] = {
{.compatible = "myPlatformDevice"},
{}
};
MODULE_DEVICE_TABLE(of, gMyPlattformDrvdtsFilter);
#else
#define gmyPlattformDrvdtsFilter (NULL)
#endif
static struct platform_device *MyPlattformDrv_devs[] = {
};
static struct platform_driver myPlattformDrv_driver = {
.driver = {
.name = dMyPlattformDrvdriver,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(gMyPlattformDrvdtsFilter),
},
.probe = myPlattformDrv_probe,
.remove = myPlattformDrv_remove,
};
// char device
static dev_t gMyCharDev;
static struct class *gMyCharDevClass;
static struct cdev gMyCharDev_cdev;
static int dev_open (struct inode *, struct file *);
static int dev_release (struct inode *, struct file *);
static ssize_t dev_read (struct file *, char *, size_t, loff_t *);
static ssize_t dev_write (struct file *, const char *, size_t, loff_t *);
static const struct file_operations gMyCharDevOps =
{
.read = dev_read,
.open = dev_open,
.write = dev_write,
.release = dev_release
};
//! looks up for the gpio name and request it
static int get_gpio(struct platform_device *pdev, const char * name, int * pGPIOnum)
{
int n,i;
int r;
struct device_node * pDN;
TRACE("look at %s for %s ...", pdev->name, name);
// reset return value
*pGPIOnum = 0;
// parse device tree
// get device tree entries associated with the device
pDN = of_find_node_by_name(NULL, pdev->name);
// parse pins
n = of_gpio_named_count(pDN, name);
if (n <= 0) {
TRACE("no gpios found");
return -1;
}
for (i = 0; i < n; i++) {
// get pin number
*pGPIOnum = of_get_named_gpio(pDN,name, i);
if (*pGPIOnum == -EPROBE_DEFER) {
return r;
}
// check if pin number is valid
if (gpio_is_valid(*pGPIOnum)) {
// yes
// request pin
r = devm_gpio_request(&pdev->dev, *pGPIOnum, name);
if (r) {
return r;
} else {
r = gpio_direction_output(*pGPIOnum, 0);
}
if (r) return r;
}
}
}
return 0;
}
//! probes the platform driver
static int myPlattformDrv_probe(struct platform_device *pdev)
{
struct TMyDrvDrvData *priv;
int i,j,r,gpioNum, ret;
KMSG_PINFO("probe my driver ...");
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
KMSG_PERR("Failed to allocate memory for the private data structure");
return -ENOMEM;
}
priv->pdev = pdev;
platform_set_drvdata(pdev, priv);
TRACE("setup gpios ...");
r = get_gpio(pdev, "pin1", &gpioNum);
if (r) {
KMSG_PERR("Failed to find gpio \"pin1\" in device tree");
}
// save number
priv->gpiod_pin1 = gpioNum;
// create "pin1" debugfs entry
debugfs_create_u32("pin1", S_IRUGO, gmyPlattformDrvDebugfsRootDir, &priv->Pin1);
r = get_gpio(pdev, "pin2", &gpioNum);
if (r) {
KMSG_PERR("Failed to find gpio \"pin2\" in device tree");
}
// save number
priv->gpiod_pin2 = gpioNum;
// create "pin2" debugfs entry
debugfs_create_u32("pin1", S_IRUGO, gmyPlattformDrvDebugfsRootDir, &priv->Pin2);
// create device class
TRACE("create myCharDev char device class");
// create char dev region
ret = alloc_chrdev_region(&gMyCharDev, 0, 1, "myCharDev");
if( ret < 0) {
KMSG_PERR("alloc_chrdev_region error %i", ret);
goto error;
}
// create device class
if((gMyCharDevClass = class_create(THIS_MODULE, dSEK4DevClass)) == NULL)
{
KMSG_PERR("class_create error");
goto error_classCreate;
}
if(NULL == device_create(gMyCharDevClass, NULL, gMyCharDev, NULL, "myCharDev"))
{
KMSG_PERR("device_create error");
goto error_deviceCreate;
}
cdev_init(&gMyCharDev_cdev, &gMyCharDevOps);
ret = cdev_add(&gMyCharDev_cdev, gMyCharDev, 1);
if(-1 == ret) {
KMSG_PERR("cdev_add error %i", ret);
goto error_device_add;
return -1;
}
TRACE("added myCharDev char device");
return 0;
// error handling block
error_std:
error_device_add:
device_destroy(gMyCharDevClass, gMyCharDev);
error_deviceCreate:
class_destroy(gMyCharDevClass);
error_classCreate:
unregister_chrdev_region(gMyCharDev, 1);
error:
return -1;
}

read USB bulk message on Linux

I am trying lessons on USB http://www.linuxforu.com/2011/12/data-transfers-to-from-usb-devices/ and stuck with the problem - while reading, usb_bulk_msg returns error 22 - Invalid argument. Write operation succeeds.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#define BULK_EP_OUT 0x01
#define BULK_EP_IN 0x82
#define MAX_PKT_SIZE 512
static struct usb_device *device;
static struct usb_class_driver class;
static unsigned char bulk_buf[MAX_PKT_SIZE];
static int pen_open(struct inode *i, struct file *f)
{
return 0;
}
static int pen_close(struct inode *i, struct file *f)
{
return 0;
}
static ssize_t pen_read(struct file *f, char __user *buf, size_t cnt, loff_t *off)
{
int retval;
int read_cnt;
/* Read the data from the bulk endpoint */
retval = usb_bulk_msg(device, usb_rcvbulkpipe(device, BULK_EP_IN),
bulk_buf, MAX_PKT_SIZE, &read_cnt, 5000);
if (retval)
{
printk(KERN_ERR "Bulk message returned %d\n", retval);
return retval;
}
if (copy_to_user(buf, bulk_buf, MIN(cnt, read_cnt)))
{
return -EFAULT;
}
return MIN(cnt, read_cnt);
}
static ssize_t pen_write(struct file *f, const char __user *buf, size_t cnt, loff_t *off)
{
int retval;
int wrote_cnt = MIN(cnt, MAX_PKT_SIZE);
if (copy_from_user(bulk_buf, buf, MIN(cnt, MAX_PKT_SIZE)))
{
return -EFAULT;
}
/* Write the data into the bulk endpoint */
retval = usb_bulk_msg(device, usb_sndbulkpipe(device, BULK_EP_OUT),
bulk_buf, MIN(cnt, MAX_PKT_SIZE), &wrote_cnt, 5000);
if (retval)
{
printk(KERN_ERR "Bulk message returned %d\n", retval);
return retval;
}
return wrote_cnt;
}
static struct file_operations fops =
{
.open = pen_open,
.release = pen_close,
.read = pen_read,
.write = pen_write,
};
static int pen_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
int retval;
device = interface_to_usbdev(interface);
class.name = "usb/pen%d";
class.fops = &fops;
if ((retval = usb_register_dev(interface, &class)) < 0)
{
/* Something prevented us from registering this driver */
err("Not able to get a minor for this device.");
}
else
{
printk(KERN_INFO "Minor obtained: %d\n", interface->minor);
}
return retval;
}
static void pen_disconnect(struct usb_interface *interface)
{
usb_deregister_dev(interface, &class);
}
/* Table of devices that work with this driver */
static struct usb_device_id pen_table[] =
{
{ USB_DEVICE(0x058F, 0x6387) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, pen_table);
static struct usb_driver pen_driver =
{
.name = "pen_driver",
.probe = pen_probe,
.disconnect = pen_disconnect,
.id_table = pen_table,
};
static int __init pen_init(void)
{
int result;
/* Register this driver with the USB subsystem */
if ((result = usb_register(&pen_driver)))
{
err("usb_register failed. Error number %d", result);
}
return result;
}
static void __exit pen_exit(void)
{
/* Deregister this driver with the USB subsystem */
usb_deregister(&pen_driver);
}
module_init(pen_init);
module_exit(pen_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email_at_sarika-pugs_dot_com>");
MODULE_DESCRIPTION("USB Pen Device Driver");
There could be many possible reasons for this error but in my case it happened that the BULK_EP address was wrong. I recommend setting up your endpoint addresses in the probe function rather than hard-coding them. Feel free to refer the below code to setup bulk endpoint addresses.
static void
set_bulk_address (
struct my_device *dev,
struct usb_interface *interface)
{
struct usb_endpoint_descriptor *endpoint;
struct usb_host_interface *iface_desc;
int i;
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
/* check for bulk endpoint */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK){
/* bulk in */
if(endpoint->bEndpointAddress & USB_DIR_IN) {
dev->bulk_in_add = endpoint->bEndpointAddress;
dev->bulk_in_size = endpoint->wMaxPacketSize;
dev->bulk_in_buffer = kmalloc(dev->bulk_in_size,
GFP_KERNEL);
if (!dev->bulk_in_buffer)
print("Could not allocate bulk buffer");
}
/* bulk out */
else
dev->bulk_out_add = endpoint->bEndpointAddress;
}
}
}
As you may notice, I have defined my own device struct to hold the endpoint information. Here is my struct definition
struct my_device {
struct usb_device *udev; /* usb device for this device */
struct usb_interface *interface; /* interface for this device */
unsigned char minor; /* minor value */
unsigned char * bulk_in_buffer; /* the buffer to in data */
size_t bulk_in_size; /* the size of the in buffer */
__u8 bulk_in_add; /* bulk in endpoint address */
__u8 bulk_out_add; /* bulk out endpoint address */
struct kref kref; /* module references counter */
};
The error is coming because you have to mention the correct bulk endpoints as per your usb device not the ones given in the example code.
For that you can either check /sys/kernel/debug/usb/devices file or /proc/bus/usb/devices.
In the file check the section containing your device's vendorId and productId and in that section check the E segment for endpoints.
In that segment the one with (I) will be BULK_EP_IN value and the one with (O) will be the value for BULK_EP_OUT.

How can I create a device node from the init_module code of a Linux kernel module?

I am writing a module for the Linux kernel, and I want to create some device nodes in the init() function:
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
// Now I want to create device nodes
// with the returned major number
}
I also want the kernel to assign a minor number for my first node, and then I will assign the other nodes' minor numbers by myself.
How can I do this in the code? I don’t want to create devices from the shell using mknod().
To have more control over the device numbers and the device creation, you could do the following steps (instead of register_chrdev()):
Call alloc_chrdev_region() to get a major number and a range of minor numbers to work with.
Create a device class for your devices with class_create().
For each device, call cdev_init() and cdev_add() to add the character device to the system.
For each device, call device_create(). As a result, among other things, Udev will create device nodes for your devices. There isn’t any need for mknod() or the like. device_create() also allows you to control the names of the devices.
There are probably many examples of this on the Internet, and one of them is here.
static int __init ofcd_init(void) /* Constructor */
{
printk(KERN_INFO "Welcome!");
if (alloc_chrdev_region(&first, 0, 1, "char_dev") < 0) //$cat /proc/devices
{
return -1;
}
if ((cl = class_create(THIS_MODULE, "chardrv")) == NULL) //$ls /sys/class
{
unregister_chrdev_region(first, 1);
return -1;
}
if (device_create(cl, NULL, first, NULL, "mynull") == NULL) //$ls /dev/
{
class_destroy(cl);
unregister_chrdev_region(first, 1);
return -1;
}
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, first, 1) == -1)
{
device_destroy(cl, first);
class_destroy(cl);
unregister_chrdev_region(first, 1);
return -1;
}
return 0;
}
Minimal runnable example
Minimized from other answers. GitHub upstream with test setup.
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/module.h>
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
#define NAME "lkmc_character_device_create"
static int major = -1;
static struct cdev mycdev;
static struct class *myclass = NULL;
static int show(struct seq_file *m, void *v)
{
seq_printf(m, "abcd");
return 0;
}
static int open(struct inode *inode, struct file *file)
{
return single_open(file, show, NULL);
}
static const struct file_operations fops = {
.llseek = seq_lseek,
.open = open,
.owner = THIS_MODULE,
.read = seq_read,
.release = single_release,
};
static void cleanup(int device_created)
{
if (device_created) {
device_destroy(myclass, major);
cdev_del(&mycdev);
}
if (myclass)
class_destroy(myclass);
if (major != -1)
unregister_chrdev_region(major, 1);
}
static int myinit(void)
{
int device_created = 0;
/* cat /proc/devices */
if (alloc_chrdev_region(&major, 0, 1, NAME "_proc") < 0)
goto error;
/* ls /sys/class */
if ((myclass = class_create(THIS_MODULE, NAME "_sys")) == NULL)
goto error;
/* ls /dev/ */
if (device_create(myclass, NULL, major, NULL, NAME "_dev") == NULL)
goto error;
device_created = 1;
cdev_init(&mycdev, &fops);
if (cdev_add(&mycdev, major, 1) == -1)
goto error;
return 0;
error:
cleanup(device_created);
return -1;
}
static void myexit(void)
{
cleanup(1);
}
module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");

Resources