Re: upgrading a char-driver to 2.6 cdev

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greg KH wrote:

On Tue, Aug 16, 2005 at 08:51:02PM -0600, Jim Cromie wrote:
folks,

Im trying to update an existing kernel char-driver to use 2.6 cdev api,
thus far Ive failed..

Ive cut my patch down to a single, fairly bare version of scullc example from LDD-3, which applies to drivers/char/scx200_gpio. It compiles ok, but does this when I
access one of the pins.

Badness in kref_get at lib/kref.c:32
[<c01b918a>] kref_get+0x2a/0x30
[<c01b88f2>] kobject_get+0x12/0x20
[<c014bc80>] cdev_get+0x20/0x50
[<c014bd01>] chrdev_open+0x21/0x120
[<c0143674>] dentry_open+0x154/0x1c0
[<c0143510>] filp_open+0x50/0x60
[<c0143805>] sys_open+0x35/0x70
[<c01026f9>] syscall_call+0x7/0xb

   30 void kref_get(struct kref *kref)
   31 {
   32         WARN_ON(!atomic_read(&kref->refcount));
   33         atomic_inc(&kref->refcount);
   34 }

the object-dump tells me nothing.

The line above with the WARN_ON() is triggering.  It's doing that
because a kref should NEVER have its reference count set to 0.  So, odds
are you never initialized your cdev properly before using it, right?

Care to post the code you wrote?

thanks,

greg k-h

here it is.  Im sure it looks familiar ;-)
I did the minimum changes after cut-pasting it in - ie
changed drivername,
dropped a few globals.

I just now looked for things that could have been improperly altered/adapted
from the reference code, I see 1 thing that left me wondering:

In scullc/scx200_setup_cdev,
thc call to cdev_init() gets pointer to FOPS,
and then cdev.ops is set to that same pointer
? are these both necessary ?  (Ive assumed so)

the rest is as current in 13-rc5-mm1 (ie unchanged for quite a while).

root@soekris:~/lab# lsmod
Module                  Size  Used by
scx200_gpio             5384  0
usbcore                81732  0
scx200                  4880  1 scx200_gpio
pc87360                36892  0
i2c_sensor              4480  1 pc87360
i2c_isa                 2304  0
i2c_core               23824  3 pc87360,i2c_sensor,i2c_isa

root@soekris:~/lab# more /proc/devices
Character devices:
[snipped]
240 scx200_gpio

root@soekris:~/lab# ls -l /dev/scxio-[0-3]
crw-r--r--  1 root root 240, 0 Aug 13 12:45 /dev/scxio-0
crw-r--r--  1 root root 240, 1 Aug 13 12:45 /dev/scxio-1
crw-r--r--  1 root root 240, 2 Aug 13 12:45 /dev/scxio-2
crw-r--r--  1 root root 240, 3 Aug 13 12:45 /dev/scxio-3

echo T > /dev/scxio-0
Badness in kref_get at lib/kref.c:32
[<c01b918a>] kref_get+0x2a/0x30
[<c01b88f2>] kobject_get+0x12/0x20
...

and heres the code:

diff -ruNp -X exclude-diffs He-3/drivers/char/scx200_gpio.c He-4/drivers/char/scx200_gpio.c
--- He-3/drivers/char/scx200_gpio.c     2005-08-16 16:14:15.000000000 -0600
+++ He-4/drivers/char/scx200_gpio.c     2005-08-16 16:37:10.000000000 -0600
@@ -14,6 +14,10 @@
#include <asm/uaccess.h>
#include <asm/io.h>

+#include <linux/types.h>        /* size_t */
+// #include <linux/ioctl.h>
+#include <linux/cdev.h>
+
#include <linux/scx200_gpio.h>

#define NAME "scx200_gpio"
@@ -124,7 +128,34 @@ static struct file_operations scx200_gpi
       .release = scx200_gpio_release,
};

-static int __init scx200_gpio_init(void)
+struct scx200_dev {
+        void **data;
+        struct scx200_dev *next;  /* next listitem */
+        int vmas;                 /* active mappings */
+        int quantum;              /* the current allocation size */
+        int qset;                 /* the current array size */
+        size_t size;              /* 32-bit will suffice */
+        struct semaphore sem;     /* Mutual exclusion */
+        struct cdev cdev;
+};
+
+struct scx200_dev *scx200_devices;
+int scx200_devs = 1;
+
+static void scx200_setup_cdev(struct scx200_dev *dev, int index)
+{
+        int err, devno = MKDEV(major, index);
+
+        cdev_init(&dev->cdev, &scx200_gpio_fops);
+        dev->cdev.owner = THIS_MODULE;
+        dev->cdev.ops = &scx200_gpio_fops;
+        err = cdev_add (&dev->cdev, devno, 1);
+        /* Fail gracefully if need be */
+        if (err)
+                printk(KERN_NOTICE "Error %d adding scull%d", err, index);
+}
+
+static int __init HOLD_scx200_gpio_init(void)
{
       int r;

@@ -148,9 +179,54 @@ static int __init scx200_gpio_init(void)
       return 0;
}

+static int __init scx200_gpio_init(void)
+{
+        int result, i;
+        dev_t dev = MKDEV(major, 0);
+
+        /*
+         * Register your major, and accept a dynamic number.
+         */
+        if (major)
+ result = register_chrdev_region(dev, scx200_devs, "scx200_gpio");
+        else {
+ result = alloc_chrdev_region(&dev, 0, scx200_devs, "scx200_gpio");
+                major = MAJOR(dev);
+        }
+        if (result < 0)
+                return result;
+
+
+        /*
+         * allocate the devices -- we can't have them static, as the number
+         * can be specified at load time
+         */
+ scx200_devices = kmalloc(scx200_devs*sizeof (struct scx200_dev), GFP_KERNEL);
+        if (!scx200_devices) {
+                result = -ENOMEM;
+                goto fail_malloc;
+        }
+        memset(scx200_devices, 0, scx200_devs*sizeof (struct scx200_dev));
+        for (i = 0; i < scx200_devs; i++) {
+                //scx200_devices[i].quantum = scx200_quantum;
+                //scx200_devices[i].qset = scx200_qset;
+                sema_init (&scx200_devices[i].sem, 1);
+                scx200_setup_cdev(scx200_devices + i, i);
+        }
+
+        return 0; /* succeed */
+
+  fail_malloc:
+        unregister_chrdev_region(dev, scx200_devs);
+        return result;
+}
+
static void __exit scx200_gpio_cleanup(void)
{
-       unregister_chrdev(major, NAME);
+
+       kfree(scx200_devices);
+       //unregister_chrdev(major, NAME);
+       unregister_chrdev_region(MKDEV(major, 0), scx200_devs);
}

module_init(scx200_gpio_init);


--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux