| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * drivers/sh/superhyway/superhyway.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SuperHyway Bus Driver | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2004, 2005  Paul Mundt <lethal@linux-sh.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is subject to the terms and conditions of the GNU General Public | 
					
						
							|  |  |  |  * License.  See the file "COPYING" in the main directory of this archive | 
					
						
							|  |  |  |  * for more details. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/device.h>
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  | #include <linux/list.h>
 | 
					
						
							|  |  |  | #include <linux/superhyway.h>
 | 
					
						
							| 
									
										
										
										
											2005-10-30 15:03:48 -08:00
										 |  |  | #include <linux/string.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int superhyway_devices; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct device superhyway_bus_device = { | 
					
						
							| 
									
										
										
										
											2009-03-03 12:16:12 +09:00
										 |  |  | 	.init_name = "superhyway", | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void superhyway_device_release(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	struct superhyway_device *sdev = to_superhyway_device(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(sdev->resource); | 
					
						
							|  |  |  | 	kfree(sdev); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * superhyway_add_device - Add a SuperHyway module | 
					
						
							|  |  |  |  * @base: Physical address where module is mapped. | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  |  * @sdev: SuperHyway device to add, or NULL to allocate a new one. | 
					
						
							|  |  |  |  * @bus: Bus where SuperHyway module resides. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This is responsible for adding a new SuperHyway module. This sets up a new | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  |  * struct superhyway_device for the module being added if @sdev == NULL. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Devices are initially added in the order that they are scanned (from the | 
					
						
							|  |  |  |  * top-down of the memory map), and are assigned an ID based on the order that | 
					
						
							|  |  |  |  * they are added. Any manual addition of a module will thus get the ID after | 
					
						
							|  |  |  |  * the devices already discovered regardless of where it resides in memory. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Further work can and should be done in superhyway_scan_bus(), to be sure | 
					
						
							|  |  |  |  * that any new modules are properly discovered and subsequently registered. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | int superhyway_add_device(unsigned long base, struct superhyway_device *sdev, | 
					
						
							|  |  |  | 			  struct superhyway_bus *bus) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	struct superhyway_device *dev = sdev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!dev) { | 
					
						
							| 
									
										
											  
											
												some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
 x =
- kmalloc
+ kzalloc
  (E1,E2)
  ...  when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
											
										 
											2007-07-19 01:49:03 -07:00
										 |  |  | 		dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 		if (!dev) | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	dev->bus = bus; | 
					
						
							|  |  |  | 	superhyway_read_vcr(dev, base, &dev->vcr); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	if (!dev->resource) { | 
					
						
							|  |  |  | 		dev->resource = kmalloc(sizeof(struct resource), GFP_KERNEL); | 
					
						
							|  |  |  | 		if (!dev->resource) { | 
					
						
							|  |  |  | 			kfree(dev); | 
					
						
							|  |  |  | 			return -ENOMEM; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dev->resource->name	= dev->name; | 
					
						
							|  |  |  | 		dev->resource->start	= base; | 
					
						
							|  |  |  | 		dev->resource->end	= dev->resource->start + 0x01000000; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dev->dev.parent		= &superhyway_bus_device; | 
					
						
							|  |  |  | 	dev->dev.bus		= &superhyway_bus_type; | 
					
						
							|  |  |  | 	dev->dev.release	= superhyway_device_release; | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	dev->id.id		= dev->vcr.mod_id; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	sprintf(dev->name, "SuperHyway device %04x", dev->id.id); | 
					
						
							| 
									
										
										
										
											2009-03-03 12:16:12 +09:00
										 |  |  | 	dev_set_name(&dev->dev, "%02x", superhyway_devices); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	superhyway_devices++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return device_register(&dev->dev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | int superhyway_add_devices(struct superhyway_bus *bus, | 
					
						
							|  |  |  | 			   struct superhyway_device **devices, | 
					
						
							|  |  |  | 			   int nr_devices) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < nr_devices; i++) { | 
					
						
							|  |  |  | 		struct superhyway_device *dev = devices[i]; | 
					
						
							|  |  |  | 		ret |= superhyway_add_device(dev->resource[0].start, dev, bus); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | static int __init superhyway_init(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 	struct superhyway_bus *bus; | 
					
						
							| 
									
										
										
										
											2007-11-06 18:05:08 +09:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-06 18:05:08 +09:00
										 |  |  | 	ret = device_register(&superhyway_bus_device); | 
					
						
							|  |  |  | 	if (unlikely(ret)) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (bus = superhyway_channels; bus->ops; bus++) | 
					
						
							|  |  |  | 		ret |= superhyway_scan_bus(bus); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | postcore_initcall(superhyway_init); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct superhyway_device_id * | 
					
						
							|  |  |  | superhyway_match_id(const struct superhyway_device_id *ids, | 
					
						
							|  |  |  | 		    struct superhyway_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	while (ids->id) { | 
					
						
							|  |  |  | 		if (ids->id == dev->id.id) | 
					
						
							|  |  |  | 			return ids; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ids++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int superhyway_device_probe(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct superhyway_device *shyway_dev = to_superhyway_device(dev); | 
					
						
							|  |  |  | 	struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (shyway_drv && shyway_drv->probe) { | 
					
						
							|  |  |  | 		const struct superhyway_device_id *id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		id = superhyway_match_id(shyway_drv->id_table, shyway_dev); | 
					
						
							|  |  |  | 		if (id) | 
					
						
							|  |  |  | 			return shyway_drv->probe(shyway_dev, id); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -ENODEV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int superhyway_device_remove(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct superhyway_device *shyway_dev = to_superhyway_device(dev); | 
					
						
							|  |  |  | 	struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (shyway_drv && shyway_drv->remove) { | 
					
						
							|  |  |  | 		shyway_drv->remove(shyway_dev); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -ENODEV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * superhyway_register_driver - Register a new SuperHyway driver | 
					
						
							|  |  |  |  * @drv: SuperHyway driver to register. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This registers the passed in @drv. Any devices matching the id table will | 
					
						
							|  |  |  |  * automatically be populated and handed off to the driver's specified probe | 
					
						
							|  |  |  |  * routine. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int superhyway_register_driver(struct superhyway_driver *drv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	drv->drv.name	= drv->name; | 
					
						
							|  |  |  | 	drv->drv.bus	= &superhyway_bus_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return driver_register(&drv->drv); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * superhyway_unregister_driver - Unregister a SuperHyway driver | 
					
						
							|  |  |  |  * @drv: SuperHyway driver to unregister. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This cleans up after superhyway_register_driver(), and should be invoked in | 
					
						
							|  |  |  |  * the exit path of any module drivers. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void superhyway_unregister_driver(struct superhyway_driver *drv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	driver_unregister(&drv->drv); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int superhyway_bus_match(struct device *dev, struct device_driver *drv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct superhyway_device *shyway_dev = to_superhyway_device(dev); | 
					
						
							|  |  |  | 	struct superhyway_driver *shyway_drv = to_superhyway_driver(drv); | 
					
						
							|  |  |  | 	const struct superhyway_device_id *ids = shyway_drv->id_table; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!ids) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	if (superhyway_match_id(ids, shyway_dev)) | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -ENODEV; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct bus_type superhyway_bus_type = { | 
					
						
							|  |  |  | 	.name		= "superhyway", | 
					
						
							|  |  |  | 	.match		= superhyway_bus_match, | 
					
						
							|  |  |  | #ifdef CONFIG_SYSFS
 | 
					
						
							|  |  |  | 	.dev_attrs	= superhyway_dev_attrs, | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-01-05 14:42:40 +00:00
										 |  |  | 	.probe		= superhyway_device_probe, | 
					
						
							|  |  |  | 	.remove		= superhyway_device_remove, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init superhyway_bus_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return bus_register(&superhyway_bus_type); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __exit superhyway_bus_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	device_unregister(&superhyway_bus_device); | 
					
						
							|  |  |  | 	bus_unregister(&superhyway_bus_type); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | core_initcall(superhyway_bus_init); | 
					
						
							|  |  |  | module_exit(superhyway_bus_exit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EXPORT_SYMBOL(superhyway_bus_type); | 
					
						
							|  |  |  | EXPORT_SYMBOL(superhyway_add_device); | 
					
						
							| 
									
										
										
										
											2005-11-07 00:58:21 -08:00
										 |  |  | EXPORT_SYMBOL(superhyway_add_devices); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | EXPORT_SYMBOL(superhyway_register_driver); | 
					
						
							|  |  |  | EXPORT_SYMBOL(superhyway_unregister_driver); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); |