Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/*
  2 * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc)
  3 *
  4 * Copyright (c) 2002-3 Patrick Mochel
  5 *               2002-3 Open Source Development Lab
  6 *
  7 * This file is released under the GPLv2
  8 *
  9 * This exports a 'system' bus type.
 10 * By default, a 'sys' bus gets added to the root of the system. There will
 11 * always be core system devices. Devices can use sysdev_register() to
 12 * add themselves as children of the system bus.
 13 */
 14
 15#include <linux/sysdev.h>
 16#include <linux/err.h>
 17#include <linux/module.h>
 18#include <linux/kernel.h>
 19#include <linux/init.h>
 20#include <linux/string.h>
 21#include <linux/pm.h>
 22#include <linux/device.h>
 23#include <linux/mutex.h>
 24#include <linux/interrupt.h>
 25
 26#include "base.h"
 27
 28#define to_sysdev(k) container_of(k, struct sys_device, kobj)
 29#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
 30
 31
 32static ssize_t
 33sysdev_show(struct kobject *kobj, struct attribute *attr, char *buffer)
 34{
 35	struct sys_device *sysdev = to_sysdev(kobj);
 36	struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr);
 37
 38	if (sysdev_attr->show)
 39		return sysdev_attr->show(sysdev, sysdev_attr, buffer);
 40	return -EIO;
 41}
 42
 43
 44static ssize_t
 45sysdev_store(struct kobject *kobj, struct attribute *attr,
 46	     const char *buffer, size_t count)
 47{
 48	struct sys_device *sysdev = to_sysdev(kobj);
 49	struct sysdev_attribute *sysdev_attr = to_sysdev_attr(attr);
 50
 51	if (sysdev_attr->store)
 52		return sysdev_attr->store(sysdev, sysdev_attr, buffer, count);
 53	return -EIO;
 54}
 55
 56static const struct sysfs_ops sysfs_ops = {
 57	.show	= sysdev_show,
 58	.store	= sysdev_store,
 59};
 60
 61static struct kobj_type ktype_sysdev = {
 62	.sysfs_ops	= &sysfs_ops,
 63};
 64
 65
 66int sysdev_create_file(struct sys_device *s, struct sysdev_attribute *a)
 67{
 68	return sysfs_create_file(&s->kobj, &a->attr);
 69}
 70
 71
 72void sysdev_remove_file(struct sys_device *s, struct sysdev_attribute *a)
 73{
 74	sysfs_remove_file(&s->kobj, &a->attr);
 75}
 76
 77EXPORT_SYMBOL_GPL(sysdev_create_file);
 78EXPORT_SYMBOL_GPL(sysdev_remove_file);
 79
 80#define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj)
 81#define to_sysdev_class_attr(a) container_of(a, \
 82	struct sysdev_class_attribute, attr)
 83
 84static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr,
 85				 char *buffer)
 86{
 87	struct sysdev_class *class = to_sysdev_class(kobj);
 88	struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
 89
 90	if (class_attr->show)
 91		return class_attr->show(class, class_attr, buffer);
 92	return -EIO;
 93}
 94
 95static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr,
 96				  const char *buffer, size_t count)
 97{
 98	struct sysdev_class *class = to_sysdev_class(kobj);
 99	struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr);
100
101	if (class_attr->store)
102		return class_attr->store(class, class_attr, buffer, count);
103	return -EIO;
104}
105
106static const struct sysfs_ops sysfs_class_ops = {
107	.show	= sysdev_class_show,
108	.store	= sysdev_class_store,
109};
110
111static struct kobj_type ktype_sysdev_class = {
112	.sysfs_ops	= &sysfs_class_ops,
113};
114
115int sysdev_class_create_file(struct sysdev_class *c,
116			     struct sysdev_class_attribute *a)
117{
118	return sysfs_create_file(&c->kset.kobj, &a->attr);
119}
120EXPORT_SYMBOL_GPL(sysdev_class_create_file);
121
122void sysdev_class_remove_file(struct sysdev_class *c,
123			      struct sysdev_class_attribute *a)
124{
125	sysfs_remove_file(&c->kset.kobj, &a->attr);
126}
127EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
128
129static struct kset *system_kset;
130
131int sysdev_class_register(struct sysdev_class *cls)
132{
133	int retval;
134
135	pr_debug("Registering sysdev class '%s'\n", cls->name);
136
137	INIT_LIST_HEAD(&cls->drivers);
138	memset(&cls->kset.kobj, 0x00, sizeof(struct kobject));
139	cls->kset.kobj.parent = &system_kset->kobj;
140	cls->kset.kobj.ktype = &ktype_sysdev_class;
141	cls->kset.kobj.kset = system_kset;
142
143	retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name);
144	if (retval)
145		return retval;
146
147	retval = kset_register(&cls->kset);
148	if (!retval && cls->attrs)
149		retval = sysfs_create_files(&cls->kset.kobj,
150					    (const struct attribute **)cls->attrs);
151	return retval;
152}
153
154void sysdev_class_unregister(struct sysdev_class *cls)
155{
156	pr_debug("Unregistering sysdev class '%s'\n",
157		 kobject_name(&cls->kset.kobj));
158	if (cls->attrs)
159		sysfs_remove_files(&cls->kset.kobj,
160				   (const struct attribute **)cls->attrs);
161	kset_unregister(&cls->kset);
162}
163
164EXPORT_SYMBOL_GPL(sysdev_class_register);
165EXPORT_SYMBOL_GPL(sysdev_class_unregister);
166
167static DEFINE_MUTEX(sysdev_drivers_lock);
168
169/*
170 * @dev != NULL means that we're unwinding because some drv->add()
171 * failed for some reason. You need to grab sysdev_drivers_lock before
172 * calling this.
173 */
174static void __sysdev_driver_remove(struct sysdev_class *cls,
175				   struct sysdev_driver *drv,
176				   struct sys_device *from_dev)
177{
178	struct sys_device *dev = from_dev;
179
180	list_del_init(&drv->entry);
181	if (!cls)
182		return;
183
184	if (!drv->remove)
185		goto kset_put;
186
187	if (dev)
188		list_for_each_entry_continue_reverse(dev, &cls->kset.list,
189						     kobj.entry)
190			drv->remove(dev);
191	else
192		list_for_each_entry(dev, &cls->kset.list, kobj.entry)
193			drv->remove(dev);
194
195kset_put:
196	kset_put(&cls->kset);
197}
198
199/**
200 *	sysdev_driver_register - Register auxiliary driver
201 *	@cls:	Device class driver belongs to.
202 *	@drv:	Driver.
203 *
204 *	@drv is inserted into @cls->drivers to be
205 *	called on each operation on devices of that class. The refcount
206 *	of @cls is incremented.
207 */
208int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
209{
210	struct sys_device *dev = NULL;
211	int err = 0;
212
213	if (!cls) {
214		WARN(1, KERN_WARNING "sysdev: invalid class passed to %s!\n",
215			__func__);
216		return -EINVAL;
217	}
218
219	/* Check whether this driver has already been added to a class. */
220	if (drv->entry.next && !list_empty(&drv->entry))
221		WARN(1, KERN_WARNING "sysdev: class %s: driver (%p) has already"
222			" been registered to a class, something is wrong, but "
223			"will forge on!\n", cls->name, drv);
224
225	mutex_lock(&sysdev_drivers_lock);
226	if (cls && kset_get(&cls->kset)) {
227		list_add_tail(&drv->entry, &cls->drivers);
228
229		/* If devices of this class already exist, tell the driver */
230		if (drv->add) {
231			list_for_each_entry(dev, &cls->kset.list, kobj.entry) {
232				err = drv->add(dev);
233				if (err)
234					goto unwind;
235			}
236		}
237	} else {
238		err = -EINVAL;
239		WARN(1, KERN_ERR "%s: invalid device class\n", __func__);
240	}
241
242	goto unlock;
243
244unwind:
245	__sysdev_driver_remove(cls, drv, dev);
246
247unlock:
248	mutex_unlock(&sysdev_drivers_lock);
249	return err;
250}
251
252/**
253 *	sysdev_driver_unregister - Remove an auxiliary driver.
254 *	@cls:	Class driver belongs to.
255 *	@drv:	Driver.
256 */
257void sysdev_driver_unregister(struct sysdev_class *cls,
258			      struct sysdev_driver *drv)
259{
260	mutex_lock(&sysdev_drivers_lock);
261	__sysdev_driver_remove(cls, drv, NULL);
262	mutex_unlock(&sysdev_drivers_lock);
263}
264EXPORT_SYMBOL_GPL(sysdev_driver_register);
265EXPORT_SYMBOL_GPL(sysdev_driver_unregister);
266
267/**
268 *	sysdev_register - add a system device to the tree
269 *	@sysdev:	device in question
270 *
271 */
272int sysdev_register(struct sys_device *sysdev)
273{
274	int error;
275	struct sysdev_class *cls = sysdev->cls;
276
277	if (!cls)
278		return -EINVAL;
279
280	pr_debug("Registering sys device of class '%s'\n",
281		 kobject_name(&cls->kset.kobj));
282
283	/* initialize the kobject to 0, in case it had previously been used */
284	memset(&sysdev->kobj, 0x00, sizeof(struct kobject));
285
286	/* Make sure the kset is set */
287	sysdev->kobj.kset = &cls->kset;
288
289	/* Register the object */
290	error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL,
291				     "%s%d", kobject_name(&cls->kset.kobj),
292				     sysdev->id);
293
294	if (!error) {
295		struct sysdev_driver *drv;
296
297		pr_debug("Registering sys device '%s'\n",
298			 kobject_name(&sysdev->kobj));
299
300		mutex_lock(&sysdev_drivers_lock);
301		/* Generic notification is implicit, because it's that
302		 * code that should have called us.
303		 */
304
305		/* Notify class auxiliary drivers */
306		list_for_each_entry(drv, &cls->drivers, entry) {
307			if (drv->add)
308				drv->add(sysdev);
309		}
310		mutex_unlock(&sysdev_drivers_lock);
311		kobject_uevent(&sysdev->kobj, KOBJ_ADD);
312	}
313
314	return error;
315}
316
317void sysdev_unregister(struct sys_device *sysdev)
318{
319	struct sysdev_driver *drv;
320
321	mutex_lock(&sysdev_drivers_lock);
322	list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
323		if (drv->remove)
324			drv->remove(sysdev);
325	}
326	mutex_unlock(&sysdev_drivers_lock);
327
328	kobject_put(&sysdev->kobj);
329}
330
331EXPORT_SYMBOL_GPL(sysdev_register);
332EXPORT_SYMBOL_GPL(sysdev_unregister);
333
334int __init system_bus_init(void)
335{
336	system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
337	if (!system_kset)
338		return -ENOMEM;
339	return 0;
340}
341
342#define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr)
343
344ssize_t sysdev_store_ulong(struct sys_device *sysdev,
345			   struct sysdev_attribute *attr,
346			   const char *buf, size_t size)
347{
348	struct sysdev_ext_attribute *ea = to_ext_attr(attr);
349	char *end;
350	unsigned long new = simple_strtoul(buf, &end, 0);
351	if (end == buf)
352		return -EINVAL;
353	*(unsigned long *)(ea->var) = new;
354	/* Always return full write size even if we didn't consume all */
355	return size;
356}
357EXPORT_SYMBOL_GPL(sysdev_store_ulong);
358
359ssize_t sysdev_show_ulong(struct sys_device *sysdev,
360			  struct sysdev_attribute *attr,
361			  char *buf)
362{
363	struct sysdev_ext_attribute *ea = to_ext_attr(attr);
364	return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
365}
366EXPORT_SYMBOL_GPL(sysdev_show_ulong);
367
368ssize_t sysdev_store_int(struct sys_device *sysdev,
369			   struct sysdev_attribute *attr,
370			   const char *buf, size_t size)
371{
372	struct sysdev_ext_attribute *ea = to_ext_attr(attr);
373	char *end;
374	long new = simple_strtol(buf, &end, 0);
375	if (end == buf || new > INT_MAX || new < INT_MIN)
376		return -EINVAL;
377	*(int *)(ea->var) = new;
378	/* Always return full write size even if we didn't consume all */
379	return size;
380}
381EXPORT_SYMBOL_GPL(sysdev_store_int);
382
383ssize_t sysdev_show_int(struct sys_device *sysdev,
384			  struct sysdev_attribute *attr,
385			  char *buf)
386{
387	struct sysdev_ext_attribute *ea = to_ext_attr(attr);
388	return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
389}
390EXPORT_SYMBOL_GPL(sysdev_show_int);
391