mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@suse.de>
To: linux-kernel@vger.kernel.org
Cc: "Hans J. Koch" <hjk@linutronix.de>, Greg Kroah-Hartman <gregkh@suse.de>
Subject: [PATCH 58/60] UIO: Pass information about ioports to userspace (V2)
Date: Tue,  6 Jan 2009 14:12:17 -0800	[thread overview]
Message-ID: <1231279939-32728-58-git-send-email-gregkh@suse.de> (raw)
In-Reply-To: <20090106221123.GA32689@kroah.com>

From: Hans J. Koch <hjk@linutronix.de>

Devices sometimes have memory where all or parts of it can not be mapped to
userspace. But it might still be possible to access this memory from
userspace by other means. An example are PCI cards that advertise not only
mappable memory but also ioport ranges. On x86 architectures, these can be
accessed with ioperm, iopl, inb, outb, and friends. Mike Frysinger (CCed)
reported a similar problem on Blackfin arch where it doesn't seem to be easy
to mmap non-cached memory but it can still be accessed from userspace.

This patch allows kernel drivers to pass information about such ports to
userspace. Similar to the existing mem[] array, it adds a port[] array to
struct uio_info. Each port range is described by start, size, and porttype.

If a driver fills in at least one such port range, the UIO core will simply
pass this information to userspace by creating a new directory "portio"
underneath /sys/class/uio/uioN/. Similar to the "mem" directory, it will
contain a subdirectory (portX) for each port range given.

Note that UIO simply passes this information to userspace, it performs no
action whatsoever with this data. It's userspace's responsibility to obtain
access to these ports and to solve arch dependent issues. The "porttype"
attribute tells userspace what kind of port it is dealing with.

This mechanism could also be used to give userspace information about GPIOs
related to a device. You frequently find such hardware in embedded devices,
so I added a UIO_PORT_GPIO definition. I'm not really sure if this is a good
idea since there are other solutions to this problem, but it won't hurt much
anyway.

Signed-off-by: Hans J. Koch <hjk@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/uio/uio.c          |  159 +++++++++++++++++++++++++++++++++++++++-----
 include/linux/uio_driver.h |   26 +++++++
 2 files changed, 168 insertions(+), 17 deletions(-)

diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 2d2440c..4ca85a1 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -35,6 +35,7 @@ struct uio_device {
 	int			vma_count;
 	struct uio_info		*info;
 	struct kobject		*map_dir;
+	struct kobject		*portio_dir;
 };
 
 static int uio_major;
@@ -75,17 +76,17 @@ static ssize_t map_offset_show(struct uio_mem *mem, char *buf)
 	return sprintf(buf, "0x%lx\n", mem->addr & ~PAGE_MASK);
 }
 
-struct uio_sysfs_entry {
+struct map_sysfs_entry {
 	struct attribute attr;
 	ssize_t (*show)(struct uio_mem *, char *);
 	ssize_t (*store)(struct uio_mem *, const char *, size_t);
 };
 
-static struct uio_sysfs_entry addr_attribute =
+static struct map_sysfs_entry addr_attribute =
 	__ATTR(addr, S_IRUGO, map_addr_show, NULL);
-static struct uio_sysfs_entry size_attribute =
+static struct map_sysfs_entry size_attribute =
 	__ATTR(size, S_IRUGO, map_size_show, NULL);
-static struct uio_sysfs_entry offset_attribute =
+static struct map_sysfs_entry offset_attribute =
 	__ATTR(offset, S_IRUGO, map_offset_show, NULL);
 
 static struct attribute *attrs[] = {
@@ -106,9 +107,9 @@ static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr,
 {
 	struct uio_map *map = to_map(kobj);
 	struct uio_mem *mem = map->mem;
-	struct uio_sysfs_entry *entry;
+	struct map_sysfs_entry *entry;
 
-	entry = container_of(attr, struct uio_sysfs_entry, attr);
+	entry = container_of(attr, struct map_sysfs_entry, attr);
 
 	if (!entry->show)
 		return -EIO;
@@ -116,16 +117,93 @@ static ssize_t map_type_show(struct kobject *kobj, struct attribute *attr,
 	return entry->show(mem, buf);
 }
 
-static struct sysfs_ops uio_sysfs_ops = {
+static struct sysfs_ops map_sysfs_ops = {
 	.show = map_type_show,
 };
 
 static struct kobj_type map_attr_type = {
 	.release	= map_release,
-	.sysfs_ops	= &uio_sysfs_ops,
+	.sysfs_ops	= &map_sysfs_ops,
 	.default_attrs	= attrs,
 };
 
+struct uio_portio {
+	struct kobject kobj;
+	struct uio_port *port;
+};
+#define to_portio(portio) container_of(portio, struct uio_portio, kobj)
+
+static ssize_t portio_start_show(struct uio_port *port, char *buf)
+{
+	return sprintf(buf, "0x%lx\n", port->start);
+}
+
+static ssize_t portio_size_show(struct uio_port *port, char *buf)
+{
+	return sprintf(buf, "0x%lx\n", port->size);
+}
+
+static ssize_t portio_porttype_show(struct uio_port *port, char *buf)
+{
+	const char *porttypes[] = {"none", "x86", "gpio", "other"};
+
+	if ((port->porttype < 0) || (port->porttype > UIO_PORT_OTHER))
+		return -EINVAL;
+
+	return sprintf(buf, "port_%s\n", porttypes[port->porttype]);
+}
+
+struct portio_sysfs_entry {
+	struct attribute attr;
+	ssize_t (*show)(struct uio_port *, char *);
+	ssize_t (*store)(struct uio_port *, const char *, size_t);
+};
+
+static struct portio_sysfs_entry portio_start_attribute =
+	__ATTR(start, S_IRUGO, portio_start_show, NULL);
+static struct portio_sysfs_entry portio_size_attribute =
+	__ATTR(size, S_IRUGO, portio_size_show, NULL);
+static struct portio_sysfs_entry portio_porttype_attribute =
+	__ATTR(porttype, S_IRUGO, portio_porttype_show, NULL);
+
+static struct attribute *portio_attrs[] = {
+	&portio_start_attribute.attr,
+	&portio_size_attribute.attr,
+	&portio_porttype_attribute.attr,
+	NULL,
+};
+
+static void portio_release(struct kobject *kobj)
+{
+	struct uio_portio *portio = to_portio(kobj);
+	kfree(portio);
+}
+
+static ssize_t portio_type_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
+{
+	struct uio_portio *portio = to_portio(kobj);
+	struct uio_port *port = portio->port;
+	struct portio_sysfs_entry *entry;
+
+	entry = container_of(attr, struct portio_sysfs_entry, attr);
+
+	if (!entry->show)
+		return -EIO;
+
+	return entry->show(port, buf);
+}
+
+static struct sysfs_ops portio_sysfs_ops = {
+	.show = portio_type_show,
+};
+
+static struct kobj_type portio_attr_type = {
+	.release	= portio_release,
+	.sysfs_ops	= &portio_sysfs_ops,
+	.default_attrs	= portio_attrs,
+};
+
 static ssize_t show_name(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
@@ -177,10 +255,13 @@ static struct attribute_group uio_attr_grp = {
 static int uio_dev_add_attributes(struct uio_device *idev)
 {
 	int ret;
-	int mi;
+	int mi, pi;
 	int map_found = 0;
+	int portio_found = 0;
 	struct uio_mem *mem;
 	struct uio_map *map;
+	struct uio_port *port;
+	struct uio_portio *portio;
 
 	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
 	if (ret)
@@ -195,25 +276,58 @@ static int uio_dev_add_attributes(struct uio_device *idev)
 			idev->map_dir = kobject_create_and_add("maps",
 							&idev->dev->kobj);
 			if (!idev->map_dir)
-				goto err;
+				goto err_map;
 		}
 		map = kzalloc(sizeof(*map), GFP_KERNEL);
 		if (!map)
-			goto err;
+			goto err_map;
 		kobject_init(&map->kobj, &map_attr_type);
 		map->mem = mem;
 		mem->map = map;
 		ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
 		if (ret)
-			goto err;
+			goto err_map;
 		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
 		if (ret)
-			goto err;
+			goto err_map;
+	}
+
+	for (pi = 0; pi < MAX_UIO_PORT_REGIONS; pi++) {
+		port = &idev->info->port[pi];
+		if (port->size == 0)
+			break;
+		if (!portio_found) {
+			portio_found = 1;
+			idev->portio_dir = kobject_create_and_add("portio",
+							&idev->dev->kobj);
+			if (!idev->portio_dir)
+				goto err_portio;
+		}
+		portio = kzalloc(sizeof(*portio), GFP_KERNEL);
+		if (!portio)
+			goto err_portio;
+		kobject_init(&portio->kobj, &portio_attr_type);
+		portio->port = port;
+		port->portio = portio;
+		ret = kobject_add(&portio->kobj, idev->portio_dir,
+							"port%d", pi);
+		if (ret)
+			goto err_portio;
+		ret = kobject_uevent(&portio->kobj, KOBJ_ADD);
+		if (ret)
+			goto err_portio;
 	}
 
 	return 0;
 
-err:
+err_portio:
+	for (pi--; pi >= 0; pi--) {
+		port = &idev->info->port[pi];
+		portio = port->portio;
+		kobject_put(&portio->kobj);
+	}
+	kobject_put(idev->portio_dir);
+err_map:
 	for (mi--; mi>=0; mi--) {
 		mem = &idev->info->mem[mi];
 		map = mem->map;
@@ -228,15 +342,26 @@ err_group:
 
 static void uio_dev_del_attributes(struct uio_device *idev)
 {
-	int mi;
+	int i;
 	struct uio_mem *mem;
-	for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
-		mem = &idev->info->mem[mi];
+	struct uio_port *port;
+
+	for (i = 0; i < MAX_UIO_MAPS; i++) {
+		mem = &idev->info->mem[i];
 		if (mem->size == 0)
 			break;
 		kobject_put(&mem->map->kobj);
 	}
 	kobject_put(idev->map_dir);
+
+	for (i = 0; i < MAX_UIO_PORT_REGIONS; i++) {
+		port = &idev->info->port[i];
+		if (port->size == 0)
+			break;
+		kobject_put(&port->portio->kobj);
+	}
+	kobject_put(idev->portio_dir);
+
 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
 }
 
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index cdf338d..20be327 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -38,6 +38,24 @@ struct uio_mem {
 
 #define MAX_UIO_MAPS	5
 
+struct uio_portio;
+
+/**
+ * struct uio_port - description of a UIO port region
+ * @start:		start of port region
+ * @size:		size of port region
+ * @porttype:		type of port (see UIO_PORT_* below)
+ * @portio:		for use by the UIO core only.
+ */
+struct uio_port {
+	unsigned long		start;
+	unsigned long		size;
+	int			porttype;
+	struct uio_portio	*portio;
+};
+
+#define MAX_UIO_PORT_REGIONS	5
+
 struct uio_device;
 
 /**
@@ -46,6 +64,7 @@ struct uio_device;
  * @name:		device name
  * @version:		device driver version
  * @mem:		list of mappable memory regions, size==0 for end of list
+ * @port:		list of port regions, size==0 for end of list
  * @irq:		interrupt number or UIO_IRQ_CUSTOM
  * @irq_flags:		flags for request_irq()
  * @priv:		optional private data
@@ -60,6 +79,7 @@ struct uio_info {
 	char			*name;
 	char			*version;
 	struct uio_mem		mem[MAX_UIO_MAPS];
+	struct uio_port		port[MAX_UIO_PORT_REGIONS];
 	long			irq;
 	unsigned long		irq_flags;
 	void			*priv;
@@ -92,4 +112,10 @@ extern void uio_event_notify(struct uio_info *info);
 #define UIO_MEM_LOGICAL	2
 #define UIO_MEM_VIRTUAL 3
 
+/* defines for uio_port->porttype */
+#define UIO_PORT_NONE	0
+#define UIO_PORT_X86	1
+#define UIO_PORT_GPIO	2
+#define UIO_PORT_OTHER	3
+
 #endif /* _LINUX_UIO_DRIVER_H_ */
-- 
1.6.0.4


  parent reply	other threads:[~2009-01-06 22:34 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-06 22:11 [GIT PATCH] driver core patches for your 2.6-git tree Greg KH
2009-01-06 22:11 ` [PATCH 01/60] PM: Simplify the new suspend/hibernation framework for devices Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 02/60] Fix misspellings in pm.h macros Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 03/60] driver core: Rearrange struct device for better packing Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 04/60] driver core: Remove completion from struct klist_node Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 05/60] driver core: struct device - replace bus_id with dev_name(), dev_set_name() Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 06/60] sysfs: clarify SYSFS_DEPRECATED help text Greg Kroah-Hartman
2009-01-07  9:21   ` Mikael Pettersson
2009-01-07 19:38     ` Greg KH
2009-01-06 22:11 ` [PATCH 07/60] uevent: don't pass envp_ext[] as format string in kobject_uevent_env() Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 08/60] kobject: return the result of uevent sending by netlink Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 09/60] kernel/ksysfs.c:fix dependence on CONFIG_NET Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 10/60] PCI: Rework default handling of suspend and resume Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 11/60] kobject: Make Documentation/kobject.txt a little more coherent Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 12/60] dynamic_printk: reduce one level of indentation Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 13/60] driver core: create a private portion of struct device Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 14/60] driver core: move klist_children into private structure Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 15/60] driver core: move knode_driver " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 16/60] driver core: move knode_bus " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 17/60] Make DEBUG take precedence over DYNAMIC_PRINTK_DEBUG Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 18/60] Driver core: move the bus notifier call points Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 19/60] driver core:fix duplicate removing driver link in __device_release_driver Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 20/60] driver core: add root_device_register() Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 21/60] virtio: do not statically allocate root device Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 22/60] lguest: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 23/60] s390: remove s390_root_dev_*() Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 24/60] xen: struct device - replace bus_id with dev_name(), dev_set_name() Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 25/60] w1: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 26/60] video: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 27/60] tifm: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 28/60] thermal: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 29/60] swiotlb: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 30/60] spi: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 31/60] SGI: " Greg Kroah-Hartman
2009-01-06 23:03   ` Jack Steiner
2009-01-06 22:11 ` [PATCH 32/60] serial: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 33/60] power-supply: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 34/60] pnp: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 35/60] mwave: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 36/60] mtd: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 37/60] mips: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 38/60] memstick: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 39/60] macintosh: " Greg Kroah-Hartman
2009-01-06 22:11 ` [PATCH 40/60] pm: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 41/60] ISDN: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 42/60] infiniband: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 43/60] i7300_idle: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 44/60] IA64: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 45/60] i2o: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 46/60] hwmon: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 47/60] gpu: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 48/60] gpio: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 49/60] gadget: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 50/60] dmi: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 51/60] chris: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 52/60] block: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 53/60] avr: " Greg Kroah-Hartman
2009-01-07  8:54   ` Haavard Skinnemoen
2009-01-07 19:36     ` Greg KH
2009-01-06 22:12 ` [PATCH 54/60] libata: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 55/60] arm: " Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 56/60] UIO: use pci_ioremap_bar() in drivers/uio Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 57/60] UIO: uio_pdrv_genirq: allow custom irq_flags Greg Kroah-Hartman
2009-01-06 22:12 ` Greg Kroah-Hartman [this message]
2009-01-06 22:12 ` [PATCH 59/60] UIO: Documentation for UIO ioport info handling Greg Kroah-Hartman
2009-01-06 22:12 ` [PATCH 60/60] uio: make uio_info's name and version const Greg Kroah-Hartman
2009-01-06 23:23 ` [GIT PATCH] driver core patches for your 2.6-git tree Hans J. Koch
2009-01-07  0:36   ` Greg KH
2009-01-07 11:33 ` [PATCH 41/60] ISDN: struct device - replace bus_id with dev_name(), dev_set_name() Karsten Keil

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1231279939-32728-58-git-send-email-gregkh@suse.de \
    --to=gregkh@suse.de \
    --cc=hjk@linutronix.de \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®