All of lore.kernel.org
 help / color / mirror / Atom feed
From: Johannes Berg <johannes@sipsolutions.net>
To: linux-kernel@vger.kernel.org
Cc: linux1394-devel@lists.sourceforge.net
Subject: [RFC 4/4] firewire: add mem1394
Date: Thu, 02 Feb 2006 23:43:05 +0100	[thread overview]
Message-ID: <1138920185.3621.24.camel@localhost> (raw)
In-Reply-To: <1138919238.3621.12.camel@localhost>

While the previous patches were purely infrastructure, this patch
actually adds the code using it: mem1394.

There are some open questions on a few things, maybe someone can help
out there.

diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 39142e2..cd7b28c 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -169,4 +169,21 @@ config IEEE1394_RAWIO
 	  To compile this driver as a module, say M here: the
 	  module will be called raw1394.
 
+config IEEE1394_MEMDEV
+	tristate "IEEE1394 memory device support"
+	depends on IEEE1394 && EXPERIMENTAL
+	help
+	  Say Y here if you want support for the ieee1394 memory device.
+	  This is useful for debugging systems attached via firewire
+	  since it usually allows you to read from and write to their memory,
+	  depending on the controller and machine setup.
+	  
+	  It differs from raw access (which allows the same usage) in that
+	  it provides devices nodes (usually called /dev/fwmem-<guid>) that can
+	  be read and written with any tool, as opposed to specialised tools
+	  required for raw1394.
+	  
+	  To compile this driver as a module, say M here: the
+	  module will be called mem1394.
+
 endmenu
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index 180bf82..7da4e21 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.
 obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
 obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
 obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
+obj-$(CONFIG_IEEE1394_MEMDEV) += mem1394.o
 
 quiet_cmd_oui2c = OUI2C   $@
       cmd_oui2c = $(CONFIG_SHELL) $(src)/oui2c.sh < $< > $@
diff --git a/drivers/ieee1394/mem1394.c b/drivers/ieee1394/mem1394.c
new file mode 100644
index 0000000..e9d44a2
--- /dev/null
+++ b/drivers/ieee1394/mem1394.c
@@ -0,0 +1,277 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * Copyright (C) 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This code is licensed under the GPL v2. See the file COPYING in the root
+ * directory of the kernel sources for details.
+ *
+ * This module provides a character device for each node attached
+ * to the bus and allows direct memory access on them.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/cdev.h>
+
+#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "ieee1394_transactions.h"
+#include "mem1394.h"
+#include "nodemgr.h"
+#include "highlevel.h"
+
+static int mem1394_mmap(struct file * file, struct vm_area_struct * vma)
+{
+	return -ENOSYS;
+}
+
+static int mem1394_open(struct inode *inode, struct file *file)
+{
+	struct mem1394_file_info *fi;
+
+	fi = kzalloc(sizeof(*fi), GFP_KERNEL);
+	if (!fi)
+		return -ENOMEM;
+	file->private_data = fi;
+	fi->memdev = container_of(inode->i_cdev, struct mem1394_dev, cdev);
+	return 0;
+}
+
+/* This function essentially clones hpsb_read. Might be better
+ * to create a new hpsb_read_user function instead... */
+static int mem1394_read(struct file *file, char __user * buffer,
+			size_t count, loff_t *offset)
+{
+	struct mem1394_file_info *fi = (struct mem1394_file_info*)file->private_data;
+	/* lower levels only support count as a multiple of 4 */
+	size_t submitcount = (count + (4-1)) & ~(4-1);
+	int retval = 0;
+	struct hpsb_packet *packet;
+
+	/* this is a bit icky. I think I'll want to create a
+	 * "struct hpsb_node_class_interface" that you register
+	 * with nodemgr.c instead of registering the "struct class_interface"
+	 * directly. It would wrap around the "struct class_interface"
+	 * and handle things like this.
+	 *
+	 * This means it would call the node_class_interface's
+	 *  - "add" method whenever the device is fully there, and an
+	 *  - "update" method when it survived a bus reset, and the
+	 *  - "remove" method when it went away, also taking care of
+	 * debouncing, which the mem1394 interface currently doesn't handle.
+	 *
+	 * But I need advice on this. It'll probably works this way
+	 * but most likely not once this interface stuff gets more
+	 * use; I can imagine using it for scanners instead of raw1394
+	 * so that the kernel can validate that a user can only
+	 * access a certain scanner and not all 1394 devices on the bus.
+	 * In other words some 'raw1394intf' instead of 'raw1394' which
+	 * creates one character device per ieee1394 node for finer
+	 * grained access control.
+	 * That would definitely want to have debouncing etc.
+	 *
+	 * However, I don't fully understand the states node_entries go
+	 * through yet, so I'm not sure this should even be here!
+	 * Maybe it should be in open? But then the device could go
+	 * into limbo when it is already opened...
+	 *
+	 * Similarly, what happens if a node is suspended?
+	 */
+	if (fi->memdev->ne->in_limbo)
+		return -ENODEV;
+
+	if (count == 0)
+		return 0;
+
+	/* I wonder if it is possible to do DMA directly to the userspace buffer... */
+	packet = hpsb_make_readpacket(fi->memdev->ne->host, fi->memdev->ne->nodeid, *offset, submitcount);
+	if (!packet)
+		return -ENOENT;
+	
+	packet->generation = fi->memdev->ne->generation;
+	retval = hpsb_send_packet_and_wait(packet);
+	if (retval < 0)
+		goto out_free;
+
+	retval = hpsb_packet_success(packet);
+	
+	if (retval == 0) {
+		if (submitcount == 4) {
+			if (copy_to_user(buffer, &packet->header[3], count))
+				retval = -EFAULT;
+		} else {
+			if (copy_to_user(buffer, packet->data, count))
+				retval = -EFAULT;
+		}
+	}
+
+	if (retval == 0) {
+		retval = count;
+		*offset += count;
+	}
+
+ out_free:
+	hpsb_free_tlabel(packet);
+	hpsb_free_packet(packet);
+
+	return retval;
+}
+
+static int mem1394_release(struct inode *inode, struct file *file)
+{
+	struct mem1394_file_info *fi = (struct mem1394_file_info*)file->private_data;
+	
+	kfree(fi);
+
+	return 0;
+}
+
+static struct class *mem1394_sysfs_class;
+
+static struct file_operations mem1394_fops = {
+	.owner = THIS_MODULE,
+	.mmap = mem1394_mmap,
+	.open = mem1394_open,
+	.read = mem1394_read,
+	.release = mem1394_release,
+};
+
+static atomic_t mem1394_dev_ctr;
+
+static struct mem1394_dev * alloc_mem1394_dev(struct device *dev)
+{
+	struct mem1394_dev *result;
+	struct node_entry *ne = container_of(dev, struct node_entry, device);
+	int ret;
+	struct class_device * mem1394_class_member;
+
+	result = kzalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return NULL;
+
+	cdev_init(&result->cdev, &mem1394_fops);
+	result->cdev.owner = THIS_MODULE;
+	result->ne = ne;
+
+	ret = hpsb_cdev_add(&result->cdev);
+	if (ret) {
+		printk(KERN_ERR "mem1394: failed to register character device!\n");
+		goto out_free;
+	}
+
+	atomic_inc(&mem1394_dev_ctr);
+	mem1394_class_member = class_device_create(mem1394_sysfs_class, NULL, result->cdev.dev,
+						dev, "fwmem-%d", atomic_read(&mem1394_dev_ctr));
+	if (IS_ERR(mem1394_class_member)) {
+		printk(KERN_WARNING "mem1394: class_device_create failed\n");
+	} else {
+		class_set_devdata(mem1394_class_member, result);
+	}
+	dev->driver_data = result;
+
+	return result;
+ out_free:
+	kfree(result);
+	return NULL;
+}
+
+static DEFINE_SPINLOCK(dev_list_lock);
+static LIST_HEAD(dev_list);
+
+static int mem1394_add(struct class_device *cl_dev, struct class_interface *cl_intf)
+{
+	struct mem1394_dev *memdev;
+
+	if (!cl_dev) {
+		printk("cl_dev not assigned\n");
+		return -ENOENT;
+	}
+	if (!cl_dev->dev) {
+		printk("cl_dev->dev not assigned\n");
+		return -ENONET;
+	}
+
+	memdev = alloc_mem1394_dev(cl_dev->dev);
+	if (!memdev)
+		return -ENOMEM;
+
+	spin_lock(&dev_list_lock);
+	list_add_tail(&memdev->list, &dev_list);
+	spin_unlock(&dev_list_lock);
+
+	/* need we do anything else? */
+	return 0;
+}
+
+static void mem1394_del(struct mem1394_dev *memdev)
+{
+	class_device_destroy(mem1394_sysfs_class, memdev->cdev.dev);
+
+	/* kill off everything that might be in progress */
+	/* TODO */
+
+	/* remove character device */
+	hpsb_cdev_del(&memdev->cdev);
+	kfree(memdev);
+}
+
+static void mem1394_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
+{
+	struct mem1394_dev *memdev, *tmp, *found = NULL;
+	
+	/* find our memdev corresponding to the class device */
+	spin_lock(&dev_list_lock);
+	list_for_each_entry_safe(memdev, tmp, &dev_list, list) {
+		if (cl_dev->dev == memdev->dev) {
+			list_del(&memdev->list);
+			found = memdev;
+			break;
+		}
+	}
+	spin_unlock(&dev_list_lock);
+	if (!found)
+		return;
+
+	mem1394_del(found);
+}
+
+static struct class_interface mem1394_interface = {
+	.add		= mem1394_add,
+	.remove		= mem1394_remove,
+};
+                
+static int __init init_mem1394(void)
+{
+	int ret;
+	
+	spin_lock_init(&dev_list_lock);
+	
+	mem1394_sysfs_class = class_create(THIS_MODULE, "mem1394");
+	if (IS_ERR(mem1394_sysfs_class)) {
+		return PTR_ERR(mem1394_sysfs_class);
+	}
+
+	ret = hpsb_register_node_interface(&mem1394_interface);
+	return ret;
+}
+
+static void __exit cleanup_mem1394(void)
+{
+	struct mem1394_dev *memdev, *tmp;
+
+	hpsb_unregister_node_interface(&mem1394_interface);
+	list_for_each_entry_safe(memdev, tmp, &dev_list, list) {
+		list_del(&memdev->list);
+		mem1394_del(memdev);
+	}
+	class_destroy(mem1394_sysfs_class);
+}
+
+module_init(init_mem1394);
+module_exit(cleanup_mem1394);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
diff --git a/drivers/ieee1394/mem1394.h b/drivers/ieee1394/mem1394.h
new file mode 100644
index 0000000..e7cc8ab
--- /dev/null
+++ b/drivers/ieee1394/mem1394.h
@@ -0,0 +1,20 @@
+#ifndef IEEE1394_MEM1394_H
+#define IEEE1394_MEM1394_H
+
+#include <asm/types.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include "nodemgr.h"
+
+struct mem1394_dev {
+	struct device *dev;
+	struct node_entry *ne;
+	struct cdev cdev;
+	struct list_head list;
+};
+
+struct mem1394_file_info {
+	struct mem1394_dev *memdev;
+};
+
+#endif /* IEEE1394_MEM1394_H */



  parent reply	other threads:[~2006-02-02 22:43 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-02-02 22:27 [RFC 0/4] firewire: interface to remote memory (mem1394) Johannes Berg
2006-02-02 22:38 ` [RFC 1/4] firewire: node interface Johannes Berg
2006-02-02 22:40 ` [RFC 2/4] firewire: dynamic cdev allocation below firewire major Johannes Berg
2006-02-05 13:11   ` Stefan Richter
2006-02-13  3:51   ` Jody McIntyre
2006-02-13  7:32     ` Arjan van de Ven
2006-02-13 12:02       ` Johannes Berg
2006-02-13 16:49         ` Stefan Richter
2006-02-13 21:10         ` Arjan van de Ven
2006-02-14 15:41           ` Johannes Berg
2006-02-02 22:41 ` [RFC 3/4] firewire: unconditionally export hpsb_send_packet_and_wait Johannes Berg
2006-02-05 13:42   ` Stefan Richter
2006-02-07 10:45     ` Johannes Berg
2006-02-02 22:43 ` Johannes Berg [this message]
2006-02-03 11:35   ` [RFC 4/4] firewire: add mem1394 Andy Wingo
2006-02-03 11:47     ` Johannes Berg
2006-02-05 12:59       ` Stefan Richter
2006-02-05  8:43   ` Andrew Morton
2006-02-05  9:09     ` Kyle Moffett
     [not found]       ` <43E5D599.5040503@s5r6.in-berlin.de>
2006-02-05 20:09         ` Stefan Richter
2006-02-05 20:17     ` Andi Kleen
2006-02-05 20:50       ` Stefan Richter
2006-02-06  8:44         ` Andi Kleen
2006-02-05 14:19   ` Stefan Richter
2006-02-07 10:41     ` Johannes Berg

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=1138920185.3621.24.camel@localhost \
    --to=johannes@sipsolutions.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux1394-devel@lists.sourceforge.net \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.