From ab121f379a3cff458c90e6f480ba4bb68c8733dd Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 27 Nov 2010 07:49:17 +0100 Subject: Linux Device Drivers 3 examples --- lddbus/Makefile | 39 +++++++++++++ lddbus/lddbus.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 lddbus/Makefile create mode 100644 lddbus/lddbus.c (limited to 'lddbus') diff --git a/lddbus/Makefile b/lddbus/Makefile new file mode 100644 index 0000000..1a3ab78 --- /dev/null +++ b/lddbus/Makefile @@ -0,0 +1,39 @@ +# Comment/uncomment the following line to disable/enable debugging +#DEBUG = y + +# Add your debugging flag (or not) to CFLAGS +ifeq ($(DEBUG),y) + DEBFLAGS = -O -g # "-O" is needed to expand inlines +else + DEBFLAGS = -O2 +endif +CFLAGS += $(DEBFLAGS) -I$(LDDINCDIR) + + +ifneq ($(KERNELRELEASE),) +# call from kernel build system + +obj-m := lddbus.o + +else + +KERNELDIR ?= /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) LDDINCDIR=$(PWD)/../include modules + +endif + + + +clean: + rm -rf *.o *.ko *~ core .depend *.mod.c .*.cmd .tmp_versions .*.o.d + +depend .depend dep: + $(CC) $(CFLAGS) -M *.c > .depend + + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/lddbus/lddbus.c b/lddbus/lddbus.c new file mode 100644 index 0000000..be37c6c --- /dev/null +++ b/lddbus/lddbus.c @@ -0,0 +1,177 @@ +/* + * A virtual bus for LDD sample code devices to plug into. This + * code is heavily borrowed from drivers/base/sys.c + * + * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet + * Copyright (C) 2001 O'Reilly & Associates + * + * The source code in this file can be freely used, adapted, + * and redistributed in source or binary form, so long as an + * acknowledgment appears in derived source files. The citation + * should list that the code comes from the book "Linux Device + * Drivers" by Alessandro Rubini and Jonathan Corbet, published + * by O'Reilly & Associates. No warranty is attached; + * we cannot take responsibility for errors or fitness for use. + * + */ +/* $Id: lddbus.c,v 1.9 2004/09/26 08:12:27 gregkh Exp $ */ + +#include +#include +#include +#include +#include +#include "lddbus.h" + +MODULE_AUTHOR("Jonathan Corbet"); +MODULE_LICENSE("Dual BSD/GPL"); +static char *Version = "$Revision: 1.9 $"; + +/* + * Respond to hotplug events. + */ +static int ldd_hotplug(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + envp[0] = buffer; + if (snprintf(buffer, buffer_size, "LDDBUS_VERSION=%s", + Version) >= buffer_size) + return -ENOMEM; + envp[1] = NULL; + return 0; +} + +/* + * Match LDD devices to drivers. Just do a simple name test. + */ +static int ldd_match(struct device *dev, struct device_driver *driver) +{ + return !strncmp(dev->bus_id, driver->name, strlen(driver->name)); +} + + +/* + * The LDD bus device. + */ +static void ldd_bus_release(struct device *dev) +{ + printk(KERN_DEBUG "lddbus release\n"); +} + +struct device ldd_bus = { + .bus_id = "ldd0", + .release = ldd_bus_release +}; + + +/* + * And the bus type. + */ +struct bus_type ldd_bus_type = { + .name = "ldd", + .match = ldd_match, + .hotplug = ldd_hotplug, +}; + +/* + * Export a simple attribute. + */ +static ssize_t show_bus_version(struct bus_type *bus, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", Version); +} + +static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); + + + +/* + * LDD devices. + */ + +/* + * For now, no references to LDDbus devices go out which are not + * tracked via the module reference count, so we use a no-op + * release function. + */ +static void ldd_dev_release(struct device *dev) +{ } + +int register_ldd_device(struct ldd_device *ldddev) +{ + ldddev->dev.bus = &ldd_bus_type; + ldddev->dev.parent = &ldd_bus; + ldddev->dev.release = ldd_dev_release; + strncpy(ldddev->dev.bus_id, ldddev->name, BUS_ID_SIZE); + return device_register(&ldddev->dev); +} +EXPORT_SYMBOL(register_ldd_device); + +void unregister_ldd_device(struct ldd_device *ldddev) +{ + device_unregister(&ldddev->dev); +} +EXPORT_SYMBOL(unregister_ldd_device); + +/* + * Crude driver interface. + */ + + +static ssize_t show_version(struct device_driver *driver, char *buf) +{ + struct ldd_driver *ldriver = to_ldd_driver(driver); + + sprintf(buf, "%s\n", ldriver->version); + return strlen(buf); +} + + +int register_ldd_driver(struct ldd_driver *driver) +{ + int ret; + + driver->driver.bus = &ldd_bus_type; + ret = driver_register(&driver->driver); + if (ret) + return ret; + driver->version_attr.attr.name = "version"; + driver->version_attr.attr.owner = driver->module; + driver->version_attr.attr.mode = S_IRUGO; + driver->version_attr.show = show_version; + driver->version_attr.store = NULL; + return driver_create_file(&driver->driver, &driver->version_attr); +} + +void unregister_ldd_driver(struct ldd_driver *driver) +{ + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL(register_ldd_driver); +EXPORT_SYMBOL(unregister_ldd_driver); + + + +static int __init ldd_bus_init(void) +{ + int ret; + + ret = bus_register(&ldd_bus_type); + if (ret) + return ret; + if (bus_create_file(&ldd_bus_type, &bus_attr_version)) + printk(KERN_NOTICE "Unable to create version attribute\n"); + ret = device_register(&ldd_bus); + if (ret) + printk(KERN_NOTICE "Unable to register ldd0\n"); + return ret; +} + +static void ldd_bus_exit(void) +{ + device_unregister(&ldd_bus); + bus_unregister(&ldd_bus_type); +} + +module_init(ldd_bus_init); +module_exit(ldd_bus_exit); -- cgit v1.2.1-18-gbd029