sys.c 9.12 KB
Newer Older
1 2 3
/*
 * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc)
 *
4 5 6 7
 * Copyright (c) 2002-3 Patrick Mochel
 *               2002-3 Open Source Development Lab
 *
 * This file is released under the GPLv2
8 9 10
 * 
 * This exports a 'system' bus type. 
 * By default, a 'sys' bus gets added to the root of the system. There will
11
 * always be core system devices. Devices can use sys_device_register() to
12 13 14
 * add themselves as children of the system bus.
 */

15
#undef DEBUG
16

17
#include <linux/sysdev.h>
18
#include <linux/err.h>
19
#include <linux/module.h>
20
#include <linux/kernel.h>
21 22
#include <linux/init.h>
#include <linux/slab.h>
23
#include <linux/string.h>
24 25


26 27
extern struct subsystem devices_subsys;

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#define to_sysdev(k) container_of(k,struct sys_device,kobj)
#define to_sysdev_attr(a) container_of(a,struct sysdev_attribute,attr)


static ssize_t 
sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
{
	struct sys_device * sysdev = to_sysdev(kobj);
	struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);

	if (sysdev_attr->show)
		return sysdev_attr->show(sysdev,buffer);
	return 0;
}


static ssize_t
sysdev_store(struct kobject * kobj, struct attribute * attr, 
	     const char * buffer, size_t count)
{
	struct sys_device * sysdev = to_sysdev(kobj);
	struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);

	if (sysdev_attr->store)
		return sysdev_attr->store(sysdev,buffer,count);
	return 0;
}

static struct sysfs_ops sysfs_ops = {
	.show	= sysdev_show,
	.store	= sysdev_store,
};

static struct kobj_type ktype_sysdev = {
	.sysfs_ops	= &sysfs_ops,
};

65 66 67 68 69 70 71 72 73 74 75 76

int sysdev_create_file(struct sys_device * s, struct sysdev_attribute * a)
{
	return sysfs_create_file(&s->kobj,&a->attr);
}


void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
{
	sysfs_remove_file(&s->kobj,&a->attr);
}

77 78
EXPORT_SYMBOL(sysdev_create_file);
EXPORT_SYMBOL(sysdev_remove_file);
79

80 81 82
/* 
 * declare system_subsys 
 */
83
decl_subsys(system,&ktype_sysdev,NULL);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

int sysdev_class_register(struct sysdev_class * cls)
{
	pr_debug("Registering sysdev class '%s'\n",cls->kset.kobj.name);
	INIT_LIST_HEAD(&cls->drivers);
	cls->kset.subsys = &system_subsys;
	kset_set_kset_s(cls,system_subsys);
	return kset_register(&cls->kset);
}

void sysdev_class_unregister(struct sysdev_class * cls)
{
	pr_debug("Unregistering sysdev class '%s'\n",cls->kset.kobj.name);
	kset_unregister(&cls->kset);
}

EXPORT_SYMBOL(sysdev_class_register);
EXPORT_SYMBOL(sysdev_class_unregister);


static LIST_HEAD(global_drivers);
105 106

/**
107 108 109
 *	sysdev_driver_register - Register auxillary driver
 * 	@cls:	Device class driver belongs to.
 *	@drv:	Driver.
110
 *
111 112 113 114 115 116 117 118 119 120 121
 *	If @cls is valid, then @drv is inserted into @cls->drivers to be 
 *	called on each operation on devices of that class. The refcount
 *	of @cls is incremented. 
 *	Otherwise, @drv is inserted into global_drivers, and called for 
 *	each device.
 */

int sysdev_driver_register(struct sysdev_class * cls, 
			   struct sysdev_driver * drv)
{
	down_write(&system_subsys.rwsem);
122
	if (cls && kset_get(&cls->kset)) {
123
		list_add_tail(&drv->entry,&cls->drivers);
124 125 126 127 128 129 130 131

		/* If devices of this class already exist, tell the driver */
		if (drv->add) {
			struct sys_device *dev;
			list_for_each_entry(dev, &cls->kset.list, kobj.entry)
				drv->add(dev);
		}
	} else
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
		list_add_tail(&drv->entry,&global_drivers);
	up_write(&system_subsys.rwsem);
	return 0;
}


/**
 *	sysdev_driver_unregister - Remove an auxillary driver.
 *	@cls:	Class driver belongs to.
 *	@drv:	Driver.
 */
void sysdev_driver_unregister(struct sysdev_class * cls,
			      struct sysdev_driver * drv)
{
	down_write(&system_subsys.rwsem);
	list_del_init(&drv->entry);
148 149 150 151 152 153
	if (cls) {
		if (drv->remove) {
			struct sys_device *dev;
			list_for_each_entry(dev, &cls->kset.list, kobj.entry)
				drv->remove(dev);
		}
154
		kset_put(&cls->kset);
155
	}
156 157 158 159 160 161 162
	up_write(&system_subsys.rwsem);
}


/**
 *	sys_device_register - add a system device to the tree
 *	@sysdev:	device in question
163 164
 *
 */
165
int sys_device_register(struct sys_device * sysdev)
166
{
167 168
	int error;
	struct sysdev_class * cls = sysdev->cls;
169

170
	if (!cls)
171 172
		return -EINVAL;

173 174 175
	/* Make sure the kset is set */
	sysdev->kobj.kset = &cls->kset;

176 177 178
	/* But make sure we point to the right type for sysfs translation */
	sysdev->kobj.ktype = &ktype_sysdev;

179 180 181 182 183
	/* set the kobject name */
	snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d",
		 cls->kset.kobj.name,sysdev->id);

	pr_debug("Registering sys device '%s'\n",sysdev->kobj.name);
184

185 186
	/* Register the object */
	error = kobject_register(&sysdev->kobj);
187 188

	if (!error) {
189 190
		struct sysdev_driver * drv;

191
		down_write(&system_subsys.rwsem);
192 193 194 195 196 197 198 199 200
		/* Generic notification is implicit, because it's that 
		 * code that should have called us. 
		 */

		/* Notify global drivers */
		list_for_each_entry(drv,&global_drivers,entry) {
			if (drv->add)
				drv->add(sysdev);
		}
201

202 203 204 205 206
		/* Notify class auxillary drivers */
		list_for_each_entry(drv,&cls->drivers,entry) {
			if (drv->add)
				drv->add(sysdev);
		}
207
		up_write(&system_subsys.rwsem);
208
	}
209 210 211
	return error;
}

212 213 214 215
void sys_device_unregister(struct sys_device * sysdev)
{
	struct sysdev_driver * drv;

216
	down_write(&system_subsys.rwsem);
217 218 219 220 221 222 223 224 225
	list_for_each_entry(drv,&global_drivers,entry) {
		if (drv->remove)
			drv->remove(sysdev);
	}

	list_for_each_entry(drv,&sysdev->cls->drivers,entry) {
		if (drv->remove)
			drv->remove(sysdev);
	}
226
	up_write(&system_subsys.rwsem);
227 228 229 230 231 232

	kobject_unregister(&sysdev->kobj);
}



233
/**
234
 *	sysdev_shutdown - Shut down all system devices.
235 236 237 238 239
 *
 *	Loop over each class of system devices, and the devices in each
 *	of those classes. For each device, we call the shutdown method for
 *	each driver registered for the device - the globals, the auxillaries,
 *	and the class driver. 
240
 *
241 242 243 244
 *	Note: The list is iterated in reverse order, so that we shut down
 *	child devices before we shut down thier parents. The list ordering
 *	is guaranteed by virtue of the fact that child devices are registered
 *	after their parents. 
245
 */
246

247
void sysdev_shutdown(void)
248
{
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
	struct sysdev_class * cls;

	pr_debug("Shutting Down System Devices\n");

	down_write(&system_subsys.rwsem);
	list_for_each_entry_reverse(cls,&system_subsys.kset.list,
				    kset.kobj.entry) {
		struct sys_device * sysdev;

		pr_debug("Shutting down type '%s':\n",cls->kset.kobj.name);

		list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
			struct sysdev_driver * drv;
			pr_debug(" %s\n",sysdev->kobj.name);

			/* Call global drivers first. */
			list_for_each_entry(drv,&global_drivers,entry) {
				if (drv->shutdown)
					drv->shutdown(sysdev);
			}

			/* Call auxillary drivers next. */
			list_for_each_entry(drv,&cls->drivers,entry) {
				if (drv->shutdown)
					drv->shutdown(sysdev);
			}

			/* Now call the generic one */
			if (cls->shutdown)
				cls->shutdown(sysdev);
		}
	}
	up_write(&system_subsys.rwsem);
282 283
}

284

285 286
/**
 *	sysdev_suspend - Suspend all system devices.
287
 *	@state:		Power state to enter.
288
 *
289
 *	We perform an almost identical operation as sys_device_shutdown()
290 291 292
 *	above, though calling ->suspend() instead. Interrupts are disabled
 *	when this called. Devices are responsible for both saving state and
 *	quiescing or powering down the device. 
293
 *
294 295
 *	This is only called by the device PM core, so we let them handle
 *	all synchronization.
296
 */
297

298
int sysdev_suspend(u32 state)
299
{
300
	struct sysdev_class * cls;
301

302 303 304 305 306 307 308
	pr_debug("Suspending System Devices\n");

	list_for_each_entry_reverse(cls,&system_subsys.kset.list,
				    kset.kobj.entry) {
		struct sys_device * sysdev;

		pr_debug("Suspending type '%s':\n",cls->kset.kobj.name);
309

310 311 312
		list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
			struct sysdev_driver * drv;
			pr_debug(" %s\n",sysdev->kobj.name);
313

314 315 316 317 318
			/* Call global drivers first. */
			list_for_each_entry(drv,&global_drivers,entry) {
				if (drv->suspend)
					drv->suspend(sysdev,state);
			}
319

320 321 322 323 324 325 326 327 328 329 330 331
			/* Call auxillary drivers next. */
			list_for_each_entry(drv,&cls->drivers,entry) {
				if (drv->suspend)
					drv->suspend(sysdev,state);
			}

			/* Now call the generic one */
			if (cls->suspend)
				cls->suspend(sysdev,state);
		}
	}
	return 0;
332 333
}

334 335

/**
336
 *	sysdev_resume - Bring system devices back to life.
337 338 339 340
 *
 *	Similar to sys_device_suspend(), but we iterate the list forwards
 *	to guarantee that parent devices are resumed before their children.
 *
341
 *	Note: Interrupts are disabled when called. 
342 343
 */

344
int sysdev_resume(void)
345
{
346 347 348 349 350 351 352 353
	struct sysdev_class * cls;

	pr_debug("Resuming System Devices\n");

	list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) {
		struct sys_device * sysdev;

		pr_debug("Resuming type '%s':\n",cls->kset.kobj.name);
354

355 356 357 358
		list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
			struct sysdev_driver * drv;
			pr_debug(" %s\n",sysdev->kobj.name);

359 360 361 362 363 364
			/* First, call the class-specific one */
			if (cls->resume)
				cls->resume(sysdev);

			/* Call auxillary drivers next. */
			list_for_each_entry(drv,&cls->drivers,entry) {
365 366 367 368
				if (drv->resume)
					drv->resume(sysdev);
			}

369 370
			/* Call global drivers. */
			list_for_each_entry(drv,&global_drivers,entry) {
371 372 373 374 375 376
				if (drv->resume)
					drv->resume(sysdev);
			}

		}
	}
377 378 379 380
	return 0;
}


381
int __init sys_bus_init(void)
382
{
383 384
	system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
	return subsystem_register(&system_subsys);
385 386
}

387 388
EXPORT_SYMBOL(sys_device_register);
EXPORT_SYMBOL(sys_device_unregister);