Re: cdev to pdev

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

 



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

[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