attached is a cut-down patch that attempts to convert scx200_gpio
to use the new 2.6 char-dev-driver API.
Its closely modelled after LDD-3 scull driver.
it segfaults reliably on cat /proc/devices after rmmod'g
tested against 12-rc4-mm2, I think it will apply to 12-rc[45]
#!/bin/bash
# load 1 at a time ??
modprobe scx200
modprobe scx200_gpio
cat /proc/devices
rmmod scx200_gpio
cat /proc/devices # 1st segfault here
rmmod scx200
cat /proc/devices # segfault again here
I can hazard a few (blind) guesses as to the reasons for segfault:
1. Im doing it wrong (I did check for the obvious, but..)
2. this is a mixed conversion
scx200_gpio depends upon scx200, which is still old api, I havent
touched it.
tia
jimc
diff -ruN -X exclude-diffs lnx/drivers/char/scx200_gpio.c scx200-segfault/drivers/char/scx200_gpio.c
--- lnx/drivers/char/scx200_gpio.c 2005-05-05 22:35:40.000000000 -0600
+++ scx200-segfault/drivers/char/scx200_gpio.c 2005-05-30 08:45:38.000000000 -0600
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -22,10 +23,21 @@
MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
MODULE_LICENSE("GPL");
+static int minor = 0;
static int major = 0; /* default to dynamic major */
module_param(major, int, 0);
MODULE_PARM_DESC(major, "Major device number");
+// int nr_devs = 1;
+#define NR_DEVS 1
+#define MAX_MINORS 96
+
+struct gpio_dev {
+ void *data;
+ struct cdev cdev; /* Char device structure */
+}
+gpio_devices[NR_DEVS];
+
static ssize_t scx200_gpio_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
@@ -109,9 +121,22 @@
.release = scx200_gpio_release,
};
+static void scx200_setup_cdev(struct gpio_dev *dev, struct file_operations *fops, int index)
+{
+ int err, devno = MKDEV(major, minor + index);
+
+ cdev_init(&dev->cdev, fops);
+ dev->cdev.owner = THIS_MODULE;
+ dev->cdev.ops = fops;
+ err = cdev_add (&dev->cdev, devno, 1);
+ /* Fail gracefully if need be */
+ if (err)
+ printk(KERN_NOTICE "Error %d adding %s %d", err, NAME, index);
+}
+
static int __init scx200_gpio_init(void)
{
- int r;
+ int rc, i, devno = 0;
printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
@@ -119,23 +144,38 @@
printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
return -ENODEV;
}
+ // scx200_init_shadow();
+ // from LDD-3
+ if (major) {
+ devno = MKDEV(major, minor);
+ rc = register_chrdev_region(devno, NR_DEVS, NAME);
+ } else {
+ rc = alloc_chrdev_region(&devno, minor, NR_DEVS, NAME);
+ major = MAJOR(devno);
+ }
+ if (rc < 0) {
+ printk(KERN_WARNING NAME ": can't get major %d\n", major);
+ return rc;
+ }
- r = register_chrdev(major, NAME, &scx200_gpio_fops);
- if (r < 0) {
- printk(KERN_ERR NAME ": unable to register character device\n");
- return r;
- }
- if (!major) {
- major = r;
- printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
- }
+
+ /* Initialize each device. */
+ for (i = 0; i < NR_DEVS; i++) {
+ scx200_setup_cdev(&gpio_devices[i], &scx200_gpio_fops, i);
+ }
return 0;
}
static void __exit scx200_gpio_cleanup(void)
{
- unregister_chrdev(major, NAME);
+ int i;
+ dev_t devno = MKDEV(major, minor);
+
+ for (i = 0; i < NR_DEVS; i++) {
+ cdev_del(&gpio_devices[i].cdev);
+ }
+ unregister_chrdev_region(devno, MAX_MINORS);
}
module_init(scx200_gpio_init);