[PATCH 1/2] staging: ozwpan: re-implemented event streaming

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Previously event streaming was implemented using ioctls on the main
character device. It has been re-implemented using a seperate character
device and using reads and writes rather than ioctls.
Data structures shared with user mode have been cleaned so they only
contain permitted data types.

Signed-off-by: Chris Kelly <ckelly@xxxxxxxxxxxxxxx>
---
 drivers/staging/ozwpan/ozappif.h    |   12 +--
 drivers/staging/ozwpan/ozcdev.c     |   19 +---
 drivers/staging/ozwpan/ozevent.c    |  225 ++++++++++++++++++++++++++---------
 drivers/staging/ozwpan/ozevent.h    |   11 +-
 drivers/staging/ozwpan/ozeventdef.h |   19 +--
 drivers/staging/ozwpan/ozmain.c     |    2 +-
 6 files changed, 185 insertions(+), 103 deletions(-)

diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
index af02732..1b59b07 100644
--- a/drivers/staging/ozwpan/ozappif.h
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -11,13 +11,13 @@
 #define OZ_IOCTL_MAGIC	0xf4
 
 struct oz_mac_addr {
-	unsigned char a[6];
+	__u8 a[6];
 };
 
 #define OZ_MAX_PDS	8
 
 struct oz_pd_list {
-	int count;
+	__u32 count;
 	struct oz_mac_addr addr[OZ_MAX_PDS];
 };
 
@@ -27,18 +27,10 @@ struct oz_binding_info {
 	char name[OZ_MAX_BINDING_LEN];
 };
 
-struct oz_test {
-	int action;
-};
-
 #define OZ_IOCTL_GET_PD_LIST	_IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
 #define OZ_IOCTL_SET_ACTIVE_PD	_IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
 #define OZ_IOCTL_GET_ACTIVE_PD	_IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
-#define OZ_IOCTL_CLEAR_EVENTS	_IO(OZ_IOCTL_MAGIC, 3)
-#define OZ_IOCTL_GET_EVENTS	_IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist)
 #define OZ_IOCTL_ADD_BINDING	_IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
-#define OZ_IOCTL_TEST		_IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test)
-#define OZ_IOCTL_SET_EVENT_MASK	_IOW(OZ_IOCTL_MAGIC, 7, unsigned long)
 #define OZ_IOCTL_REMOVE_BINDING	_IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
 #define OZ_IOCTL_MAX		9
 
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 1c380d6..4da4899 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -41,9 +41,6 @@ struct oz_serial_ctx {
 };
 /*------------------------------------------------------------------------------
  */
-int g_taction;
-/*------------------------------------------------------------------------------
- */
 static struct oz_cdev g_cdev;
 /*------------------------------------------------------------------------------
  * Context: process and softirq
@@ -276,20 +273,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 				return -EFAULT;
 		}
 		break;
-#ifdef WANT_EVENT_TRACE
-	case OZ_IOCTL_CLEAR_EVENTS:
-		oz_events_clear();
-		break;
-	case OZ_IOCTL_GET_EVENTS:
-		rc = oz_events_copy((void __user *)arg);
-		break;
-	case OZ_IOCTL_SET_EVENT_MASK:
-		if (copy_from_user(&g_evt_mask, (void __user *)arg,
-			sizeof(unsigned long))) {
-			return -EFAULT;
-		}
-		break;
-#endif /* WANT_EVENT_TRACE */
 	case OZ_IOCTL_ADD_BINDING:
 	case OZ_IOCTL_REMOVE_BINDING: {
 			struct oz_binding_info b;
@@ -359,6 +342,7 @@ int oz_cdev_register(void)
 	spin_lock_init(&g_cdev.lock);
 	init_waitqueue_head(&g_cdev.rdq);
 	err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
+	oz_create_event_dev(g_cdev.devnum + 1);
 	return 0;
 }
 /*------------------------------------------------------------------------------
@@ -366,6 +350,7 @@ int oz_cdev_register(void)
  */
 int oz_cdev_deregister(void)
 {
+	oz_destroy_event_dev();
 	cdev_del(&g_cdev.cdev);
 	unregister_chrdev_region(g_cdev.devnum, 1);
 	return 0;
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c
index 73703d3..af1d7c1 100644
--- a/drivers/staging/ozwpan/ozevent.c
+++ b/drivers/staging/ozwpan/ozevent.c
@@ -5,29 +5,49 @@
  */
 #include "ozconfig.h"
 #ifdef WANT_EVENT_TRACE
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
 #include <linux/jiffies.h>
 #include <linux/uaccess.h>
 #include "oztrace.h"
 #include "ozevent.h"
+#include "ozappif.h"
 /*------------------------------------------------------------------------------
+ * Although the event mask is logically part of the oz_evtdev structure, it is
+ * needed outside of this file so define it seperately to avoid the need to
+ * export definition of struct oz_evtdev.
  */
-unsigned long g_evt_mask = 0xffffffff;
+u32 g_evt_mask;
 /*------------------------------------------------------------------------------
  */
 #define OZ_MAX_EVTS	2048	/* Must be power of 2 */
-DEFINE_SPINLOCK(g_eventlock);
-static int g_evt_in;
-static int g_evt_out;
-static int g_missed_events;
-static struct oz_event g_events[OZ_MAX_EVTS];
+struct oz_evtdev {
+	struct cdev dev;
+	int evt_in;
+	int evt_out;
+	int missed_events;
+	int present;
+	atomic_t users;
+	spinlock_t lock;
+	struct semaphore sem;
+	struct oz_event evts[OZ_MAX_EVTS];
+};
+
+static struct oz_evtdev g_evtdev;
+
 /*------------------------------------------------------------------------------
  * Context: process
  */
 void oz_event_init(void)
 {
+	/* Because g_evtdev is static external all fields initally zero so no
+	 * need to reinitialised those.
+	 */
 	oz_trace("Event tracing initialized\n");
-	g_evt_in = g_evt_out = 0;
-	g_missed_events = 0;
+	spin_lock_init(&g_evtdev.lock);
+	sema_init(&g_evtdev.sem, 1);
+	atomic_set(&g_evtdev.users, 0);
 }
 /*------------------------------------------------------------------------------
  * Context: process
@@ -43,74 +63,165 @@ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
 {
 	unsigned long irqstate;
 	int ix;
-	spin_lock_irqsave(&g_eventlock, irqstate);
-	ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
-	if (ix != g_evt_out) {
-		struct oz_event *e = &g_events[g_evt_in];
+	spin_lock_irqsave(&g_evtdev.lock, irqstate);
+	ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1);
+	if (ix != g_evtdev.evt_out) {
+		struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in];
 		e->jiffies = jiffies;
 		e->evt = evt;
 		e->ctx1 = ctx1;
 		e->ctx2 = ctx2;
-		e->ctx3 = ctx3;
+		e->ctx3 = (__u32)(unsigned long)ctx3;
 		e->ctx4 = ctx4;
-		g_evt_in = ix;
+		g_evtdev.evt_in = ix;
 	} else {
-		g_missed_events++;
+		g_evtdev.missed_events++;
 	}
-	spin_unlock_irqrestore(&g_eventlock, irqstate);
+	spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
 }
 /*------------------------------------------------------------------------------
  * Context: process
  */
-int oz_events_copy(struct oz_evtlist __user *lst)
+static void oz_events_clear(struct oz_evtdev *dev)
 {
-	int first;
-	int ix;
-	struct hdr {
-		int count;
-		int missed;
-	} hdr;
-	ix = g_evt_out;
-	hdr.count = g_evt_in - ix;
-	if (hdr.count < 0)
-		hdr.count += OZ_MAX_EVTS;
-	if (hdr.count > OZ_EVT_LIST_SZ)
-		hdr.count = OZ_EVT_LIST_SZ;
-	hdr.missed = g_missed_events;
-	g_missed_events = 0;
-	if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
-		return -EFAULT;
-	first = OZ_MAX_EVTS - ix;
-	if (first > hdr.count)
-		first = hdr.count;
-	if (first) {
-		int sz = first*sizeof(struct oz_event);
-		void __user *p = (void __user *)lst->evts;
-		if (copy_to_user(p, &g_events[ix], sz))
-			return -EFAULT;
-		if (hdr.count > first) {
-			p = (void __user *)&lst->evts[first];
-			sz = (hdr.count-first)*sizeof(struct oz_event);
-			if (copy_to_user(p, g_events, sz))
-				return -EFAULT;
-		}
+	unsigned long irqstate;
+	oz_trace("Clearing events\n");
+	if (down_interruptible(&dev->sem))
+		return;
+	spin_lock_irqsave(&dev->lock, irqstate);
+	dev->evt_in = dev->evt_out = 0;
+	dev->missed_events = 0;
+	spin_unlock_irqrestore(&dev->lock, irqstate);
+	up(&dev->sem);
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_evt_open(struct inode *inode, struct file *filp)
+{
+	struct oz_evtdev *dev;
+	oz_trace("oz_evt_open()\n");
+	oz_trace("major = %d minor = %d\n", imajor(inode), iminor(inode));
+	oz_trace("Open flags: 0x%x\n", filp->f_flags);
+	dev = container_of(inode->i_cdev, struct oz_evtdev, dev);
+	filp->private_data = dev;
+	if (atomic_inc_return(&dev->users) == 1)
+		oz_events_clear(dev);
+	return nonseekable_open(inode, filp);
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_evt_release(struct inode *inode, struct file *filp)
+{
+	struct oz_evtdev *dev = filp->private_data;
+
+	if (atomic_dec_and_test(&dev->users)) {
+		oz_events_clear(dev);
+		g_evt_mask = 0;
 	}
-	ix += hdr.count;
-	if (ix >= OZ_MAX_EVTS)
-		ix -= OZ_MAX_EVTS;
-	g_evt_out = ix;
+	oz_trace("oz_evt_release()\n");
 	return 0;
 }
 /*------------------------------------------------------------------------------
  * Context: process
  */
-void oz_events_clear(void)
+ssize_t oz_evt_read(struct file *filp, char __user *buf, size_t count,
+		loff_t *fpos)
 {
-	unsigned long irqstate;
-	spin_lock_irqsave(&g_eventlock, irqstate);
-	g_evt_in = g_evt_out = 0;
-	g_missed_events = 0;
-	spin_unlock_irqrestore(&g_eventlock, irqstate);
+	struct oz_evtdev *dev = filp->private_data;
+	int rc = 0;
+	int nb_evts = count / sizeof(struct oz_event);
+	int n;
+	int sz;
+
+	if (down_interruptible(&dev->sem))
+		return -ERESTARTSYS;
+	n = dev->evt_in - dev->evt_out;
+	if (n < 0)
+		n += OZ_MAX_EVTS;
+	if (nb_evts > n)
+		nb_evts = n;
+	if (nb_evts == 0)
+		goto out;
+	n = OZ_MAX_EVTS - dev->evt_out;
+	if (n > nb_evts)
+		n = nb_evts;
+	sz = n * sizeof(struct oz_event);
+	if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) {
+		rc = -EFAULT;
+		goto out;
+	}
+	if (n == nb_evts)
+		goto out2;
+	n = nb_evts - n;
+	if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) {
+		rc = -EFAULT;
+		goto out;
+	}
+out2:
+	dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
+	rc = nb_evts * sizeof(struct oz_event);
+out:
+	up(&dev->sem);
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+ssize_t oz_evt_write(struct file *filp, const char __user *buf, size_t count,
+		loff_t *fpos)
+{
+	struct oz_evtdev *dev = filp->private_data;
+	int rc;
+	if (down_interruptible(&dev->sem))
+		return -ERESTARTSYS;
+	if (count < sizeof(g_evt_mask)) {
+		rc = 0;
+		goto out;
+	}
+	if (copy_from_user(&g_evt_mask, buf, sizeof(g_evt_mask))) {
+		rc = -EFAULT;
+		goto out;
+	}
+	rc = sizeof(g_evt_mask);
+	oz_trace("Event mask set to: 0x%x\n", g_evt_mask);
+out:
+	up(&dev->sem);
+	return rc;
+}
+/*------------------------------------------------------------------------------
+ */
+const struct file_operations oz_evtops = {
+	.owner =	THIS_MODULE,
+	.open =		oz_evt_open,
+	.release =	oz_evt_release,
+	.read =		oz_evt_read,
+	.write =	oz_evt_write,
+	.llseek	=	no_llseek,
+};
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_create_event_dev(dev_t devnum)
+{
+	cdev_init(&g_evtdev.dev, &oz_evtops);
+	g_evtdev.dev.owner = THIS_MODULE;
+	g_evtdev.dev.ops = &oz_evtops;
+	/* Failure to add the device means that the event stream will not
+	 * be available but this driver can continued to function perfectly
+	 * well otherwise so we live with that.
+	 */
+	if (cdev_add(&g_evtdev.dev, devnum, 1) == 0)
+		g_evtdev.present = 1;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_destroy_event_dev(void)
+{
+	if (g_evtdev.present)
+		cdev_del(&g_evtdev.dev);
 }
 #endif /* WANT_EVENT_TRACE */
 
diff --git a/drivers/staging/ozwpan/ozevent.h b/drivers/staging/ozwpan/ozevent.h
index f033d01..be80756 100644
--- a/drivers/staging/ozwpan/ozevent.h
+++ b/drivers/staging/ozwpan/ozevent.h
@@ -9,7 +9,7 @@
 #include "ozeventdef.h"
 
 #ifdef WANT_EVENT_TRACE
-extern unsigned long g_evt_mask;
+extern u32 g_evt_mask;
 void oz_event_init(void);
 void oz_event_term(void);
 void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
@@ -18,14 +18,15 @@ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
 		if ((1<<(__evt)) & g_evt_mask) \
 			oz_event_log2(__evt, __ctx1, __ctx2, __ctx3, __ctx4); \
 	} while (0)
-int oz_events_copy(struct oz_evtlist __user *lst);
-void oz_events_clear(void);
+void oz_create_event_dev(dev_t devnum);
+void oz_destroy_event_dev(void);
+
 #else
 #define oz_event_init()
 #define oz_event_term()
 #define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4)
-#define oz_events_copy(__lst)
-#define oz_events_clear()
+#define oz_create_event_dev(__devnum)
+#define oz_destroy_event_dev()
 #endif /* WANT_EVENT_TRACE */
 
 #endif /* _OZEVENT_H */
diff --git a/drivers/staging/ozwpan/ozeventdef.h b/drivers/staging/ozwpan/ozeventdef.h
index a880288..4b93898 100644
--- a/drivers/staging/ozwpan/ozeventdef.h
+++ b/drivers/staging/ozwpan/ozeventdef.h
@@ -29,19 +29,12 @@
 #define OZ_EVT_DEBUG		20
 
 struct oz_event {
-	unsigned long jiffies;
-	unsigned char evt;
-	unsigned char ctx1;
-	unsigned short ctx2;
-	void *ctx3;
-	unsigned ctx4;
-};
-
-#define OZ_EVT_LIST_SZ	64
-struct oz_evtlist {
-	int count;
-	int missed;
-	struct oz_event evts[OZ_EVT_LIST_SZ];
+	__u32 jiffies;
+	__u8 evt;
+	__u8 ctx1;
+	__u16 ctx2;
+	__u32 ctx3;
+	__u32 ctx4;
 };
 
 #endif /* _OZEVENTDEF_H */
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index aaf2ccc..d667562 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -53,6 +53,6 @@ module_exit(ozwpan_exit);
 
 MODULE_AUTHOR("Chris Kelly");
 MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.8");
+MODULE_VERSION("1.0.9");
 MODULE_LICENSE("GPL");
 
-- 
1.7.7.6


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux