ARM char device driver initialization isn't creating /dev/ file - linux

I am writing a driver for the GPIO pins on an ARM platform.
My driver works correctly and I've avoided the problem until
now by manually mknod'ing a device file.
my initialization code:
static int __init gpio_init (void)
{
void *ptr_error;
if (register_chrdev(249, "gpio_device", &fops) < 0){
printk(KERN_INFO "Registering device failed\n");
return -EINVAL;
}
if ((device_class = class_create(THIS_MODULE, "gpio_device"))
== NULL){
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Class creation failed\n");
return -EINVAL;
}
ptr_error = device_create(device_class, NULL, DEV_T, NULL, "gpio_device");
if (IS_ERR(ptr_error)){
class_destroy(device_class);
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Device creation failed\n");
return -EINVAL;
}
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, DEV_T, 1)){
device_destroy(device_class, DEV_T);
class_destroy(device_class);
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Cdev add failed\n");
return -EINVAL;
}
printk(KERN_INFO "Guten tag, GPIO driver initialized\n");
return SUCCESS;
}
This runs with no errors, except no file "gpio_device" is created in /dev.
I'm cross compiling for ARM onto kernel 2.6.39.4. (using arm-linux-gcc)
As I understand it, device_create should be creating the /dev file.

I tried running your code and found a few mistakes:
When you register with register_chrdev(), you should unregister with unregister_chrdev(). unregister_chrdev_region() is used to unregister a registration done with alloc_chrdev_region() or register_chrdev_region().
A call to register_chrdev() registers minor numbers 0-255 for the given major, and sets up a default cdev structure for each, therefore, you do not need to deal with the cdev_init() & cdev_add().
You should check the error using IS_ERR & PTR_ERR for class_create() & device_create() as PTR_ERR will turn the return pointer to the error code with a cast.
You can read more here: Char Device Registration.
After applying the modification I mentioned, the /dev/gpio_device is created without mknod:
int init_module(void)
{
void *ptr_error;
struct cdev* c_dev;
int result=0;
/* register_chrdev */
result=register_chrdev(my_major, "gpio_device", &fops);
if (result < 0)
{
printk(KERN_INFO "Registering device failed\n");
return result;
}
DEV_T = MKDEV(my_major, my_minor);
/* class_create */
device_class = class_create(THIS_MODULE, "gpio_device");
if (IS_ERR(device_class))
{
unregister_chrdev(my_major, "gpio_device");
printk(KERN_INFO "Class creation failed\n");
return PTR_ERR(device_class);
}
/* device_create */
ptr_error = device_create(device_class, NULL, DEV_T, NULL, "gpio_device");
if (IS_ERR(ptr_error))
{
class_destroy(device_class);
unregister_chrdev(my_major, "gpio_device");
printk(KERN_INFO "Device creation failed\n");
return PTR_ERR(ptr_error);
}
/* //removed
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, DEV_T, 1)){
device_destroy(device_class, DEV_T);
class_destroy(device_class);
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Cdev add failed\n");
return -EINVAL;
}*/
printk(KERN_INFO "Guten tag, GPIO driver initialized\n");
return SUCCESS;
}

I just figured out what was going on here.
We are using BuildRoot to create our custom
linux, and the it turns out we had compiled
out the udev device file management system.
So that's why this doesn't work.

Related

IRQ interrupt is not get triggered

My Driver Code :
static irqreturn_t pwm_cnt_interrupt(int irq, void *data)
{
printk("==> %s\r\n", __func__);
return IRQ_HANDLED;
}
static int ecap_cnt_probe(struct platform_device *pdev)
{
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
clk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(clk)) {
if (of_device_is_compatible(np, "ti,counter-ecap")) {
dev_warn(&pdev->dev, "Binding is obsolete.\n");
clk = devm_clk_get(pdev->dev.parent, "fck");
}
}
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(clk);
}
pc->clk_rate = clk_get_rate(clk);
if (!pc->clk_rate) {
dev_err(&pdev->dev, "failed to get clock rate\n");
return -EINVAL;
}
/* Get PWM IRQ number */
ecapirq = platform_get_irq(pdev, 0);
if (ecapirq < 0) {
printk(KERN_ERR "Could not get IRQ");
return -EINVAL;
}
printk(KERN_DEBUG "irq = %d\n", ecapirq);
oreore_dentry = debugfs_create_file("counter", 0666, NULL, &value, &fops);
if(request_irq(ecapirq, pwm_cnt_interrupt, IRQF_SHARED,
"counter", (void *)&counter)) {
printk(KERN_ERR "pwm counter: Can't allocate irq %d\n",
ecapirq);
return -EBUSY;
}
enable_irq(ecapirq);
return 0;
}
My Interrupt got registed in /proc/interrupts
But, Its not get triggered.
I have connected UART with my pwm interrupt pin. I m sending data using uart port. my irq handler is not get called at that time.
Need help on this.

Linux I2C device driver probe function is not called

I am trying to connect Analog Devices` ADV7182 video encoder chip which has I2C communication to config the chip and control MIPI video data over CSI-2.
The issue is that the probe function of the driver is not called unless I create a new I2C device manually in __init function. Like this:
static struct i2c_board_info i2c_board_info_adv[] = {
{
I2C_BOARD_INFO("adv7281-m", 0x21)
}};
static int __init adv7180_initialize (void) {
struct i2c_client *client;
struct i2c_adapter *adapter;
int i2c_bus_number = 3;
int ret = i2c_register_board_info(i2c_bus_number, i2c_board_info_adv, ARRAY_SIZE(i2c_board_info_adv));
if (ret) {
printk("ADV7180 i2c_register_board_info failed. Result %d\n", ret);
return -EINVAL;
}
ret = i2c_add_driver(&adv7180_driver);
if (ret) {
printk("ADV7180 i2c_add_driver failed. Result %d\n", ret);
return -EINVAL;
}
adapter = i2c_get_adapter(i2c_bus_number);
if (!adapter) {
printk("ADV7180 i2c_get_adapter failed. Result %d\n", ret);
return -EINVAL;
}
client = i2c_new_device(adapter, &i2c_board_info_adv[0]);
if (!client) {
printk("ADV7180 i2c_new_device failed. Result %d\n", ret);
return -EINVAL;
}
return 0; }
In the original driver for ADV7xxx devices there is only call of i2c_add_driver in init function. https://github.com/analogdevicesinc/linux/tree/adv7280 Unfortunately, I cannot use that driver directly because of different kernels versions (since it uses backward incompatible versions of video for linux) and kernel upgrade does not seem to work either for the device I use (NanoPC).
I am quite new to linux drivers so I think I do not understand something about the platform. Any help?

Linux Device Driver open error

I am new with Linux.
I have made a USB skeleton driver and one application program which open and close skeleton.
But it gives error can't open device.
Can anyone tell me the possible reason why this may happen?
This simple driver programs needs any device attached with usb port ?
Here is my application programs
int main()
/* no memory-swapping for this programm */
ret = mlockall(MCL_CURRENT | MCL_FUTURE);
if (ret) {
perror("ERROR : mlockall has failled");
exit(1);
}
/*
* Turn the NRTcurrent task into a RT-task.
* */
ret = rt_task_shadow(&rt_task_desc, NULL, 1, 0);
if (ret)
{
fprintf(stderr, "ERROR : rt_task_shadow: %s\n",
strerror(-ret));
exit(1);
}
/* open the device */
device = rt_dev_open(DEVICE_NAME, 0);
if (device < 0) {
printf("ERROR : can't open device %s (%s)\n",
DEVICE_NAME, strerror(-device));
exit(1);
}
/*
* If an argument was given on the command line, write it to the device,
* otherwise, read from the device.
*/
/* close the device */
ret = rt_dev_close(device);
if (ret < 0) {
printf("ERROR : can't close device %s (%s)\n",
DEVICE_NAME, strerror(-ret));
exit(1);
}
return 0;
}
Here is a my driver open function
static int skel_open(struct inode *inode, struct file *file)
{
struct usb_skel *dev;
struct usb_interface *interface;
int subminor;
int retval = 0;
subminor = iminor(inode);
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
pr_err("%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV;
goto exit;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
}
/* increment our usage count for the device */
kref_get(&dev->kref);
/* lock the device to allow correctly handling errors
* in resumption */
mutex_lock(&dev->io_mutex);
retval = usb_autopm_get_interface(interface);
if (retval)
goto out_err;
/* save our object in the file's private structure */
file->private_data = dev;
mutex_unlock(&dev->io_mutex);
exit:
return retval;
}

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");

Direct access to linux framebuffer - copyarea

I want to move very quickly a rectangle over a framebuffer in an embedded linux application. I have found that the function cfb_copyarea may be useful. But I cannot find any ioctl over the /dev/fb device to call the function. Or can this function be called directly?
Here is a code to init and close FrameBuffer
class CFrameBuffer
{
void* m_FrameBuffer;
struct fb_fix_screeninfo m_FixInfo;
struct fb_var_screeninfo m_VarInfo;
int m_FBFD;
int InitFB()
{
int iFrameBufferSize;
/* Open the framebuffer device in read write */
m_FBFD = open(FB_NAME, O_RDWR);
if (m_FBFD < 0) {
printf("Unable to open %s.\n", FB_NAME);
return 1;
}
/* Do Ioctl. Retrieve fixed screen info. */
if (ioctl(m_FBFD, FBIOGET_FSCREENINFO, &m_FixInfo) < 0) {
printf("get fixed screen info failed: %s\n",
strerror(errno));
close(m_FBFD);
return 1;
}
/* Do Ioctl. Get the variable screen info. */
if (ioctl(m_FBFD, FBIOGET_VSCREENINFO, &m_VarInfo) < 0) {
printf("Unable to retrieve variable screen info: %s\n",
strerror(errno));
close(m_FBFD);
return 1;
}
/* Calculate the size to mmap */
iFrameBufferSize = m_FixInfo.line_length * m_VarInfo.yres;
printf("Line length %d\n", m_FixInfo.line_length);
/* Now mmap the framebuffer. */
m_FrameBuffer = mmap(NULL, iFrameBufferSize, PROT_READ | PROT_WRITE,
MAP_SHARED, m_FBFD,0);
if (m_FrameBuffer == NULL) {
printf("mmap failed:\n");
close(m_FBFD);
return 1;
}
return 0;
}
void CloseFB()
{
munmap(m_FrameBuffer,0);
close(m_FBFD);
}
};
Note that this code is not entirely correct, although it will work on many linux devices, on some it won't. To calculate the framebuffer size, do not do this:
iFrameBufferSize = m_FixInfo.line_length * m_VarInfo.yres;
Instead, do this:
iFrameBufferSize = m_FixInfo.smem_len;
And your code will be more portable.
As far as I know after a few days of research, there is no ioctl for invoking this function. I have to write my own system call preferrably in a kernel module. Or copy the algorithm the from kernel source and use it in the user space via nmaped memory.

Resources