Greg KH wrote:
Are you suggesting that I should embedd both struct cdev and struct device
in my struct my_device?
Um, no. The bus your device is on should take care of the struct device
stuff. What kind of driver are you writing? Have a pointer to the
code?
It is SPI datakey flash device driver. I originaly put it the mtd subsystem but
didn't 'like' it since the device can be removed and mtd partition would not be
deleted sometimes (when device is removed) and I don't use anykind of FS on top
of raw flash anyway.
So I'm writing char device with read/write/erase functions accessible from
userspace via read/write/ioctl syscalls. I've chosen platform device (since
this driver is meant for embedded device).
My struct my_device:
struct datakey_info {
int valid;
struct flash_info *fl_info;
struct erase_info er_info;
struct semaphore sem; /* mutual exclusion semaphore */
};
What I do now is (no cdev here):
- define file operations and put them in struct file_operations 'datakey_fops'
struct file_operations datakey_fops = {
.owner = THIS_MODULE,
.open = datakey_open,
// .release = datakey_release,
.read = datakey_read,
.write = datakey_write,
.ioctl = datakey_ioctl,
.llseek = datakey_llseek,
};
- define struct device_driver
static struct device_driver datakey_platform_driver = {
.owner = THIS_MODULE,
.name = "datakey",
.bus = &platform_bus_type,
.probe = datakey_probe,
.remove = datakey_remove,
};
- define struct platform_device
static struct platform_device datakey_platform_device = {
.name = "datakey",
.id = -1,
.dev = {
.release = datakey_release,
},
};
- in datakey_init (called by module_init) this gets done among other stuff
...
/* register platform driver and device */
ret = driver_register(&datakey_platform_driver);
if (ret == 0) {
ret = platform_device_register(&datakey_platform_device);
if (ret) {
driver_unregister(&datakey_platform_driver);
printk(KERN_ERR "%s: coundn't register the device.\n",
__FUNCTION__);
return ret;
}
}
else {
printk(KERN_ERR "%s: coudn't register the driver.\n",
__FUNCTION__);
return ret;
}
/* register char device for userspace access */
if (register_chrdev(datakey_major, "datakey", &datakey_fops)) {
printk("%s: can't register datakey as char device\n",
__FUNCTION__);
return -EAGAIN;
}
...
(some timers, workqueues and other allocations)
- in datakey_probe:
static int
__init datakey_probe (struct device *device)
{
struct platform_device *dev = to_platform_device(device);
struct datakey_info *datakey = &datakey_data;
/* zero-out the datakey_data */
memset(datakey, 0, sizeof(struct datakey_info));
init_MUTEX(&datakey->sem);
if ( datakey_detect(datakey) )
datakey_add();
dev_set_drvdata(&dev->dev, datakey);
device_create_file(&dev->dev, &dev_attr_reg_data);
device_create_file(&dev->dev, &dev_attr_reg_status);
device_create_file(&dev->dev, &dev_attr_reg_control);
return 0;
}
(dev_attr_reg_xxx are created earlier...)
Otherwise I can't use cdev_init, cdev_add and similar for cdev registration
if I'm understanding this right and need to use old-style (as seen in LDD3
chapter3.4.2. The Older Way) char device registration which it is supposed
to be removed in the future.
No, you should use cdev, I never said you should not. Only that a
struct cdev does not give you a place in sysfs to place your files,
that's all.
Oh, right.
Here is sample code that uses cdev, but no sysfs here:
Different my_device struct:
struct datakey_info {
int valid;
struct flash_info *fl_info;
struct erase_info er_info;
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev;
};
- datakey_setup_cdev is called from init
static int
datakey_setup_cdev (struct datakey_info *datakey)
{
int ret = 0;
dev_t dev = 0;
memset(datakey, 0, sizeof(struct datakey_info));
init_MUTEX(&datakey->sem);
cdev_init(&datakey->cdev, &datakey_fops);
datakey->cdev.owner = THIS_MODULE;
datakey->cdev.ops = &datakey_fops;
if (datakey_major) {
dev = MKDEV(datakey_major, datakey_minor);
ret = register_chrdev_region(dev, 1, "datakey");
}
if (ret < 0) {
printk(KERN_WARNING "%s: can't get major %d\n",
__FUNCTION__, datakey_major);
return ret;
}
ret = cdev_add(&datakey->cdev, dev, 1);
if (ret) {
printk("%s: error %d adding datakey cdev!\n",
__FUNCTION__, ret);
return ret;
}
return 0;
}
After reading http://lwn.net/Articles/50988/ I think kobject from cdev could be
the way to go but I haven't ever digged that deep in the kernel subsystems.
Thanks for your time,
hinko
--
hinko <dot> kocevar <at> iskramedical <dot> si
Hinko Kocevar, embedded systems developer
Iskra Medical d.o.o., Stegne 23, 1k LJ, SLO-EU
"Aì rén" | [Analects XII:22]
--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive: http://mail.nl.linux.org/kernelnewbies/
FAQ: http://kernelnewbies.org/faq/