forked from mirrors/linux
		
	parport: add device-model to parport subsystem
parport subsystem starts using the device-model. Drivers using the device-model has to define devmodel as true and should register the device with parport using parport_register_dev_model(). Tested-by: Jean Delvare <jdelvare@suse.de> Tested-by: Alan Cox <gnomes@lxorguk.ukuu.org.uk> Signed-off-by: Sudip Mukherjee <sudip@vectorindia.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									208250dd4c
								
							
						
					
					
						commit
						6fa45a2268
					
				
					 4 changed files with 379 additions and 28 deletions
				
			
		|  | @ -2255,7 +2255,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, | |||
| 		release_region(base+0x3, 5); | ||||
| 	release_region(base, 3); | ||||
| out4: | ||||
| 	parport_put_port(p); | ||||
| 	parport_del_port(p); | ||||
| out3: | ||||
| 	kfree(priv); | ||||
| out2: | ||||
|  | @ -2294,7 +2294,7 @@ void parport_pc_unregister_port(struct parport *p) | |||
| 				    priv->dma_handle); | ||||
| #endif | ||||
| 	kfree(p->private_data); | ||||
| 	parport_put_port(p); | ||||
| 	parport_del_port(p); | ||||
| 	kfree(ops); /* hope no-one cached it */ | ||||
| } | ||||
| EXPORT_SYMBOL(parport_pc_unregister_port); | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ | |||
| #include <linux/parport.h> | ||||
| #include <linux/ctype.h> | ||||
| #include <linux/sysctl.h> | ||||
| #include <linux/device.h> | ||||
| 
 | ||||
| #include <asm/uaccess.h> | ||||
| 
 | ||||
|  | @ -558,8 +559,18 @@ int parport_device_proc_unregister(struct pardevice *device) | |||
| 
 | ||||
| static int __init parport_default_proc_register(void) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	parport_default_sysctl_table.sysctl_header = | ||||
| 		register_sysctl_table(parport_default_sysctl_table.dev_dir); | ||||
| 	if (!parport_default_sysctl_table.sysctl_header) | ||||
| 		return -ENOMEM; | ||||
| 	ret = parport_bus_init(); | ||||
| 	if (ret) { | ||||
| 		unregister_sysctl_table(parport_default_sysctl_table. | ||||
| 					sysctl_header); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -570,6 +581,7 @@ static void __exit parport_default_proc_unregister(void) | |||
| 					sysctl_header); | ||||
| 		parport_default_sysctl_table.sysctl_header = NULL; | ||||
| 	} | ||||
| 	parport_bus_exit(); | ||||
| } | ||||
| 
 | ||||
| #else /* no sysctl or no procfs*/ | ||||
|  | @ -596,11 +608,12 @@ int parport_device_proc_unregister(struct pardevice *device) | |||
| 
 | ||||
| static int __init parport_default_proc_register (void) | ||||
| { | ||||
| 	return 0; | ||||
| 	return parport_bus_init(); | ||||
| } | ||||
| 
 | ||||
| static void __exit parport_default_proc_unregister (void) | ||||
| { | ||||
| 	parport_bus_exit(); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ | |||
| #include <linux/slab.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/kmod.h> | ||||
| #include <linux/device.h> | ||||
| 
 | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/mutex.h> | ||||
|  | @ -100,13 +101,91 @@ static struct parport_operations dead_ops = { | |||
| 	.owner		= NULL, | ||||
| }; | ||||
| 
 | ||||
| static struct device_type parport_device_type = { | ||||
| 	.name = "parport", | ||||
| }; | ||||
| 
 | ||||
| static int is_parport(struct device *dev) | ||||
| { | ||||
| 	return dev->type == &parport_device_type; | ||||
| } | ||||
| 
 | ||||
| static int parport_probe(struct device *dev) | ||||
| { | ||||
| 	struct parport_driver *drv; | ||||
| 
 | ||||
| 	if (is_parport(dev)) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	drv = to_parport_driver(dev->driver); | ||||
| 	if (!drv->probe) { | ||||
| 		/* if driver has not defined a custom probe */ | ||||
| 		struct pardevice *par_dev = to_pardevice(dev); | ||||
| 
 | ||||
| 		if (strcmp(par_dev->name, drv->name)) | ||||
| 			return -ENODEV; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	/* if driver defined its own probe */ | ||||
| 	return drv->probe(to_pardevice(dev)); | ||||
| } | ||||
| 
 | ||||
| static struct bus_type parport_bus_type = { | ||||
| 	.name = "parport", | ||||
| 	.probe = parport_probe, | ||||
| }; | ||||
| 
 | ||||
| int parport_bus_init(void) | ||||
| { | ||||
| 	return bus_register(&parport_bus_type); | ||||
| } | ||||
| 
 | ||||
| void parport_bus_exit(void) | ||||
| { | ||||
| 	bus_unregister(&parport_bus_type); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * iterates through all the drivers registered with the bus and sends the port | ||||
|  * details to the match_port callback of the driver, so that the driver can | ||||
|  * know about the new port that just regsitered with the bus and decide if it | ||||
|  * wants to use this new port. | ||||
|  */ | ||||
| static int driver_check(struct device_driver *dev_drv, void *_port) | ||||
| { | ||||
| 	struct parport *port = _port; | ||||
| 	struct parport_driver *drv = to_parport_driver(dev_drv); | ||||
| 
 | ||||
| 	if (drv->match_port) | ||||
| 		drv->match_port(port); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Call attach(port) for each registered driver. */ | ||||
| static void attach_driver_chain(struct parport *port) | ||||
| { | ||||
| 	/* caller has exclusive registration_lock */ | ||||
| 	struct parport_driver *drv; | ||||
| 
 | ||||
| 	list_for_each_entry(drv, &drivers, list) | ||||
| 		drv->attach(port); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * call the driver_check function of the drivers registered in | ||||
| 	 * new device model | ||||
| 	 */ | ||||
| 
 | ||||
| 	bus_for_each_drv(&parport_bus_type, NULL, port, driver_check); | ||||
| } | ||||
| 
 | ||||
| static int driver_detach(struct device_driver *_drv, void *_port) | ||||
| { | ||||
| 	struct parport *port = _port; | ||||
| 	struct parport_driver *drv = to_parport_driver(_drv); | ||||
| 
 | ||||
| 	if (drv->detach) | ||||
| 		drv->detach(port); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Call detach(port) for each registered driver. */ | ||||
|  | @ -116,6 +195,13 @@ static void detach_driver_chain(struct parport *port) | |||
| 	/* caller has exclusive registration_lock */ | ||||
| 	list_for_each_entry(drv, &drivers, list) | ||||
| 		drv->detach (port); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * call the detach function of the drivers registered in | ||||
| 	 * new device model | ||||
| 	 */ | ||||
| 
 | ||||
| 	bus_for_each_drv(&parport_bus_type, NULL, port, driver_detach); | ||||
| } | ||||
| 
 | ||||
| /* Ask kmod for some lowlevel drivers. */ | ||||
|  | @ -126,17 +212,39 @@ static void get_lowlevel_driver (void) | |||
| 	request_module ("parport_lowlevel"); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * iterates through all the devices connected to the bus and sends the device | ||||
|  * details to the match_port callback of the driver, so that the driver can | ||||
|  * know what are all the ports that are connected to the bus and choose the | ||||
|  * port to which it wants to register its device. | ||||
|  */ | ||||
| static int port_check(struct device *dev, void *dev_drv) | ||||
| { | ||||
| 	struct parport_driver *drv = dev_drv; | ||||
| 
 | ||||
| 	/* only send ports, do not send other devices connected to bus */ | ||||
| 	if (is_parport(dev)) | ||||
| 		drv->match_port(to_parport_dev(dev)); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *	parport_register_driver - register a parallel port device driver | ||||
|  *	@drv: structure describing the driver | ||||
|  *	@owner: owner module of drv | ||||
|  *	@mod_name: module name string | ||||
|  * | ||||
|  *	This can be called by a parallel port device driver in order | ||||
|  *	to receive notifications about ports being found in the | ||||
|  *	system, as well as ports no longer available. | ||||
|  * | ||||
|  *	If devmodel is true then the new device model is used | ||||
|  *	for registration. | ||||
|  * | ||||
|  *	The @drv structure is allocated by the caller and must not be | ||||
|  *	deallocated until after calling parport_unregister_driver(). | ||||
|  * | ||||
|  *	If using the non device model: | ||||
|  *	The driver's attach() function may block.  The port that | ||||
|  *	attach() is given will be valid for the duration of the | ||||
|  *	callback, but if the driver wants to take a copy of the | ||||
|  | @ -148,21 +256,57 @@ static void get_lowlevel_driver (void) | |||
|  *	callback, but if the driver wants to take a copy of the | ||||
|  *	pointer it must call parport_get_port() to do so. | ||||
|  * | ||||
|  *	Returns 0 on success.  Currently it always succeeds. | ||||
|  * | ||||
|  *	Returns 0 on success. The non device model will always succeeds. | ||||
|  *	but the new device model can fail and will return the error code. | ||||
|  **/ | ||||
| 
 | ||||
| int parport_register_driver (struct parport_driver *drv) | ||||
| int __parport_register_driver(struct parport_driver *drv, struct module *owner, | ||||
| 			      const char *mod_name) | ||||
| { | ||||
| 	struct parport *port; | ||||
| 
 | ||||
| 	if (list_empty(&portlist)) | ||||
| 		get_lowlevel_driver (); | ||||
| 
 | ||||
| 	mutex_lock(®istration_lock); | ||||
| 	list_for_each_entry(port, &portlist, list) | ||||
| 		drv->attach(port); | ||||
| 	list_add(&drv->list, &drivers); | ||||
| 	mutex_unlock(®istration_lock); | ||||
| 	if (drv->devmodel) { | ||||
| 		/* using device model */ | ||||
| 		int ret; | ||||
| 
 | ||||
| 		/* initialize common driver fields */ | ||||
| 		drv->driver.name = drv->name; | ||||
| 		drv->driver.bus = &parport_bus_type; | ||||
| 		drv->driver.owner = owner; | ||||
| 		drv->driver.mod_name = mod_name; | ||||
| 		ret = driver_register(&drv->driver); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 
 | ||||
| 		mutex_lock(®istration_lock); | ||||
| 		if (drv->match_port) | ||||
| 			bus_for_each_dev(&parport_bus_type, NULL, drv, | ||||
| 					 port_check); | ||||
| 		mutex_unlock(®istration_lock); | ||||
| 	} else { | ||||
| 		struct parport *port; | ||||
| 
 | ||||
| 		drv->devmodel = false; | ||||
| 
 | ||||
| 		mutex_lock(®istration_lock); | ||||
| 		list_for_each_entry(port, &portlist, list) | ||||
| 			drv->attach(port); | ||||
| 		list_add(&drv->list, &drivers); | ||||
| 		mutex_unlock(®istration_lock); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(__parport_register_driver); | ||||
| 
 | ||||
| static int port_detach(struct device *dev, void *_drv) | ||||
| { | ||||
| 	struct parport_driver *drv = _drv; | ||||
| 
 | ||||
| 	if (is_parport(dev) && drv->detach) | ||||
| 		drv->detach(to_parport_dev(dev)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -189,15 +333,22 @@ void parport_unregister_driver (struct parport_driver *drv) | |||
| 	struct parport *port; | ||||
| 
 | ||||
| 	mutex_lock(®istration_lock); | ||||
| 	list_del_init(&drv->list); | ||||
| 	list_for_each_entry(port, &portlist, list) | ||||
| 		drv->detach(port); | ||||
| 	if (drv->devmodel) { | ||||
| 		bus_for_each_dev(&parport_bus_type, NULL, drv, port_detach); | ||||
| 		driver_unregister(&drv->driver); | ||||
| 	} else { | ||||
| 		list_del_init(&drv->list); | ||||
| 		list_for_each_entry(port, &portlist, list) | ||||
| 			drv->detach(port); | ||||
| 	} | ||||
| 	mutex_unlock(®istration_lock); | ||||
| } | ||||
| 
 | ||||
| static void free_port (struct parport *port) | ||||
| static void free_port(struct device *dev) | ||||
| { | ||||
| 	int d; | ||||
| 	struct parport *port = to_parport_dev(dev); | ||||
| 
 | ||||
| 	spin_lock(&full_list_lock); | ||||
| 	list_del(&port->full_list); | ||||
| 	spin_unlock(&full_list_lock); | ||||
|  | @ -223,25 +374,29 @@ static void free_port (struct parport *port) | |||
| 
 | ||||
| struct parport *parport_get_port (struct parport *port) | ||||
| { | ||||
| 	atomic_inc (&port->ref_count); | ||||
| 	return port; | ||||
| 	struct device *dev = get_device(&port->bus_dev); | ||||
| 
 | ||||
| 	return to_parport_dev(dev); | ||||
| } | ||||
| 
 | ||||
| void parport_del_port(struct parport *port) | ||||
| { | ||||
| 	device_unregister(&port->bus_dev); | ||||
| } | ||||
| EXPORT_SYMBOL(parport_del_port); | ||||
| 
 | ||||
| /**
 | ||||
|  *	parport_put_port - decrement a port's reference count | ||||
|  *	@port: the port | ||||
|  * | ||||
|  *	This should be called once for each call to parport_get_port(), | ||||
|  *	once the port is no longer needed. | ||||
|  *	once the port is no longer needed. When the reference count reaches | ||||
|  *	zero (port is no longer used), free_port is called. | ||||
|  **/ | ||||
| 
 | ||||
| void parport_put_port (struct parport *port) | ||||
| { | ||||
| 	if (atomic_dec_and_test (&port->ref_count)) | ||||
| 		/* Can destroy it now. */ | ||||
| 		free_port (port); | ||||
| 
 | ||||
| 	return; | ||||
| 	put_device(&port->bus_dev); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -281,6 +436,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, | |||
| 	int num; | ||||
| 	int device; | ||||
| 	char *name; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	tmp = kzalloc(sizeof(struct parport), GFP_KERNEL); | ||||
| 	if (!tmp) { | ||||
|  | @ -333,6 +489,10 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, | |||
| 	 */ | ||||
| 	sprintf(name, "parport%d", tmp->portnum = tmp->number); | ||||
| 	tmp->name = name; | ||||
| 	tmp->bus_dev.bus = &parport_bus_type; | ||||
| 	tmp->bus_dev.release = free_port; | ||||
| 	dev_set_name(&tmp->bus_dev, name); | ||||
| 	tmp->bus_dev.type = &parport_device_type; | ||||
| 
 | ||||
| 	for (device = 0; device < 5; device++) | ||||
| 		/* assume the worst */ | ||||
|  | @ -340,6 +500,12 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, | |||
| 
 | ||||
| 	tmp->waithead = tmp->waittail = NULL; | ||||
| 
 | ||||
| 	ret = device_register(&tmp->bus_dev); | ||||
| 	if (ret) { | ||||
| 		put_device(&tmp->bus_dev); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return tmp; | ||||
| } | ||||
| 
 | ||||
|  | @ -575,6 +741,7 @@ parport_register_device(struct parport *port, const char *name, | |||
| 	tmp->irq_func = irq_func; | ||||
| 	tmp->waiting = 0; | ||||
| 	tmp->timeout = 5 * HZ; | ||||
| 	tmp->devmodel = false; | ||||
| 
 | ||||
| 	/* Chain this onto the list */ | ||||
| 	tmp->prev = NULL; | ||||
|  | @ -630,6 +797,136 @@ parport_register_device(struct parport *port, const char *name, | |||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static void free_pardevice(struct device *dev) | ||||
| { | ||||
| 	struct pardevice *par_dev = to_pardevice(dev); | ||||
| 
 | ||||
| 	kfree(par_dev->name); | ||||
| 	kfree(par_dev); | ||||
| } | ||||
| 
 | ||||
| struct pardevice * | ||||
| parport_register_dev_model(struct parport *port, const char *name, | ||||
| 			   const struct pardev_cb *par_dev_cb, int id) | ||||
| { | ||||
| 	struct pardevice *par_dev; | ||||
| 	int ret; | ||||
| 	char *devname; | ||||
| 
 | ||||
| 	if (port->physport->flags & PARPORT_FLAG_EXCL) { | ||||
| 		/* An exclusive device is registered. */ | ||||
| 		pr_err("%s: no more devices allowed\n", port->name); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (par_dev_cb->flags & PARPORT_DEV_LURK) { | ||||
| 		if (!par_dev_cb->preempt || !par_dev_cb->wakeup) { | ||||
| 			pr_info("%s: refused to register lurking device (%s) without callbacks\n", | ||||
| 				port->name, name); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!try_module_get(port->ops->owner)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	parport_get_port(port); | ||||
| 
 | ||||
| 	par_dev = kzalloc(sizeof(*par_dev), GFP_KERNEL); | ||||
| 	if (!par_dev) | ||||
| 		goto err_put_port; | ||||
| 
 | ||||
| 	par_dev->state = kzalloc(sizeof(*par_dev->state), GFP_KERNEL); | ||||
| 	if (!par_dev->state) | ||||
| 		goto err_put_par_dev; | ||||
| 
 | ||||
| 	devname = kstrdup(name, GFP_KERNEL); | ||||
| 	if (!devname) | ||||
| 		goto err_free_par_dev; | ||||
| 
 | ||||
| 	par_dev->name = devname; | ||||
| 	par_dev->port = port; | ||||
| 	par_dev->daisy = -1; | ||||
| 	par_dev->preempt = par_dev_cb->preempt; | ||||
| 	par_dev->wakeup = par_dev_cb->wakeup; | ||||
| 	par_dev->private = par_dev_cb->private; | ||||
| 	par_dev->flags = par_dev_cb->flags; | ||||
| 	par_dev->irq_func = par_dev_cb->irq_func; | ||||
| 	par_dev->waiting = 0; | ||||
| 	par_dev->timeout = 5 * HZ; | ||||
| 
 | ||||
| 	par_dev->dev.parent = &port->bus_dev; | ||||
| 	par_dev->dev.bus = &parport_bus_type; | ||||
| 	ret = dev_set_name(&par_dev->dev, "%s.%d", devname, id); | ||||
| 	if (ret) | ||||
| 		goto err_free_devname; | ||||
| 	par_dev->dev.release = free_pardevice; | ||||
| 	par_dev->devmodel = true; | ||||
| 	ret = device_register(&par_dev->dev); | ||||
| 	if (ret) | ||||
| 		goto err_put_dev; | ||||
| 
 | ||||
| 	/* Chain this onto the list */ | ||||
| 	par_dev->prev = NULL; | ||||
| 	/*
 | ||||
| 	 * This function must not run from an irq handler so we don' t need | ||||
| 	 * to clear irq on the local CPU. -arca | ||||
| 	 */ | ||||
| 	spin_lock(&port->physport->pardevice_lock); | ||||
| 
 | ||||
| 	if (par_dev_cb->flags & PARPORT_DEV_EXCL) { | ||||
| 		if (port->physport->devices) { | ||||
| 			spin_unlock(&port->physport->pardevice_lock); | ||||
| 			pr_debug("%s: cannot grant exclusive access for device %s\n", | ||||
| 				 port->name, name); | ||||
| 			goto err_put_dev; | ||||
| 		} | ||||
| 		port->flags |= PARPORT_FLAG_EXCL; | ||||
| 	} | ||||
| 
 | ||||
| 	par_dev->next = port->physport->devices; | ||||
| 	wmb();	/*
 | ||||
| 		 * Make sure that tmp->next is written before it's | ||||
| 		 * added to the list; see comments marked 'no locking | ||||
| 		 * required' | ||||
| 		 */ | ||||
| 	if (port->physport->devices) | ||||
| 		port->physport->devices->prev = par_dev; | ||||
| 	port->physport->devices = par_dev; | ||||
| 	spin_unlock(&port->physport->pardevice_lock); | ||||
| 
 | ||||
| 	init_waitqueue_head(&par_dev->wait_q); | ||||
| 	par_dev->timeslice = parport_default_timeslice; | ||||
| 	par_dev->waitnext = NULL; | ||||
| 	par_dev->waitprev = NULL; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This has to be run as last thing since init_state may need other | ||||
| 	 * pardevice fields. -arca | ||||
| 	 */ | ||||
| 	port->ops->init_state(par_dev, par_dev->state); | ||||
| 	port->proc_device = par_dev; | ||||
| 	parport_device_proc_register(par_dev); | ||||
| 
 | ||||
| 	return par_dev; | ||||
| 
 | ||||
| err_put_dev: | ||||
| 	put_device(&par_dev->dev); | ||||
| err_free_devname: | ||||
| 	kfree(devname); | ||||
| err_free_par_dev: | ||||
| 	kfree(par_dev->state); | ||||
| err_put_par_dev: | ||||
| 	if (!par_dev->devmodel) | ||||
| 		kfree(par_dev); | ||||
| err_put_port: | ||||
| 	parport_put_port(port); | ||||
| 	module_put(port->ops->owner); | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| EXPORT_SYMBOL(parport_register_dev_model); | ||||
| 
 | ||||
| /**
 | ||||
|  *	parport_unregister_device - deregister a device on a parallel port | ||||
|  *	@dev: pointer to structure representing device | ||||
|  | @ -691,7 +988,10 @@ void parport_unregister_device(struct pardevice *dev) | |||
| 	spin_unlock_irq(&port->waitlist_lock); | ||||
| 
 | ||||
| 	kfree(dev->state); | ||||
| 	kfree(dev); | ||||
| 	if (dev->devmodel) | ||||
| 		device_unregister(&dev->dev); | ||||
| 	else | ||||
| 		kfree(dev); | ||||
| 
 | ||||
| 	module_put(port->ops->owner); | ||||
| 	parport_put_port (port); | ||||
|  | @ -1019,7 +1319,6 @@ EXPORT_SYMBOL(parport_release); | |||
| EXPORT_SYMBOL(parport_register_port); | ||||
| EXPORT_SYMBOL(parport_announce_port); | ||||
| EXPORT_SYMBOL(parport_remove_port); | ||||
| EXPORT_SYMBOL(parport_register_driver); | ||||
| EXPORT_SYMBOL(parport_unregister_driver); | ||||
| EXPORT_SYMBOL(parport_register_device); | ||||
| EXPORT_SYMBOL(parport_unregister_device); | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ | |||
| #include <linux/wait.h> | ||||
| #include <linux/irqreturn.h> | ||||
| #include <linux/semaphore.h> | ||||
| #include <linux/device.h> | ||||
| #include <asm/ptrace.h> | ||||
| #include <uapi/linux/parport.h> | ||||
| 
 | ||||
|  | @ -145,6 +146,8 @@ struct pardevice { | |||
| 	unsigned int flags; | ||||
| 	struct pardevice *next; | ||||
| 	struct pardevice *prev; | ||||
| 	struct device dev; | ||||
| 	bool devmodel; | ||||
| 	struct parport_state *state;     /* saved status over preemption */ | ||||
| 	wait_queue_head_t wait_q; | ||||
| 	unsigned long int time; | ||||
|  | @ -156,6 +159,8 @@ struct pardevice { | |||
| 	void * sysctl_table; | ||||
| }; | ||||
| 
 | ||||
| #define to_pardevice(n) container_of(n, struct pardevice, dev) | ||||
| 
 | ||||
| /* IEEE1284 information */ | ||||
| 
 | ||||
| /* IEEE1284 phases. These are exposed to userland through ppdev IOCTL
 | ||||
|  | @ -195,7 +200,7 @@ struct parport { | |||
| 				 * This may unfortulately be null if the | ||||
| 				 * port has a legacy driver. | ||||
| 				 */ | ||||
| 
 | ||||
| 	struct device bus_dev;	/* to link with the bus */ | ||||
| 	struct parport *physport; | ||||
| 				/* If this is a non-default mux
 | ||||
| 				   parport, i.e. we're a clone of a real | ||||
|  | @ -245,15 +250,26 @@ struct parport { | |||
| 	struct parport *slaves[3]; | ||||
| }; | ||||
| 
 | ||||
| #define to_parport_dev(n) container_of(n, struct parport, bus_dev) | ||||
| 
 | ||||
| #define DEFAULT_SPIN_TIME 500 /* us */ | ||||
| 
 | ||||
| struct parport_driver { | ||||
| 	const char *name; | ||||
| 	void (*attach) (struct parport *); | ||||
| 	void (*detach) (struct parport *); | ||||
| 	void (*match_port)(struct parport *); | ||||
| 	int (*probe)(struct pardevice *); | ||||
| 	struct device_driver driver; | ||||
| 	bool devmodel; | ||||
| 	struct list_head list; | ||||
| }; | ||||
| 
 | ||||
| #define to_parport_driver(n) container_of(n, struct parport_driver, driver) | ||||
| 
 | ||||
| int parport_bus_init(void); | ||||
| void parport_bus_exit(void); | ||||
| 
 | ||||
| /* parport_register_port registers a new parallel port at the given
 | ||||
|    address (if one does not already exist) and returns a pointer to it. | ||||
|    This entails claiming the I/O region, IRQ and DMA.  NULL is returned | ||||
|  | @ -272,10 +288,20 @@ void parport_announce_port (struct parport *port); | |||
| extern void parport_remove_port(struct parport *port); | ||||
| 
 | ||||
| /* Register a new high-level driver. */ | ||||
| extern int parport_register_driver (struct parport_driver *); | ||||
| 
 | ||||
| int __must_check __parport_register_driver(struct parport_driver *, | ||||
| 					   struct module *, | ||||
| 					   const char *mod_name); | ||||
| /*
 | ||||
|  * parport_register_driver must be a macro so that KBUILD_MODNAME can | ||||
|  * be expanded | ||||
|  */ | ||||
| #define parport_register_driver(driver)             \ | ||||
| 	__parport_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) | ||||
| 
 | ||||
| /* Unregister a high-level driver. */ | ||||
| extern void parport_unregister_driver (struct parport_driver *); | ||||
| void parport_unregister_driver(struct parport_driver *); | ||||
| 
 | ||||
| /* If parport_register_driver doesn't fit your needs, perhaps
 | ||||
|  * parport_find_xxx does. */ | ||||
|  | @ -288,6 +314,15 @@ extern irqreturn_t parport_irq_handler(int irq, void *dev_id); | |||
| /* Reference counting for ports. */ | ||||
| extern struct parport *parport_get_port (struct parport *); | ||||
| extern void parport_put_port (struct parport *); | ||||
| void parport_del_port(struct parport *); | ||||
| 
 | ||||
| struct pardev_cb { | ||||
| 	int (*preempt)(void *); | ||||
| 	void (*wakeup)(void *); | ||||
| 	void *private; | ||||
| 	void (*irq_func)(void *); | ||||
| 	unsigned int flags; | ||||
| }; | ||||
| 
 | ||||
| /* parport_register_device declares that a device is connected to a
 | ||||
|    port, and tells the kernel all it needs to know. | ||||
|  | @ -301,6 +336,10 @@ struct pardevice *parport_register_device(struct parport *port, | |||
| 			  void (*irq_func)(void *),  | ||||
| 			  int flags, void *handle); | ||||
| 
 | ||||
| struct pardevice * | ||||
| parport_register_dev_model(struct parport *port, const char *name, | ||||
| 			   const struct pardev_cb *par_dev_cb, int cnt); | ||||
| 
 | ||||
| /* parport_unregister unlinks a device from the chain. */ | ||||
| extern void parport_unregister_device(struct pardevice *dev); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Sudip Mukherjee
						Sudip Mukherjee