Jim Cromie wrote:
**Subject: Driver model ISA bus**
http://marc.theaimsgroup.com/?l=linux-kernel&m=114678055902797&w=2
It looks interesting - anything that simplifies stuff is - but
alas - theres no empty-isa-driver.c for me to start from.
Now there is!
The .match() method is used to guarantee that a later "bind" (echo -n
empty.0 >/sys/bus/isa/driver/empty/bind) could conceivably succeed. If
it can not (in this example due to no port value having been passed in)
then the method returns a non-match (0) meaning the bus code will
unregister the device again. Otherwise, it keeps it registered and the
probe() method gets called where all the real work can happen. Note that
this should include things like requesting the I/O ports -- even if they
are busy now, an unload of another driver could free them, after which a
bind could succeed.
You are being passed the "unsigned int id" in all methods, but expected
use is for probe() to hang its private data off dev_get_drvdata() as in
this example. Your choice...
remove() gets called on device unbind / driver unload. There are also
suspend and resume callbacks available. Hope the example is useful. As
Greg said though, this code is not currently available in any public
kernel yet anyway, so ...
+ pdev = platform_device_register_simple(DRVNAME, 0, NULL, 0);
... if you will be using platform devices instead, please don't use the
platform_device_register_simple() API; it's going away. Use:
pdev = platform_device_alloc(DRVNAME, 0);
if (!pdev)
/* ENOMEM */
error = platform_device_add(device);
if (error) {
platform_device_put(device);
/* error */;
}
instead. Also make that DRVNAME a DEVNAME by the way -- it's the name
that shows up in /sys/devices/platform.
Rene.
/*
* An empty ISA driver
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/resource.h>
#include <linux/isa.h>
MODULE_DESCRIPTION("An empty ISA driver");;
MODULE_AUTHOR("The Neighbour's Cat");
MODULE_LICENSE("GPL");
#define NDEV 2
static unsigned long port[NDEV];
module_param_array(port, ulong, NULL, 0444);
struct empty {
struct resource *port;
/* ... */
};
static int __devinit empty_match(struct device *dev, unsigned int id)
{
if (!port[id]) {
printk("%s: please specify port\n", dev->bus_id);
return 0;
}
return 1;
}
static int __devinit empty_probe(struct device *dev, unsigned int id)
{
struct empty *empty;
empty = kmalloc(sizeof *empty, GFP_KERNEL);
if (!empty) {
printk("%s: out of memory\n", dev->bus_id);
return -ENOMEM;
}
empty->port = request_region(port[id], 1, dev->bus_id);
if (!empty->port) {
printk("%s: could not grab port %#lx\n", dev->bus_id, port[id]);
kfree(empty);
return -EBUSY;
}
/* setup hardware, register things */
dev_set_drvdata(dev, empty);
return 0;
}
static int __devexit empty_remove(struct device *dev, unsigned int id)
{
struct empty *empty = dev_get_drvdata(dev);
/* shut up hardware, deregister things */
release_resource(empty->port);
kfree(empty->port);
kfree(empty);
dev_set_drvdata(dev, NULL);
return 0;
}
static struct isa_driver empty_isa_driver = {
.match = empty_match,
.probe = empty_probe,
.remove = __devexit_p(empty_remove),
.driver = {
.name = "empty"
}
};
int __init empty_init(void)
{
return isa_register_driver(&empty_isa_driver, NDEV);
}
void __exit empty_exit(void)
{
isa_unregister_driver(&empty_isa_driver);
}
module_init(empty_init);
module_exit(empty_exit);
ifneq ($(KERNELRELEASE),)
obj-m := empty-isa-driver.o
else
default:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd)
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
endif