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