diff options
author | Todd Poynter <tpoynter@nvidia.com> | 2013-10-28 13:40:01 -0500 |
---|---|---|
committer | Harshada Kale <hkale@nvidia.com> | 2013-11-06 02:55:27 -0800 |
commit | 2d4cd9f05640c44bf87342525e5352899aca42e1 (patch) | |
tree | 6fa6e7ac468d08a5fc987c35293ffb2c96299cc4 | |
parent | f9dede308e2f85da438b2ca39a888077f29c25e4 (diff) |
staging: ozwpan: Update to latest drop from ATMEL.
Update the ozwpan driver to the latest drop from ATMEL.
Bug 1394137.
Change-Id: I9069c974cb665a8be68d43536f57c3b717b570a6
Signed-off-by: Todd Poynter <tpoynter@nvidia.com>
Reviewed-on: http://git-master/r/304456
GVS: Gerrit_Virtual_Submit
Reviewed-by: Mitch Luban <mluban@nvidia.com>
Reviewed-by: Toby Butzon <tbutzon@nvidia.com>
26 files changed, 1996 insertions, 1153 deletions
diff --git a/drivers/staging/ozwpan/Kbuild b/drivers/staging/ozwpan/Kbuild index 6cc84cb3f0a6..08bc7938692d 100644 --- a/drivers/staging/ozwpan/Kbuild +++ b/drivers/staging/ozwpan/Kbuild @@ -14,6 +14,6 @@ ozwpan-y := \ ozcdev.o \ ozurbparanoia.o \ oztrace.o \ - ozevent.o + ozkobject.o diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h index af0273293872..ea1b271fdcda 100644 --- a/drivers/staging/ozwpan/ozappif.h +++ b/drivers/staging/ozwpan/ozappif.h @@ -6,18 +6,16 @@ #ifndef _OZAPPIF_H #define _OZAPPIF_H -#include "ozeventdef.h" - #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,20 +25,12 @@ 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 +#define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 3, struct oz_binding_info) +#define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 4, struct oz_binding_info) +#define OZ_IOCTL_MAX 5 #endif /* _OZAPPIF_H */ diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c index 1c380d687963..f3238229b5b3 100644 --- a/drivers/staging/ozwpan/ozcdev.c +++ b/drivers/staging/ozwpan/ozcdev.c @@ -10,17 +10,19 @@ #include <linux/netdevice.h> #include <linux/poll.h> #include <linux/sched.h> -#include "ozconfig.h" #include "ozprotocol.h" #include "oztrace.h" #include "ozappif.h" #include "ozeltbuf.h" #include "ozpd.h" #include "ozproto.h" -#include "ozevent.h" +#include "ozkobject.h" /*------------------------------------------------------------------------------ */ #define OZ_RD_BUF_SZ 256 +#define OZ_MODE_TFTP 0x1 +#define OZ_MODE_SERIAL 0x0 + struct oz_cdev { dev_t devnum; struct cdev cdev; @@ -28,6 +30,8 @@ struct oz_cdev { spinlock_t lock; u8 active_addr[ETH_ALEN]; struct oz_pd *active_pd; + atomic_t ref_count; + u8 mode; }; /* Per PD context for the serial service stored in the PD. */ @@ -35,16 +39,34 @@ struct oz_serial_ctx { atomic_t ref_count; u8 tx_seq_num; u8 rx_seq_num; + u8 tx_done_seq_num; + u8 padding; u8 rd_buf[OZ_RD_BUF_SZ]; int rd_in; int rd_out; + spinlock_t rd_lock; + int dg_len[OZ_RD_BUF_SZ/4]; + int dg_in; + int dg_out; }; /*------------------------------------------------------------------------------ */ -int g_taction; +static struct oz_cdev g_cdev; +struct class *g_oz_class; +struct device *g_oz_wpan_dev; /*------------------------------------------------------------------------------ + * Context: softirq */ -static struct oz_cdev g_cdev; + +static void oz_cdev_elt_completion_callback(struct oz_pd *pd, long context) +{ + struct oz_serial_ctx *ctx; + spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); + ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1]; + if (ctx) + ctx->tx_done_seq_num = (u8)context; + spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); +} /*------------------------------------------------------------------------------ * Context: process and softirq */ @@ -63,7 +85,7 @@ static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd) */ static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx) { - if (atomic_dec_and_test(&ctx->ref_count)) { + if (ctx && atomic_dec_and_test(&ctx->ref_count)) { oz_trace("Dealloc serial context.\n"); kfree(ctx); } @@ -74,8 +96,10 @@ static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx) int oz_cdev_open(struct inode *inode, struct file *filp) { struct oz_cdev *dev; - oz_trace("oz_cdev_open()\n"); - oz_trace("major = %d minor = %d\n", imajor(inode), iminor(inode)); + + if (!atomic_add_unless(&g_cdev.ref_count, 1, 1)) + return -EBUSY; + dev = container_of(inode->i_cdev, struct oz_cdev, cdev); filp->private_data = dev; return 0; @@ -85,7 +109,7 @@ int oz_cdev_open(struct inode *inode, struct file *filp) */ int oz_cdev_release(struct inode *inode, struct file *filp) { - oz_trace("oz_cdev_release()\n"); + atomic_dec(&g_cdev.ref_count); return 0; } /*------------------------------------------------------------------------------ @@ -96,7 +120,7 @@ ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count, { int n; int ix; - + int is_tftp; struct oz_pd *pd; struct oz_serial_ctx *ctx = 0; @@ -104,36 +128,93 @@ ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count, pd = g_cdev.active_pd; if (pd) oz_pd_get(pd); + is_tftp = (g_cdev.mode & OZ_MODE_TFTP) ? 1 : 0; spin_unlock_bh(&g_cdev.lock); if (pd == 0) return -1; ctx = oz_cdev_claim_ctx(pd); if (ctx == 0) goto out2; - n = ctx->rd_in - ctx->rd_out; - if (n < 0) - n += OZ_RD_BUF_SZ; - if (count > n) + + spin_lock_bh(&ctx->rd_lock); + + if (is_tftp) { + /* if n is non zero we have a datagram */ + n = ctx->dg_len[ctx->dg_out]; + + if (n == 0) { + count = 0; + spin_unlock_bh(&ctx->rd_lock); + goto out1; + } + + ix = ctx->rd_out; + spin_unlock_bh(&ctx->rd_lock); + + /* copy n bytes of datagram to user bufer */ + if ((ix + n) < OZ_RD_BUF_SZ) { + if (copy_to_user(buf, &ctx->rd_buf[ix], n)) { + count = 0; + goto out1; + } + spin_lock_bh(&ctx->rd_lock); + ctx->rd_out += n; + } else { + int b = (OZ_RD_BUF_SZ - ix); + /* datagram maybe split in between the end and start of + * the buffer */ + if (copy_to_user(buf, &ctx->rd_buf[ix], b)) { + count = 0; + goto out1; + } + if (copy_to_user(&buf[b], ctx->rd_buf, n - b)) { + count = 0; + goto out1; + } + spin_lock_bh(&ctx->rd_lock); + ctx->rd_out = n - (OZ_RD_BUF_SZ - ix); + } + count = n; - ix = ctx->rd_out; - n = OZ_RD_BUF_SZ - ix; - if (n > count) - n = count; - if (copy_to_user(buf, &ctx->rd_buf[ix], n)) { - count = 0; - goto out1; - } - ix += n; - if (ix == OZ_RD_BUF_SZ) - ix = 0; - if (n < count) { - if (copy_to_user(&buf[n], ctx->rd_buf, count-n)) { + + ctx->dg_len[ctx->dg_out] = 0; + ctx->dg_out++; + if ((OZ_RD_BUF_SZ/4) == ctx->dg_out) + ctx->dg_out = 0; + spin_unlock_bh(&ctx->rd_lock); + } else { + n = ctx->rd_in - ctx->rd_out; + if (n < 0) + n += OZ_RD_BUF_SZ; + if (count > n) + count = n; + + ix = ctx->rd_out; + spin_unlock_bh(&ctx->rd_lock); + n = OZ_RD_BUF_SZ - ix; + if (n > count) + n = count; + + if (copy_to_user(buf, &ctx->rd_buf[ix], n)) { count = 0; goto out1; } - ix = count-n; + + ix += n; + if (ix == OZ_RD_BUF_SZ) + ix = 0; + if (n < count) { + if (copy_to_user(&buf[n], ctx->rd_buf, count-n)) { + count = 0; + goto out1; + } + ix = count-n; + } + + spin_lock_bh(&ctx->rd_lock); + ctx->rd_out = ix; + spin_unlock_bh(&ctx->rd_lock); } - ctx->rd_out = ix; out1: oz_cdev_release_ctx(ctx); out2: @@ -150,6 +231,7 @@ ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count, struct oz_elt_buf *eb; struct oz_elt_info *ei = 0; struct oz_elt *elt; + struct oz_ext_elt *ext_elt; struct oz_app_hdr *app_hdr; struct oz_serial_ctx *ctx; @@ -160,33 +242,52 @@ ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count, spin_unlock_bh(&g_cdev.lock); if (pd == 0) return -1; + if (!(pd->state & OZ_PD_S_CONNECTED)) + return -ENXIO; eb = &pd->elt_buff; ei = oz_elt_info_alloc(eb); if (ei == 0) { count = 0; goto out; } - elt = (struct oz_elt *)ei->data; - app_hdr = (struct oz_app_hdr *)(elt+1); - elt->length = sizeof(struct oz_app_hdr) + count; - elt->type = OZ_ELT_APP_DATA; - ei->app_id = OZ_APPID_SERIAL; - ei->length = elt->length + sizeof(struct oz_elt); - app_hdr->app_id = OZ_APPID_SERIAL; + spin_lock_bh(&g_cdev.lock); + if (g_cdev.mode & OZ_MODE_TFTP) { + spin_unlock_bh(&g_cdev.lock); + ei->app_id = OZ_APPID_SERIAL; + ei->flags |= OZ_EI_F_EXT_ELM; + ext_elt = (struct oz_ext_elt *)ei->data; + app_hdr = (struct oz_app_hdr *)(ext_elt+1); + app_hdr->app_id = OZ_APPID_TFTP; + ext_elt->length = sizeof(struct oz_app_hdr) + count; + ext_elt->type = OZ_ELT_APP_DATA_EX; + ei->length = ext_elt->length + sizeof(struct oz_ext_elt); + ext_elt->length = cpu_to_le16(ext_elt->length); + } else { + spin_unlock_bh(&g_cdev.lock); + ei->app_id = OZ_APPID_SERIAL; + elt = (struct oz_elt *)ei->data; + app_hdr = (struct oz_app_hdr *)(elt+1); + app_hdr->app_id = OZ_APPID_SERIAL; + elt->length = sizeof(struct oz_app_hdr) + count; + elt->type = OZ_ELT_APP_DATA; + ei->length = elt->length + sizeof(struct oz_elt); + } if (copy_from_user(app_hdr+1, buf, count)) goto out; - spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]); + spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1]; if (ctx) { app_hdr->elt_seq_num = ctx->tx_seq_num++; if (ctx->tx_seq_num == 0) ctx->tx_seq_num = 1; + ei->callback = oz_cdev_elt_completion_callback; + ei->context = ctx->tx_seq_num; spin_lock(&eb->lock); if (oz_queue_elt_info(eb, 0, 0, ei) == 0) ei = 0; spin_unlock(&eb->lock); } - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); + spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); out: if (ei) { count = 0; @@ -200,22 +301,40 @@ out: /*------------------------------------------------------------------------------ * Context: process */ -static int oz_set_active_pd(u8 *addr) +int oz_set_active_pd(u8 *addr) { int rc = 0; struct oz_pd *pd; struct oz_pd *old_pd; + struct oz_serial_ctx *ctx; pd = oz_pd_find(addr); if (pd) { spin_lock_bh(&g_cdev.lock); + if (memcmp(g_cdev.active_addr, addr, ETH_ALEN) == 0) { + spin_unlock_bh(&g_cdev.lock); + return rc; + } memcpy(g_cdev.active_addr, addr, ETH_ALEN); old_pd = g_cdev.active_pd; g_cdev.active_pd = pd; spin_unlock_bh(&g_cdev.lock); + + /*Reset buffer pointers if new device is selected*/ + ctx = oz_cdev_claim_ctx(pd); + if (ctx != NULL) { + spin_lock_bh(&ctx->rd_lock); + ctx->dg_in = 0; + ctx->dg_out = 0; + ctx->dg_len[0] = 0; + ctx->rd_out = 0; + ctx->rd_in = 0; + spin_unlock_bh(&ctx->rd_lock); + } + if (old_pd) oz_pd_put(old_pd); } else { - if (!memcmp(addr, "\0\0\0\0\0\0", sizeof(addr))) { + if (!memcmp(addr, "\0\0\0\0\0\0", ETH_ALEN)) { spin_lock_bh(&g_cdev.lock); pd = g_cdev.active_pd; g_cdev.active_pd = 0; @@ -233,6 +352,52 @@ static int oz_set_active_pd(u8 *addr) /*------------------------------------------------------------------------------ * Context: process */ +void oz_get_active_pd(u8 *addr) +{ + spin_lock_bh(&g_cdev.lock); + memcpy(addr, g_cdev.active_addr, ETH_ALEN); + spin_unlock_bh(&g_cdev.lock); + +} +/*------------------------------------------------------------------------------ + * Context: process + */ +u8 oz_get_serial_mode(void) +{ + u8 serial_mode; + + spin_lock_bh(&g_cdev.lock); + serial_mode = g_cdev.mode; + spin_unlock_bh(&g_cdev.lock); + return serial_mode; +} +/*------------------------------------------------------------------------------ + * Context: process + */ +void oz_set_serial_mode(u8 mode) +{ + u8 addr[ETH_ALEN]; + struct oz_pd *pd; + struct oz_serial_ctx *ctx; + + oz_get_active_pd(addr); + pd = oz_pd_find(addr); + if (!pd) + return; + ctx = oz_cdev_claim_ctx(pd); + if (!ctx) { + oz_pd_put(pd); + return; + } + spin_lock_bh(&g_cdev.lock); + g_cdev.mode = mode; + spin_unlock_bh(&g_cdev.lock); + oz_cdev_release_ctx(ctx); + oz_pd_put(pd); +} +/*------------------------------------------------------------------------------ + * Context: process + */ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int rc = 0; @@ -251,7 +416,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case OZ_IOCTL_GET_PD_LIST: { struct oz_pd_list list; - oz_trace("OZ_IOCTL_GET_PD_LIST\n"); list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS); if (copy_to_user((void __user *)arg, &list, sizeof(list))) @@ -260,7 +424,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; case OZ_IOCTL_SET_ACTIVE_PD: { u8 addr[ETH_ALEN]; - oz_trace("OZ_IOCTL_SET_ACTIVE_PD\n"); if (copy_from_user(addr, (void __user *)arg, ETH_ALEN)) return -EFAULT; rc = oz_set_active_pd(addr); @@ -268,7 +431,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; case OZ_IOCTL_GET_ACTIVE_PD: { u8 addr[ETH_ALEN]; - oz_trace("OZ_IOCTL_GET_ACTIVE_PD\n"); spin_lock_bh(&g_cdev.lock); memcpy(addr, g_cdev.active_addr, ETH_ALEN); spin_unlock_bh(&g_cdev.lock); @@ -276,20 +438,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; @@ -315,17 +463,23 @@ unsigned int oz_cdev_poll(struct file *filp, poll_table *wait) { unsigned int ret = 0; struct oz_cdev *dev = filp->private_data; - oz_trace("Poll called wait = %p\n", wait); spin_lock_bh(&dev->lock); if (dev->active_pd) { struct oz_serial_ctx *ctx = oz_cdev_claim_ctx(dev->active_pd); + spin_unlock_bh(&dev->lock); if (ctx) { + spin_lock_bh(&ctx->rd_lock); if (ctx->rd_in != ctx->rd_out) ret |= POLLIN | POLLRDNORM; + + if (ctx->tx_seq_num == ctx->tx_done_seq_num) + ret |= POLLOUT; + spin_unlock_bh(&ctx->rd_lock); oz_cdev_release_ctx(ctx); } - } - spin_unlock_bh(&dev->lock); + } else + spin_unlock_bh(&dev->lock); + if (wait) poll_wait(filp, &dev->rdq, wait); return ret; @@ -350,16 +504,36 @@ int oz_cdev_register(void) memset(&g_cdev, 0, sizeof(g_cdev)); err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan"); if (err < 0) - return err; - oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum), - MINOR(g_cdev.devnum)); + goto out3; cdev_init(&g_cdev.cdev, &oz_fops); g_cdev.cdev.owner = THIS_MODULE; g_cdev.cdev.ops = &oz_fops; spin_lock_init(&g_cdev.lock); init_waitqueue_head(&g_cdev.rdq); err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1); + if (err < 0) { + oz_trace("Failed to add cdev\n"); + goto out2; + } + g_oz_class = class_create(THIS_MODULE, "ozmo_wpan"); + if (IS_ERR(g_oz_class)) { + oz_trace("Failed to register ozmo_wpan class\n"); + goto out1; + } + g_oz_wpan_dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, + "ozwpan"); + if (IS_ERR(g_oz_wpan_dev)) { + oz_trace("Failed to create sysfs entry for cdev\n"); + goto out1; + } + oz_create_sys_entry(); return 0; +out1: + cdev_del(&g_cdev.cdev); +out2: + unregister_chrdev_region(g_cdev.devnum, 1); +out3: + return err; } /*------------------------------------------------------------------------------ * Context: process @@ -368,6 +542,11 @@ int oz_cdev_deregister(void) { cdev_del(&g_cdev.cdev); unregister_chrdev_region(g_cdev.devnum, 1); + if (g_oz_class) { + oz_destroy_sys_entry(); + device_destroy(g_oz_class, g_cdev.devnum); + class_destroy(g_oz_class); + } return 0; } /*------------------------------------------------------------------------------ @@ -375,7 +554,6 @@ int oz_cdev_deregister(void) */ int oz_cdev_init(void) { - oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_SERIAL, 0, 0); oz_app_enable(OZ_APPID_SERIAL, 1); return 0; } @@ -384,7 +562,6 @@ int oz_cdev_init(void) */ void oz_cdev_term(void) { - oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_SERIAL, 0, 0); oz_app_enable(OZ_APPID_SERIAL, 0); } /*------------------------------------------------------------------------------ @@ -394,7 +571,6 @@ int oz_cdev_start(struct oz_pd *pd, int resume) { struct oz_serial_ctx *ctx; struct oz_serial_ctx *old_ctx = 0; - oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_SERIAL, 0, resume); if (resume) { oz_trace("Serial service resumed.\n"); return 0; @@ -404,6 +580,7 @@ int oz_cdev_start(struct oz_pd *pd, int resume) return -ENOMEM; atomic_set(&ctx->ref_count, 1); ctx->tx_seq_num = 1; + ctx->tx_done_seq_num = 1; spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); old_ctx = pd->app_ctx[OZ_APPID_SERIAL-1]; if (old_ctx) { @@ -418,7 +595,6 @@ int oz_cdev_start(struct oz_pd *pd, int resume) (memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) { oz_pd_get(pd); g_cdev.active_pd = pd; - oz_trace("Active PD arrived.\n"); } spin_unlock(&g_cdev.lock); oz_trace("Serial service started.\n"); @@ -430,7 +606,6 @@ int oz_cdev_start(struct oz_pd *pd, int resume) void oz_cdev_stop(struct oz_pd *pd, int pause) { struct oz_serial_ctx *ctx; - oz_event_log(OZ_EVT_SERVICE, 4, OZ_APPID_SERIAL, 0, pause); if (pause) { oz_trace("Serial service paused.\n"); return; @@ -449,7 +624,6 @@ void oz_cdev_stop(struct oz_pd *pd, int pause) spin_unlock(&g_cdev.lock); if (pd) { oz_pd_put(pd); - oz_trace("Active PD departed.\n"); } oz_trace("Serial service stopped.\n"); } @@ -465,6 +639,11 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) int space; int copy_sz; int ix; + int is_tftp; + + spin_lock_bh(&g_cdev.lock); + is_tftp = (g_cdev.mode & OZ_MODE_TFTP) ? 1 : 0; + spin_unlock_bh(&g_cdev.lock); ctx = oz_cdev_claim_ctx(pd); if (ctx == 0) { @@ -472,7 +651,7 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) return; } - app_hdr = (struct oz_app_hdr *)(elt+1); + app_hdr = (struct oz_app_hdr *)(oz_elt_data(elt)); /* If sequence number is non-zero then check it is not a duplicate. */ if (app_hdr->elt_seq_num != 0) { @@ -484,10 +663,11 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) } } ctx->rx_seq_num = app_hdr->elt_seq_num; - len = elt->length - sizeof(struct oz_app_hdr); - data = ((u8 *)(elt+1)) + sizeof(struct oz_app_hdr); + len = oz_elt_data_len(elt) - sizeof(struct oz_app_hdr); + data = ((u8 *)(app_hdr + 1)); if (len <= 0) goto out; + spin_lock_bh(&ctx->rd_lock); space = ctx->rd_out - ctx->rd_in - 1; if (space < 0) space += OZ_RD_BUF_SZ; @@ -495,6 +675,19 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) oz_trace("Not enough space:%d %d\n", len, space); len = space; } + + + if (is_tftp) { + if (len != 0) { + /* remember length of datagram */ + ctx->dg_len[ctx->dg_in] = len; + + ctx->dg_in++; + if ((OZ_RD_BUF_SZ/4) == ctx->dg_in) + ctx->dg_in = 0; + } + } + ix = ctx->rd_in; copy_sz = OZ_RD_BUF_SZ - ix; if (copy_sz > len) @@ -509,6 +702,7 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) ix = len; } ctx->rd_in = ix; + spin_unlock_bh(&ctx->rd_lock); wake_up(&g_cdev.rdq); out: oz_cdev_release_ctx(ctx); diff --git a/drivers/staging/ozwpan/ozcdev.h b/drivers/staging/ozwpan/ozcdev.h index 698014bb8d72..0e4071782448 100644 --- a/drivers/staging/ozwpan/ozcdev.h +++ b/drivers/staging/ozwpan/ozcdev.h @@ -6,6 +6,7 @@ #ifndef _OZCDEV_H #define _OZCDEV_H +extern struct device *g_oz_wpan_dev; int oz_cdev_register(void); int oz_cdev_deregister(void); int oz_cdev_init(void); @@ -14,5 +15,7 @@ int oz_cdev_start(struct oz_pd *pd, int resume); void oz_cdev_stop(struct oz_pd *pd, int pause); void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt); void oz_cdev_heartbeat(struct oz_pd *pd); +int oz_set_active_pd(u8 *addr); +void oz_get_active_pd(u8 *addr); #endif /* _OZCDEV_H */ diff --git a/drivers/staging/ozwpan/ozconfig.h b/drivers/staging/ozwpan/ozconfig.h deleted file mode 100644 index 43e6373a009c..000000000000 --- a/drivers/staging/ozwpan/ozconfig.h +++ /dev/null @@ -1,27 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ---------------------------------------------------------------------------*/ -#ifndef _OZCONFIG_H -#define _OZCONFIG_H - -/* #define WANT_TRACE */ -#ifdef WANT_TRACE -#define WANT_VERBOSE_TRACE -#endif /* #ifdef WANT_TRACE */ -/* #define WANT_URB_PARANOIA */ - -/* #define WANT_PRE_2_6_39 */ -#define WANT_EVENT_TRACE - -/* These defines determine what verbose trace is displayed. */ -#ifdef WANT_VERBOSE_TRACE -/* #define WANT_TRACE_STREAM */ -/* #define WANT_TRACE_URB */ -/* #define WANT_TRACE_CTRL_DETAIL */ -#define WANT_TRACE_HUB -/* #define WANT_TRACE_RX_FRAMES */ -/* #define WANT_TRACE_TX_FRAMES */ -#endif /* WANT_VERBOSE_TRACE */ - -#endif /* _OZCONFIG_H */ diff --git a/drivers/staging/ozwpan/ozeltbuf.c b/drivers/staging/ozwpan/ozeltbuf.c index 988f522475d9..e86f28b8dfa5 100644 --- a/drivers/staging/ozwpan/ozeltbuf.c +++ b/drivers/staging/ozwpan/ozeltbuf.c @@ -6,7 +6,6 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/netdevice.h> -#include "ozconfig.h" #include "ozprotocol.h" #include "ozeltbuf.h" #include "ozpd.h" @@ -132,8 +131,6 @@ int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count) { struct oz_elt_stream *st; - oz_trace("oz_elt_stream_create(0x%x)\n", id); - st = kzalloc(sizeof(struct oz_elt_stream), GFP_ATOMIC | __GFP_ZERO); if (st == 0) return -ENOMEM; @@ -152,7 +149,7 @@ int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id) { struct list_head *e; struct oz_elt_stream *st; - oz_trace("oz_elt_stream_delete(0x%x)\n", id); + spin_lock_bh(&buf->lock); e = buf->stream_list.next; while (e != &buf->stream_list) { @@ -175,9 +172,6 @@ int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id) list_del_init(&ei->link); list_del_init(&ei->link_order); st->buf_count -= ei->length; - oz_trace2(OZ_TRACE_STREAM, "Stream down: %d %d %d\n", - st->buf_count, - ei->length, atomic_read(&st->ref_count)); oz_elt_stream_put(st); oz_elt_info_free(buf, ei); } @@ -242,8 +236,6 @@ int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id, st->buf_count += ei->length; /* Add to list in stream. */ list_add_tail(&ei->link, &st->elt_list); - oz_trace2(OZ_TRACE_STREAM, "Stream up: %d %d\n", - st->buf_count, ei->length); /* Check if we have too much buffered for this stream. If so * start dropping elements until we are back in bounds. */ @@ -283,8 +275,12 @@ int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len, ei = container_of(e, struct oz_elt_info, link_order); e = e->next; if ((*len + ei->length) <= max_len) { - app_hdr = (struct oz_app_hdr *) - &ei->data[sizeof(struct oz_elt)]; + if (ei->flags & OZ_EI_F_EXT_ELM) + app_hdr = (struct oz_app_hdr *) + &ei->data[sizeof(struct oz_ext_elt)]; + else + app_hdr = (struct oz_app_hdr *) + &ei->data[sizeof(struct oz_elt)]; app_hdr->elt_seq_num = buf->tx_seq_num[ei->app_id]++; if (buf->tx_seq_num[ei->app_id] == 0) buf->tx_seq_num[ei->app_id] = 1; @@ -293,9 +289,6 @@ int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len, list_del(&ei->link_order); if (ei->stream) { ei->stream->buf_count -= ei->length; - oz_trace2(OZ_TRACE_STREAM, - "Stream down: %d %d\n", - ei->stream->buf_count, ei->length); oz_elt_stream_put(ei->stream); ei->stream = 0; } diff --git a/drivers/staging/ozwpan/ozeltbuf.h b/drivers/staging/ozwpan/ozeltbuf.h index 03c12f57b9bb..2c184be4adab 100644 --- a/drivers/staging/ozwpan/ozeltbuf.h +++ b/drivers/staging/ozwpan/ozeltbuf.h @@ -23,7 +23,7 @@ struct oz_elt_stream { u8 id; }; -#define OZ_MAX_ELT_PAYLOAD 255 +#define OZ_MAX_ELT_PAYLOAD 1024 struct oz_elt_info { struct list_head link; struct list_head link_order; @@ -32,12 +32,13 @@ struct oz_elt_info { oz_elt_callback_t callback; long context; struct oz_elt_stream *stream; - u8 data[sizeof(struct oz_elt) + OZ_MAX_ELT_PAYLOAD]; + u8 data[sizeof(struct oz_ext_elt) + OZ_MAX_ELT_PAYLOAD]; int length; unsigned magic; }; /* Flags values */ #define OZ_EI_F_MARKED 0x1 +#define OZ_EI_F_EXT_ELM 0x2 struct oz_elt_buf { spinlock_t lock; diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c deleted file mode 100644 index 73703d3e96bd..000000000000 --- a/drivers/staging/ozwpan/ozevent.c +++ /dev/null @@ -1,116 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#include "ozconfig.h" -#ifdef WANT_EVENT_TRACE -#include <linux/jiffies.h> -#include <linux/uaccess.h> -#include "oztrace.h" -#include "ozevent.h" -/*------------------------------------------------------------------------------ - */ -unsigned long g_evt_mask = 0xffffffff; -/*------------------------------------------------------------------------------ - */ -#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]; -/*------------------------------------------------------------------------------ - * Context: process - */ -void oz_event_init(void) -{ - oz_trace("Event tracing initialized\n"); - g_evt_in = g_evt_out = 0; - g_missed_events = 0; -} -/*------------------------------------------------------------------------------ - * Context: process - */ -void oz_event_term(void) -{ - oz_trace("Event tracing terminated\n"); -} -/*------------------------------------------------------------------------------ - * Context: any - */ -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]; - e->jiffies = jiffies; - e->evt = evt; - e->ctx1 = ctx1; - e->ctx2 = ctx2; - e->ctx3 = ctx3; - e->ctx4 = ctx4; - g_evt_in = ix; - } else { - g_missed_events++; - } - spin_unlock_irqrestore(&g_eventlock, irqstate); -} -/*------------------------------------------------------------------------------ - * Context: process - */ -int oz_events_copy(struct oz_evtlist __user *lst) -{ - 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; - } - } - ix += hdr.count; - if (ix >= OZ_MAX_EVTS) - ix -= OZ_MAX_EVTS; - g_evt_out = ix; - return 0; -} -/*------------------------------------------------------------------------------ - * Context: process - */ -void oz_events_clear(void) -{ - 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); -} -#endif /* WANT_EVENT_TRACE */ - diff --git a/drivers/staging/ozwpan/ozevent.h b/drivers/staging/ozwpan/ozevent.h deleted file mode 100644 index f033d014c6f3..000000000000 --- a/drivers/staging/ozwpan/ozevent.h +++ /dev/null @@ -1,31 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZEVENT_H -#define _OZEVENT_H -#include "ozconfig.h" -#include "ozeventdef.h" - -#ifdef WANT_EVENT_TRACE -extern unsigned long 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); -#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) \ - do { \ - 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); -#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() -#endif /* WANT_EVENT_TRACE */ - -#endif /* _OZEVENT_H */ diff --git a/drivers/staging/ozwpan/ozeventdef.h b/drivers/staging/ozwpan/ozeventdef.h deleted file mode 100644 index a880288bab11..000000000000 --- a/drivers/staging/ozwpan/ozeventdef.h +++ /dev/null @@ -1,47 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZEVENTDEF_H -#define _OZEVENTDEF_H - -#define OZ_EVT_RX_FRAME 0 -#define OZ_EVT_RX_PROCESS 1 -#define OZ_EVT_TX_FRAME 2 -#define OZ_EVT_TX_ISOC 3 -#define OZ_EVT_URB_SUBMIT 4 -#define OZ_EVT_URB_DONE 5 -#define OZ_EVT_URB_CANCEL 6 -#define OZ_EVT_CTRL_REQ 7 -#define OZ_EVT_CTRL_CNF 8 -#define OZ_EVT_CTRL_LOCAL 9 -#define OZ_EVT_CONNECT_REQ 10 -#define OZ_EVT_CONNECT_RSP 11 -#define OZ_EVT_EP_CREDIT 12 -#define OZ_EVT_EP_BUFFERING 13 -#define OZ_EVT_TX_ISOC_DONE 14 -#define OZ_EVT_TX_ISOC_DROP 15 -#define OZ_EVT_TIMER_CTRL 16 -#define OZ_EVT_TIMER 17 -#define OZ_EVT_PD_STATE 18 -#define OZ_EVT_SERVICE 19 -#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]; -}; - -#endif /* _OZEVENTDEF_H */ diff --git a/drivers/staging/ozwpan/ozeventtrace.h b/drivers/staging/ozwpan/ozeventtrace.h new file mode 100644 index 000000000000..def0878b3fc1 --- /dev/null +++ b/drivers/staging/ozwpan/ozeventtrace.h @@ -0,0 +1,219 @@ +/* ----------------------------------------------------------------------------- + * Copyright (c) 2011 Ozmo Inc + * Released under the GNU General Public License Version 2 (GPLv2). + * ----------------------------------------------------------------------------- + */ + + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM ozwpan + +#if !defined(_OZEVENTTRACE_H) || defined(TRACE_HEADER_MULTI_READ) + +#define _OZEVENTTRACE_H + +#include <linux/tracepoint.h> +#include <linux/usb.h> + +#define MAX_URB_LEN 16 +#define MAX_FRAME_LEN 32 +#define MAX_MSG_LEN 128 + +TRACE_EVENT(urb_in, + + TP_PROTO(struct urb *oz_urb), + + TP_ARGS(oz_urb), + + TP_STRUCT__entry( + __field(uintptr_t, urb) + __field(u32, endpoint) + __field(u32, buffer_length) + __field(u32, inc_length) + __array(u8, buffer, MAX_URB_LEN) + ), + + TP_fast_assign( + __entry->urb = (uintptr_t)oz_urb; + __entry->endpoint = usb_pipeendpoint(oz_urb->pipe); + if (usb_pipein(oz_urb->pipe)) + __entry->endpoint |= 0x80; + __entry->buffer_length = oz_urb->transfer_buffer_length; + __entry->inc_length = oz_urb->transfer_buffer_length + <= MAX_URB_LEN ? oz_urb->transfer_buffer_length : MAX_URB_LEN; + if ((__entry->endpoint == 0x00) || + (__entry->endpoint == 0x80)) { + __entry->buffer_length = 8; + __entry->inc_length = 8; + memcpy(__entry->buffer, oz_urb->setup_packet, 8); + } else { + memcpy(__entry->buffer, oz_urb->transfer_buffer, + __entry->inc_length); + } + ), + + TP_printk("%08x,%02x,%03x,%03x," + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + (u32)__entry->urb, __entry->endpoint, __entry->buffer_length, + __entry->inc_length, __entry->buffer[0], __entry->buffer[1], + __entry->buffer[2], __entry->buffer[3], __entry->buffer[4], + __entry->buffer[5], __entry->buffer[6], __entry->buffer[7], + __entry->buffer[8], __entry->buffer[9], __entry->buffer[10], + __entry->buffer[11], __entry->buffer[12], __entry->buffer[13], + __entry->buffer[14], __entry->buffer[15]) +); + +TRACE_EVENT(urb_out, + + TP_PROTO(struct urb *oz_urb, int status), + + TP_ARGS(oz_urb, status), + + TP_STRUCT__entry( + __field(uintptr_t, urb) + __field(u32, endpoint) + __field(u32, status) + __field(u32, actual_length) + __field(u32, inc_length) + __array(u8, buffer, MAX_URB_LEN) + ), + + TP_fast_assign( + __entry->urb = (uintptr_t)oz_urb; + __entry->endpoint = usb_pipeendpoint(oz_urb->pipe); + __entry->status = status; + if (usb_pipein(oz_urb->pipe)) + __entry->endpoint |= 0x80; + __entry->actual_length = oz_urb->actual_length; + __entry->inc_length = oz_urb->actual_length + <= MAX_URB_LEN ? oz_urb->actual_length : MAX_URB_LEN; + if (usb_pipein(oz_urb->pipe)) + memcpy(__entry->buffer, oz_urb->transfer_buffer, + __entry->inc_length); + ), + + TP_printk("%08x,%08x,%02x,%03x,%03x," + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + (u32)__entry->urb, __entry->status, __entry->endpoint, + __entry->actual_length, __entry->inc_length, __entry->buffer[0], + __entry->buffer[1], __entry->buffer[2], __entry->buffer[3], + __entry->buffer[4], __entry->buffer[5], __entry->buffer[6], + __entry->buffer[7], __entry->buffer[8], __entry->buffer[9], + __entry->buffer[10], __entry->buffer[11], __entry->buffer[12], + __entry->buffer[13], __entry->buffer[14], __entry->buffer[15]) +); + +TRACE_EVENT(rx_frame, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb), + + TP_STRUCT__entry( + __field(u32, inc_len) + __field(u32, orig_len) + __array(u8, data, MAX_FRAME_LEN) + ), + + TP_fast_assign( + __entry->orig_len = skb->len; + __entry->inc_len = skb->len < MAX_FRAME_LEN ? + skb->len : MAX_FRAME_LEN; + memcpy(__entry->data, (u8 *)skb_network_header(skb), + __entry->inc_len); + ), + + TP_printk("%03x,%03x,%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x", __entry->orig_len, + __entry->inc_len, __entry->data[0], __entry->data[1], + __entry->data[2], __entry->data[3], __entry->data[4], + __entry->data[5], __entry->data[6], __entry->data[7], + __entry->data[8], __entry->data[9], __entry->data[10], + __entry->data[11], __entry->data[12], __entry->data[13], + __entry->data[14], __entry->data[15], __entry->data[16], + __entry->data[17], __entry->data[18], __entry->data[19], + __entry->data[20], __entry->data[21], __entry->data[22], + __entry->data[23], __entry->data[24], __entry->data[25], + __entry->data[26], __entry->data[27], __entry->data[28], + __entry->data[29], __entry->data[30], __entry->data[31]) +); + +TRACE_EVENT(tx_frame, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb), + + TP_STRUCT__entry( + __field(u32, inc_len) + __field(u32, orig_len) + __array(u8, data, MAX_FRAME_LEN) + ), + + TP_fast_assign( + __entry->orig_len = skb->len - 14; + __entry->inc_len = __entry->orig_len + < MAX_FRAME_LEN ? + __entry->orig_len + : MAX_FRAME_LEN; + memcpy(__entry->data, (u8 *)skb_network_header(skb), + __entry->inc_len); + ), + + TP_printk("%03x,%03x,%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x", __entry->orig_len, + __entry->inc_len, __entry->data[0], __entry->data[1], + __entry->data[2], __entry->data[3], __entry->data[4], + __entry->data[5], __entry->data[6], __entry->data[7], + __entry->data[8], __entry->data[9], __entry->data[10], + __entry->data[11], __entry->data[12], __entry->data[13], + __entry->data[14], __entry->data[15], __entry->data[16], + __entry->data[17], __entry->data[18], __entry->data[19], + __entry->data[20], __entry->data[21], __entry->data[22], + __entry->data[23], __entry->data[24], __entry->data[25], + __entry->data[26], __entry->data[27], __entry->data[28], + __entry->data[29], __entry->data[30], __entry->data[31]) +); + +DECLARE_EVENT_CLASS(debug_msg, + + TP_PROTO(char *fmt, va_list arg), + + TP_ARGS(fmt, arg), + + TP_STRUCT__entry( + __array(char, msg, MAX_MSG_LEN) + ), + + TP_fast_assign( + snprintf(__entry->msg, MAX_MSG_LEN, fmt, arg); + ), + + TP_printk("%s", __entry->msg) +); + +DEFINE_EVENT(debug_msg, hcd_msg_evt, + TP_PROTO(char *fmt, va_list arg), + TP_ARGS(fmt, arg) +); + +DEFINE_EVENT(debug_msg, isoc_msg_evt, + TP_PROTO(char *fmt, va_list arg), + TP_ARGS(fmt, arg) +); + +DEFINE_EVENT(debug_msg, info_msg_evt, + TP_PROTO(char *fmt, va_list arg), + TP_ARGS(fmt, arg) +); + + +#endif /*_OZEVENTTRACE_H*/ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE ozeventtrace +#include <trace/define_trace.h> diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c index 750b14eb505e..c26547b4e553 100644 --- a/drivers/staging/ozwpan/ozhcd.c +++ b/drivers/staging/ozwpan/ozhcd.c @@ -26,21 +26,16 @@ */ #include <linux/platform_device.h> #include <linux/usb.h> -#include <linux/jiffies.h> #include <linux/slab.h> #include <linux/export.h> #include "linux/usb/hcd.h" #include <asm/unaligned.h> -#include "ozconfig.h" #include "ozusbif.h" #include "oztrace.h" #include "ozurbparanoia.h" -#include "ozevent.h" -/*------------------------------------------------------------------------------ - * Number of units of buffering to capture for an isochronous IN endpoint before - * allowing data to be indicated up. - */ -#define OZ_IN_BUFFERING_UNITS 50 + +#define OZ_HUB_DEBOUNCE_TIMEOUT 1500 + /* Name of our platform device. */ #define OZ_PLAT_DEV_NAME "ozwpan" @@ -50,6 +45,9 @@ /* Get endpoint object from the containing link. */ #define ep_from_link(__e) container_of((__e), struct oz_endpoint, link) +/*EP0 timeout before ep0 request is again added to TX queue. (13*8 = 98mSec) + */ +#define EP0_TIMEOUT_COUNTER 13 /*------------------------------------------------------------------------------ * Used to link urbs together and also store some status information for each * urb. @@ -61,7 +59,7 @@ struct oz_urb_link { struct oz_port *port; u8 req_id; u8 ep_num; - unsigned long submit_jiffies; + unsigned submit_counter; }; /* Holds state information about a USB endpoint. @@ -70,7 +68,8 @@ struct oz_endpoint { struct list_head urb_list; /* List of oz_urb_link items. */ struct list_head link; /* For isoc ep, links in to isoc lists of oz_port. */ - unsigned long last_jiffies; + struct timespec timestamp; + int credit2; int credit; int credit_ceiling; u8 ep_num; @@ -80,6 +79,7 @@ struct oz_endpoint { int in_ix; int out_ix; int buffered_units; + u8 max_buffer_units; unsigned flags; int start_frame; }; @@ -87,6 +87,13 @@ struct oz_endpoint { #define OZ_F_EP_BUFFERING 0x1 #define OZ_F_EP_HAVE_STREAM 0x2 + +/* Buffer_size. +Total size of buffer (in bytes) for the endpoint buffer for isochronous data, +and for stashing BULK or INT data if a URB is not available. +*/ +#define OZ_EP_BUFFER_SIZE_ISOC (1024*24) +#define OZ_EP_BUFFER_SIZE_INT (512) /* Holds state information about a USB interface. */ struct oz_interface { @@ -188,6 +195,7 @@ static DEFINE_SPINLOCK(g_tasklet_lock); static struct tasklet_struct g_urb_process_tasklet; static struct tasklet_struct g_urb_cancel_tasklet; static atomic_t g_pending_urbs = ATOMIC_INIT(0); +static atomic_t g_usb_frame_number = ATOMIC_INIT(0); static const struct hc_driver g_oz_hc_drv = { .description = g_hcd_name, .product_desc = "Ozmo Devices WPAN", @@ -236,9 +244,14 @@ static inline struct oz_hcd *oz_hcd_private(struct usb_hcd *hcd) static int oz_get_port_from_addr(struct oz_hcd *ozhcd, u8 bus_addr) { int i; - for (i = 0; i < OZ_NB_PORTS; i++) { - if (ozhcd->ports[i].bus_addr == bus_addr) - return i; + + if (0 != bus_addr) { + for (i = 0; i < OZ_NB_PORTS; i++) { + if (ozhcd->ports[i].bus_addr == bus_addr) + return i; + } + + return -1; } return ozhcd->conn_port; } @@ -346,12 +359,27 @@ struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb) * Context: softirq or process */ static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb, - int status, unsigned long submit_jiffies) + int status) { struct oz_hcd *ozhcd = oz_hcd_private(hcd); unsigned long irq_state; struct oz_urb_link *cancel_urbl = 0; spin_lock_irqsave(&g_tasklet_lock, irq_state); + + if (usb_pipeisoc(urb->pipe)) { + if (status < 0) { + int i; + urb->transfer_buffer_length = 0; + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = status; + } + } else { + /* ISOC checks transfer_buffer_length */ + urb->transfer_buffer_length = urb->actual_length; + } + } + oz_trace_urb_out(urb, status); usb_hcd_unlink_urb_from_ep(hcd, urb); /* Clear hcpriv which will prevent it being put in the cancel list * in the event that an attempt is made to cancel it. @@ -374,14 +402,7 @@ static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb, if (oz_forget_urb(urb)) { oz_trace("OZWPAN: ERROR Unknown URB %p\n", urb); } else { - static unsigned long last_time; atomic_dec(&g_pending_urbs); - oz_trace2(OZ_TRACE_URB, - "%lu: giveback_urb(%p,%x) %lu %lu pending:%d\n", - jiffies, urb, status, jiffies-submit_jiffies, - jiffies-last_time, atomic_read(&g_pending_urbs)); - last_time = jiffies; - oz_event_log(OZ_EVT_URB_DONE, 0, 0, urb, status); usb_hcd_giveback_urb(hcd, urb, status); } spin_lock(&g_tasklet_lock); @@ -396,7 +417,6 @@ static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb, */ static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep) { - oz_trace("oz_ep_free()\n"); if (port) { struct list_head list; struct oz_hcd *ozhcd = port->ozhcd; @@ -411,12 +431,47 @@ static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep) list_splice_tail(&list, &ozhcd->orphanage); spin_unlock_bh(&ozhcd->hcd_lock); } - oz_trace("Freeing endpoint memory\n"); kfree(ep); } /*------------------------------------------------------------------------------ * Context: softirq */ +void oz_complete_buffered_urb(struct oz_port *port, struct oz_endpoint *ep, + struct urb *urb) +{ + int data_len, available_space, copy_len; + + data_len = ep->buffer[ep->out_ix]; + if (data_len <= urb->transfer_buffer_length) + available_space = data_len; + else + available_space = urb->transfer_buffer_length; + + if (++ep->out_ix == ep->buffer_size) + ep->out_ix = 0; + copy_len = ep->buffer_size - ep->out_ix; + if (copy_len >= available_space) + copy_len = available_space; + memcpy(urb->transfer_buffer, &ep->buffer[ep->out_ix], copy_len); + + if (copy_len < available_space) { + memcpy((urb->transfer_buffer + copy_len), ep->buffer, + (available_space - copy_len)); + ep->out_ix = available_space - copy_len; + } else { + ep->out_ix += copy_len; + } + urb->actual_length = available_space; + if (ep->out_ix == ep->buffer_size) + ep->out_ix = 0; + + ep->buffered_units--; + oz_complete_urb(port->ozhcd->hcd, urb, 0); +} + +/*------------------------------------------------------------------------------ + * Context: softirq + */ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, struct urb *urb, u8 req_id) { @@ -430,7 +485,7 @@ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, urbl = oz_alloc_urb_link(); if (!urbl) return -ENOMEM; - urbl->submit_jiffies = jiffies; + urbl->submit_counter = 0; urbl->urb = urb; urbl->req_id = req_id; urbl->ep_num = ep_addr; @@ -444,25 +499,47 @@ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, if (urb->unlinked) { spin_unlock_bh(&port->ozhcd->hcd_lock); oz_trace("urb %p unlinked so complete immediately\n", urb); - oz_complete_urb(port->ozhcd->hcd, urb, 0, 0); + oz_complete_urb(port->ozhcd->hcd, urb, 0); oz_free_urb_link(urbl); return 0; } - if (in_dir) - ep = port->in_ep[ep_addr]; - else - ep = port->out_ep[ep_addr]; + if (in_dir) { + if (port->in_ep[ep_addr]) { + ep = port->in_ep[ep_addr]; + } else { + err = -EINVAL; + goto out; + } + } else { + if (port->out_ep[ep_addr]) { + ep = port->out_ep[ep_addr]; + } else { + err = -EINVAL; + goto out; + } + } + + /*For interrupt endpoint check for buffered data + * & complete urb + */ + if (((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + && ep->buffered_units > 0) { + oz_free_urb_link(urbl); + spin_unlock_bh(&port->ozhcd->hcd_lock); + oz_complete_buffered_urb(port, ep, urb); + return 0; + } + if (ep && port->hpd) { list_add_tail(&urbl->link, &ep->urb_list); if (!in_dir && ep_addr && (ep->credit < 0)) { - ep->last_jiffies = jiffies; + getrawmonotonic(&ep->timestamp); ep->credit = 0; - oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, - 0, 0, ep->credit); } } else { err = -EPIPE; } +out: spin_unlock_bh(&port->ozhcd->hcd_lock); if (err) oz_free_urb_link(urbl); @@ -532,6 +609,35 @@ static struct urb *oz_find_urb_by_id(struct oz_port *port, int ep_ix, return urb; } /*------------------------------------------------------------------------------ + * Finds an urbl given request it, then set submit_count to 1, thus heartbeat + * count this value up to EP0_TIMEOUT. + */ +void oz_hcd_mark_urb_submitted(void *hport, int ep_ix, u8 req_id) +{ + struct oz_port *port = (struct oz_port *)hport; + struct oz_hcd *ozhcd = port->ozhcd; + struct oz_urb_link *urbl = 0; + struct oz_endpoint *ep; + unsigned long irq_state; + unsigned found = 0; + spin_lock_bh(&ozhcd->hcd_lock); + spin_lock_irqsave(&g_tasklet_lock, irq_state); + ep = port->out_ep[ep_ix]; + if (ep) { + struct list_head *e; + list_for_each(e, &ep->urb_list) { + urbl = container_of(e, struct oz_urb_link, link); + if (urbl->req_id == req_id) { + urbl->submit_counter = 1; + found = 1; + break; + } + } + } + spin_unlock_irqrestore(&g_tasklet_lock, irq_state); + spin_unlock_bh(&ozhcd->hcd_lock); +} +/*------------------------------------------------------------------------------ * Pre-condition: Port lock must be held. * Context: softirq */ @@ -584,7 +690,8 @@ void *oz_hcd_pd_arrived(void *hpd) void *hport = 0; struct oz_hcd *ozhcd = 0; struct oz_endpoint *ep; - oz_trace("oz_hcd_pd_arrived()\n"); + static int n = OZ_NB_PORTS; + int j; ozhcd = oz_hcd_claim(); if (ozhcd == 0) return 0; @@ -595,32 +702,38 @@ void *oz_hcd_pd_arrived(void *hpd) spin_lock_bh(&ozhcd->hcd_lock); if (ozhcd->conn_port >= 0) { spin_unlock_bh(&ozhcd->hcd_lock); - oz_trace("conn_port >= 0\n"); goto out; } + j = n; for (i = 0; i < OZ_NB_PORTS; i++) { - struct oz_port *port = &ozhcd->ports[i]; + struct oz_port *port; + if (++j >= OZ_NB_PORTS) + j = 0; + port = &ozhcd->ports[j]; spin_lock(&port->port_lock); if ((port->flags & OZ_PORT_F_PRESENT) == 0) { oz_acquire_port(port, hpd); + port->bus_addr = 0; + port->config_num = 0; spin_unlock(&port->port_lock); break; } spin_unlock(&port->port_lock); } if (i < OZ_NB_PORTS) { - oz_trace("Setting conn_port = %d\n", i); - ozhcd->conn_port = i; + ozhcd->conn_port = j; /* Attach out endpoint 0. */ - ozhcd->ports[i].out_ep[0] = ep; + ozhcd->ports[j].out_ep[0] = ep; ep = 0; - hport = &ozhcd->ports[i]; + hport = &ozhcd->ports[j]; spin_unlock_bh(&ozhcd->hcd_lock); if (ozhcd->flags & OZ_HDC_F_SUSPENDED) { - oz_trace("Resuming root hub\n"); + oz_trace_msg(H, "usb_hcd_resume_root_hub()\n"); usb_hcd_resume_root_hub(ozhcd->hcd); } + n = j; + oz_trace_msg(H, "usb_hcd_poll_rh()\n"); usb_hcd_poll_rh_status(ozhcd->hcd); } else { spin_unlock_bh(&ozhcd->hcd_lock); @@ -644,9 +757,9 @@ void oz_hcd_pd_departed(void *hport) void *hpd; struct oz_endpoint *ep = 0; - oz_trace("oz_hcd_pd_departed()\n"); + oz_trace("%s:\n", __func__); if (port == 0) { - oz_trace("oz_hcd_pd_departed() port = 0\n"); + oz_trace("%s: port = 0\n", __func__); return; } ozhcd = port->ozhcd; @@ -657,7 +770,6 @@ void oz_hcd_pd_departed(void *hport) spin_lock_bh(&ozhcd->hcd_lock); if ((ozhcd->conn_port >= 0) && (port == &ozhcd->ports[ozhcd->conn_port])) { - oz_trace("Clearing conn_port\n"); ozhcd->conn_port = -1; } spin_lock(&port->port_lock); @@ -670,9 +782,10 @@ void oz_hcd_pd_departed(void *hport) hpd = port->hpd; port->hpd = 0; port->bus_addr = 0xff; + port->config_num = 0; port->flags &= ~(OZ_PORT_F_PRESENT | OZ_PORT_F_DYING); port->flags |= OZ_PORT_F_CHANGED; - port->status &= ~USB_PORT_STAT_CONNECTION; + port->status &= ~(USB_PORT_STAT_CONNECTION|USB_PORT_STAT_ENABLE); port->status |= (USB_PORT_STAT_C_CONNECTION << 16); /* If there is an endpont 0 then clear the pointer while we hold * the spinlock be we deallocate it after releasing the lock. @@ -684,6 +797,7 @@ void oz_hcd_pd_departed(void *hport) spin_unlock_bh(&port->port_lock); if (ep) oz_ep_free(port, ep); + oz_trace_msg(H, "usb_hcd_poll_rh_status()\n"); usb_hcd_poll_rh_status(ozhcd->hcd); oz_usb_put(hpd); } @@ -715,9 +829,6 @@ void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, u8 *desc, struct urb *urb; int err = 0; - oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, 0, status); - oz_trace("oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n", - length, offset, total_size); urb = oz_find_urb_by_id(port, 0, req_id); if (!urb) return; @@ -749,53 +860,8 @@ void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, u8 *desc, } } urb->actual_length = total_size; - oz_complete_urb(port->ozhcd->hcd, urb, 0, 0); -} -/*------------------------------------------------------------------------------ - * Context: softirq - */ -#ifdef WANT_TRACE -static void oz_display_conf_type(u8 t) -{ - switch (t) { - case USB_REQ_GET_STATUS: - oz_trace("USB_REQ_GET_STATUS - cnf\n"); - break; - case USB_REQ_CLEAR_FEATURE: - oz_trace("USB_REQ_CLEAR_FEATURE - cnf\n"); - break; - case USB_REQ_SET_FEATURE: - oz_trace("USB_REQ_SET_FEATURE - cnf\n"); - break; - case USB_REQ_SET_ADDRESS: - oz_trace("USB_REQ_SET_ADDRESS - cnf\n"); - break; - case USB_REQ_GET_DESCRIPTOR: - oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n"); - break; - case USB_REQ_SET_DESCRIPTOR: - oz_trace("USB_REQ_SET_DESCRIPTOR - cnf\n"); - break; - case USB_REQ_GET_CONFIGURATION: - oz_trace("USB_REQ_GET_CONFIGURATION - cnf\n"); - break; - case USB_REQ_SET_CONFIGURATION: - oz_trace("USB_REQ_SET_CONFIGURATION - cnf\n"); - break; - case USB_REQ_GET_INTERFACE: - oz_trace("USB_REQ_GET_INTERFACE - cnf\n"); - break; - case USB_REQ_SET_INTERFACE: - oz_trace("USB_REQ_SET_INTERFACE - cnf\n"); - break; - case USB_REQ_SYNCH_FRAME: - oz_trace("USB_REQ_SYNCH_FRAME - cnf\n"); - break; - } + oz_complete_urb(port->ozhcd->hcd, urb, 0); } -#else -#define oz_display_conf_type(__x) -#endif /* WANT_TRACE */ /*------------------------------------------------------------------------------ * Context: softirq */ @@ -814,7 +880,7 @@ static void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb, } else { rc = -ENOMEM; } - oz_complete_urb(hcd, urb, rc, 0); + oz_complete_urb(hcd, urb, rc); } /*------------------------------------------------------------------------------ * Context: softirq @@ -825,21 +891,24 @@ static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb, struct usb_hcd *hcd = port->ozhcd->hcd; int rc = 0; if (rcode == 0) { - struct usb_host_config *config; - struct usb_host_interface *intf; - oz_trace("Set interface %d alt %d\n", if_num, alt); - oz_clean_endpoints_for_interface(hcd, port, if_num); - config = &urb->dev->config[port->config_num-1]; - intf = &config->intf_cache[if_num]->altsetting[alt]; - if (oz_build_endpoints_for_interface(hcd, port, intf, - GFP_ATOMIC)) + if (port->config_num > 0) { + struct usb_host_config *config; + struct usb_host_interface *intf; + + oz_clean_endpoints_for_interface(hcd, port, if_num); + config = &urb->dev->config[port->config_num-1]; + intf = &config->intf_cache[if_num]->altsetting[alt]; + if (oz_build_endpoints_for_interface(hcd, port, intf, + GFP_ATOMIC)) + rc = -ENOMEM; + else + port->iface[if_num].alt = alt; + } else rc = -ENOMEM; - else - port->iface[if_num].alt = alt; } else { rc = -ENOMEM; } - oz_complete_urb(hcd, urb, rc, 0); + oz_complete_urb(hcd, urb, rc); } /*------------------------------------------------------------------------------ * Context: softirq @@ -854,11 +923,9 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data, unsigned windex; unsigned wvalue; - oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, 0, rcode); - oz_trace("oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len); urb = oz_find_urb_by_id(port, 0, req_id); if (!urb) { - oz_trace("URB not found\n"); + oz_trace("URB not found: %p\n", urb); return; } setup = (struct usb_ctrlrequest *)urb->setup_packet; @@ -866,7 +933,6 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data, wvalue = le16_to_cpu(setup->wValue); if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { /* Standard requests */ - oz_display_conf_type(setup->bRequest); switch (setup->bRequest) { case USB_REQ_SET_CONFIGURATION: oz_hcd_complete_set_config(port, urb, rcode, @@ -877,20 +943,20 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data, (u8)windex, (u8)wvalue); break; default: - oz_complete_urb(hcd, urb, 0, 0); + oz_complete_urb(hcd, urb, 0); } } else { int copy_len; - oz_trace("VENDOR-CLASS - cnf\n"); - if (data_len <= urb->transfer_buffer_length) - copy_len = data_len; - else - copy_len = urb->transfer_buffer_length; - if (copy_len) + if (data_len) { + if (data_len <= urb->transfer_buffer_length) + copy_len = data_len; + else + copy_len = urb->transfer_buffer_length; memcpy(urb->transfer_buffer, data, copy_len); - urb->actual_length = copy_len; - oz_complete_urb(hcd, urb, 0, 0); + urb->actual_length = copy_len; + } + oz_complete_urb(hcd, urb, 0); } } /*------------------------------------------------------------------------------ @@ -906,7 +972,10 @@ static int oz_hcd_buffer_data(struct oz_endpoint *ep, u8 *data, int data_len) if (space < 0) space += ep->buffer_size; if (space < (data_len+1)) { - oz_trace("Buffer full\n"); + oz_trace_msg(I, "EP:%02X u:%d FULL len:%d spc:%d\n", + ep->ep_num | USB_DIR_IN, + ep->buffered_units, + data_len, space); return -1; } ep->buffer[ep->in_ix] = (u8)data_len; @@ -959,12 +1028,35 @@ void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len) copy_len = urb->transfer_buffer_length; memcpy(urb->transfer_buffer, data, copy_len); urb->actual_length = copy_len; - oz_complete_urb(port->ozhcd->hcd, urb, 0, 0); + oz_complete_urb(port->ozhcd->hcd, urb, 0); return; + } else { + oz_hcd_buffer_data(ep, data, data_len); } break; case USB_ENDPOINT_XFER_ISOC: - oz_hcd_buffer_data(ep, data, data_len); + if (oz_hcd_buffer_data(ep, data, data_len) != 0) { + int len; + int copy_len; + while (ep->buffered_units > ep->max_buffer_units) { + len = ep->buffer[ep->out_ix]; + if (++ep->out_ix == ep->buffer_size) + ep->out_ix = 0; + copy_len = ep->buffer_size - ep->out_ix; + if (copy_len > len) + copy_len = len; + if (copy_len < len) + ep->out_ix = len - copy_len; + else + ep->out_ix += copy_len; + + if (ep->out_ix == ep->buffer_size) + ep->out_ix = 0; + + ep->buffered_units--; + } + ep->flags |= OZ_F_EP_BUFFERING; + } break; } done: @@ -975,7 +1067,7 @@ done: */ static inline int oz_usb_get_frame_number(void) { - return jiffies_to_msecs(get_jiffies_64()); + return atomic_inc_return(&g_usb_frame_number); } /*------------------------------------------------------------------------------ * Context: softirq @@ -991,7 +1083,8 @@ int oz_hcd_heartbeat(void *hport) struct list_head *n; struct urb *urb; struct oz_endpoint *ep; - unsigned long now = jiffies; + struct timespec ts, delta; + getrawmonotonic(&ts); INIT_LIST_HEAD(&xfr_list); /* Check the OUT isoc endpoints to see if any URB data can be sent. */ @@ -1000,20 +1093,20 @@ int oz_hcd_heartbeat(void *hport) ep = ep_from_link(e); if (ep->credit < 0) continue; - ep->credit += (now - ep->last_jiffies); + delta = timespec_sub(ts, ep->timestamp); + ep->credit += div64_u64(timespec_to_ns(&delta), NSEC_PER_MSEC); if (ep->credit > ep->credit_ceiling) ep->credit = ep->credit_ceiling; - oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit); - ep->last_jiffies = now; + ep->timestamp = ts; while (ep->credit && !list_empty(&ep->urb_list)) { urbl = list_first_entry(&ep->urb_list, struct oz_urb_link, link); urb = urbl->urb; - if (ep->credit < urb->number_of_packets) + if ((ep->credit + 1) < urb->number_of_packets) break; ep->credit -= urb->number_of_packets; - oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, - ep->credit); + if (ep->credit < 0) + ep->credit = 0; list_del(&urbl->link); list_add_tail(&urbl->link, &xfr_list); } @@ -1022,40 +1115,34 @@ int oz_hcd_heartbeat(void *hport) /* Send to PD and complete URBs. */ list_for_each_safe(e, n, &xfr_list) { - unsigned long t; urbl = container_of(e, struct oz_urb_link, link); urb = urbl->urb; - t = urbl->submit_jiffies; list_del_init(e); urb->error_count = 0; urb->start_frame = oz_usb_get_frame_number(); oz_usb_send_isoc(port->hpd, urbl->ep_num, urb); oz_free_urb_link(urbl); - oz_complete_urb(port->ozhcd->hcd, urb, 0, t); + oz_complete_urb(port->ozhcd->hcd, urb, 0); } /* Check the IN isoc endpoints to see if any URBs can be completed. */ spin_lock_bh(&ozhcd->hcd_lock); list_for_each(e, &port->isoc_in_ep) { struct oz_endpoint *ep = ep_from_link(e); + if (ep->flags & OZ_F_EP_BUFFERING) { - if (ep->buffered_units * OZ_IN_BUFFERING_UNITS) { + if (ep->buffered_units >= ep->max_buffer_units) { ep->flags &= ~OZ_F_EP_BUFFERING; ep->credit = 0; - oz_event_log(OZ_EVT_EP_CREDIT, - ep->ep_num | USB_DIR_IN, - 0, 0, ep->credit); - ep->last_jiffies = now; + ep->credit2 = 0; + ep->timestamp = ts; ep->start_frame = 0; - oz_event_log(OZ_EVT_EP_BUFFERING, - ep->ep_num | USB_DIR_IN, 0, 0, 0); } continue; } - ep->credit += (now - ep->last_jiffies); - oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN, - 0, 0, ep->credit); - ep->last_jiffies = now; + delta = timespec_sub(ts, ep->timestamp); + ep->credit += div64_u64(timespec_to_ns(&delta)+5000, NSEC_PER_MSEC); + ep->timestamp = ts; while (!list_empty(&ep->urb_list)) { struct oz_urb_link *urbl = list_first_entry(&ep->urb_list, @@ -1064,8 +1151,6 @@ int oz_hcd_heartbeat(void *hport) int len = 0; int copy_len; int i; - if (ep->credit < urb->number_of_packets) - break; if (ep->buffered_units < urb->number_of_packets) break; urb->actual_length = 0; @@ -1099,8 +1184,29 @@ int oz_hcd_heartbeat(void *hport) list_del(&urbl->link); list_add_tail(&urbl->link, &xfr_list); ep->credit -= urb->number_of_packets; - oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN, - 0, 0, ep->credit); + ep->credit2 += urb->number_of_packets; + } + if (ep->buffered_units == 0) { + oz_trace_msg(I, "EP:%02X Buffer under run\n", + ep->ep_num | USB_DIR_IN); + ep->flags |= OZ_F_EP_BUFFERING; + continue; + } + if (ep->credit2 >= 1000) + { + static int buffered_units=-1; + static int max_buffer_units=-1; + { + int diff = ep->buffered_units - buffered_units; + oz_trace_msg(I, "u:%d o:%04d b:%d\n", + ep->credit2, + ep->credit2 + diff, + ep->buffered_units); + + buffered_units = ep->buffered_units; + max_buffer_units = ep->max_buffer_units; + } + ep->credit2 = 0; } } if (!list_empty(&port->isoc_out_ep) || !list_empty(&port->isoc_in_ep)) @@ -1113,7 +1219,7 @@ int oz_hcd_heartbeat(void *hport) urb = urbl->urb; list_del_init(e); oz_free_urb_link(urbl); - oz_complete_urb(port->ozhcd->hcd, urb, 0, 0); + oz_complete_urb(port->ozhcd->hcd, urb, 0); } /* Check if there are any ep0 requests that have timed out. * If so resent to PD. @@ -1125,12 +1231,15 @@ int oz_hcd_heartbeat(void *hport) spin_lock_bh(&ozhcd->hcd_lock); list_for_each_safe(e, n, &ep->urb_list) { urbl = container_of(e, struct oz_urb_link, link); - if (time_after(now, urbl->submit_jiffies+HZ/2)) { - oz_trace("%ld: Request 0x%p timeout\n", - now, urbl->urb); - urbl->submit_jiffies = now; + if (urbl->submit_counter > EP0_TIMEOUT_COUNTER) { + oz_trace_msg(M, "URB:%08X timeout %02X\n", + (unsigned int)((uintptr_t)urbl->urb), + urbl->req_id); list_del(e); list_add_tail(e, &xfr_list); + urbl->submit_counter = 0; + } else if (urbl->submit_counter) { + urbl->submit_counter++; } } if (!list_empty(&ep->urb_list)) @@ -1140,7 +1249,7 @@ int oz_hcd_heartbeat(void *hport) while (e != &xfr_list) { urbl = container_of(e, struct oz_urb_link, link); e = e->next; - oz_trace("Resending request to PD.\n"); + oz_trace_msg(M, "Resending request to PD.\n"); oz_process_ep0_urb(ozhcd, urbl->urb, GFP_ATOMIC); oz_free_urb_link(urbl); } @@ -1156,9 +1265,17 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd, { struct oz_hcd *ozhcd = port->ozhcd; int i; - int if_ix = intf->desc.bInterfaceNumber; + int if_ix; int request_heartbeat = 0; + + if (intf == NULL) + return -ENOMEM; + + if_ix = intf->desc.bInterfaceNumber; oz_trace("interface[%d] = %p\n", if_ix, intf); + if (if_ix >= port->num_iface || port->iface == NULL) + return -ENOMEM; + for (i = 0; i < intf->desc.bNumEndpoints; i++) { struct usb_host_endpoint *hep = &intf->endpoint[i]; u8 ep_addr = hep->desc.bEndpointAddress; @@ -1166,11 +1283,16 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd, struct oz_endpoint *ep; int buffer_size = 0; - oz_trace("%d bEndpointAddress = %x\n", i, ep_addr); - if ((ep_addr & USB_ENDPOINT_DIR_MASK) && - ((hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC)) { - buffer_size = 24*1024; + if (ep_addr & USB_ENDPOINT_DIR_MASK) { + switch (hep->desc.bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_ISOC: + buffer_size = OZ_EP_BUFFER_SIZE_ISOC; + break; + case USB_ENDPOINT_XFER_INT: + buffer_size = OZ_EP_BUFFER_SIZE_INT; + break; + } } ep = oz_ep_alloc(mem_flags, buffer_size); @@ -1182,13 +1304,11 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd, ep->ep_num = ep_num; if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC) { - oz_trace("wMaxPacketSize = %d\n", - hep->desc.wMaxPacketSize); ep->credit_ceiling = 200; if (ep_addr & USB_ENDPOINT_DIR_MASK) { + ep->max_buffer_units = + oz_get_up_max_buffer_units(port->hpd); ep->flags |= OZ_F_EP_BUFFERING; - oz_event_log(OZ_EVT_EP_BUFFERING, - ep->ep_num | USB_DIR_IN, 1, 0, 0); } else { ep->flags |= OZ_F_EP_HAVE_STREAM; if (oz_usb_stream_create(port->hpd, ep_num)) @@ -1314,7 +1434,6 @@ static void oz_clean_endpoints_for_config(struct usb_hcd *hcd, oz_clean_endpoints_for_interface(hcd, port, i); spin_lock_bh(&ozhcd->hcd_lock); if (port->iface) { - oz_trace("Freeing interfaces object.\n"); kfree(port->iface); port->iface = 0; } @@ -1353,8 +1472,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, int port_ix = -1; struct oz_port *port = 0; - oz_trace2(OZ_TRACE_URB, "%lu: oz_process_ep0_urb(%p)\n", jiffies, urb); - port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum); + port_ix = oz_get_port_from_addr(ozhcd, (usb_pipedevice(urb->pipe))); if (port_ix < 0) { rc = -EPIPE; goto out; @@ -1374,17 +1492,10 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, windex = le16_to_cpu(setup->wIndex); wvalue = le16_to_cpu(setup->wValue); wlength = le16_to_cpu(setup->wLength); - oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequestType = %x\n", - setup->bRequestType); - oz_trace2(OZ_TRACE_CTRL_DETAIL, "bRequest = %x\n", setup->bRequest); - oz_trace2(OZ_TRACE_CTRL_DETAIL, "wValue = %x\n", wvalue); - oz_trace2(OZ_TRACE_CTRL_DETAIL, "wIndex = %x\n", windex); - oz_trace2(OZ_TRACE_CTRL_DETAIL, "wLength = %x\n", wlength); req_id = port->next_req_id++; hpd = oz_claim_hpd(port); if (hpd == 0) { - oz_trace("Cannot claim port\n"); rc = -EPIPE; goto out; } @@ -1394,34 +1505,23 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, */ switch (setup->bRequest) { case USB_REQ_GET_DESCRIPTOR: - oz_trace("USB_REQ_GET_DESCRIPTOR - req\n"); break; case USB_REQ_SET_ADDRESS: - oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, - 0, 0, setup->bRequestType); - oz_trace("USB_REQ_SET_ADDRESS - req\n"); - oz_trace("Port %d address is 0x%x\n", ozhcd->conn_port, - (u8)le16_to_cpu(setup->wValue)); spin_lock_bh(&ozhcd->hcd_lock); if (ozhcd->conn_port >= 0) { ozhcd->ports[ozhcd->conn_port].bus_addr = (u8)le16_to_cpu(setup->wValue); - oz_trace("Clearing conn_port\n"); ozhcd->conn_port = -1; } spin_unlock_bh(&ozhcd->hcd_lock); complete = 1; break; case USB_REQ_SET_CONFIGURATION: - oz_trace("USB_REQ_SET_CONFIGURATION - req\n"); break; case USB_REQ_GET_CONFIGURATION: - /* We short curcuit this case and reply directly since + /* We short circuit this case and reply directly since * we have the selected configuration number cached. */ - oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0, - setup->bRequestType); - oz_trace("USB_REQ_GET_CONFIGURATION - reply now\n"); if (urb->transfer_buffer_length >= 1) { urb->actual_length = 1; *((u8 *)urb->transfer_buffer) = @@ -1432,25 +1532,19 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, } break; case USB_REQ_GET_INTERFACE: - /* We short curcuit this case and reply directly since + /* We short circuit this case and reply directly since * we have the selected interface alternative cached. */ - oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0, - setup->bRequestType); - oz_trace("USB_REQ_GET_INTERFACE - reply now\n"); if (urb->transfer_buffer_length >= 1) { urb->actual_length = 1; *((u8 *)urb->transfer_buffer) = port->iface[(u8)windex].alt; - oz_trace("interface = %d alt = %d\n", - windex, port->iface[(u8)windex].alt); complete = 1; } else { rc = -EPIPE; } break; case USB_REQ_SET_INTERFACE: - oz_trace("USB_REQ_SET_INTERFACE - req\n"); break; } } @@ -1458,12 +1552,13 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, int data_len = 0; if ((setup->bRequestType & USB_DIR_IN) == 0) data_len = wlength; + urb->actual_length = data_len; if (oz_usb_control_req(port->hpd, req_id, setup, urb->transfer_buffer, data_len)) { rc = -ENOMEM; } else { /* Note: we are queuing the request after we have - * submitted it to be tranmitted. If the request were + * submitted it to be transmitted. If the request were * to complete before we queued it then it would not * be found in the queue. It seems impossible for * this to happen but if it did the request would @@ -1480,8 +1575,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, oz_usb_put(hpd); out: if (rc || complete) { - oz_trace("Completing request locally\n"); - oz_complete_urb(ozhcd->hcd, urb, rc, 0); + oz_complete_urb(ozhcd->hcd, urb, rc); } else { oz_usb_request_heartbeat(port->hpd); } @@ -1506,14 +1600,14 @@ static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb) /* Check if there is a device at the port - refuse if not. */ if ((port->flags & OZ_PORT_F_PRESENT) == 0) - return -EPIPE; + return -ENODEV; ep_addr = usb_pipeendpoint(urb->pipe); if (ep_addr) { /* If the request is not for EP0 then queue it. */ if (oz_enqueue_ep_urb(port, ep_addr, usb_pipein(urb->pipe), urb, 0)) - rc = -EPIPE; + rc = -ENOENT; } else { oz_process_ep0_urb(ozhcd, urb, GFP_ATOMIC); } @@ -1545,7 +1639,7 @@ static void oz_urb_process_tasklet(unsigned long unused) oz_free_urb_link(urbl); rc = oz_urb_process(ozhcd, urb); if (rc) - oz_complete_urb(ozhcd->hcd, urb, rc, 0); + oz_complete_urb(ozhcd->hcd, urb, rc); spin_lock_irqsave(&g_tasklet_lock, irq_state); } spin_unlock_irqrestore(&g_tasklet_lock, irq_state); @@ -1568,12 +1662,12 @@ static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb) unsigned long irq_state; u8 ix; if (port == 0) { - oz_trace("ERRORERROR: oz_urb_cancel(%p) port is null\n", urb); + oz_trace("%s: urb=%p port is null\n", __func__, urb); return; } ozhcd = port->ozhcd; if (ozhcd == 0) { - oz_trace("ERRORERROR: oz_urb_cancel(%p) ozhcd is null\n", urb); + oz_trace("%s: urb=%p ozhcd is null\n", __func__, urb); return; } @@ -1598,7 +1692,7 @@ static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb) urbl = container_of(e, struct oz_urb_link, link); if (urbl->urb == urb) { list_del(e); - oz_trace("Found urb in orphanage\n"); + oz_trace("Found urb in orphanage urb=%p\n", urb); goto out; } } @@ -1614,7 +1708,7 @@ out2: if (urbl) { urb->actual_length = 0; oz_free_urb_link(urbl); - oz_complete_urb(ozhcd->hcd, urb, -EPIPE, 0); + oz_complete_urb(ozhcd->hcd, urb, -ENOENT); } } /*------------------------------------------------------------------------------ @@ -1654,7 +1748,7 @@ static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status) urbl = list_first_entry(&ozhcd->orphanage, struct oz_urb_link, link); list_del(&urbl->link); - oz_complete_urb(ozhcd->hcd, urbl->urb, status, 0); + oz_complete_urb(ozhcd->hcd, urbl->urb, status); oz_free_urb_link(urbl); } } @@ -1664,7 +1758,6 @@ static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status) */ static int oz_hcd_start(struct usb_hcd *hcd) { - oz_trace("oz_hcd_start()\n"); hcd->power_budget = 200; hcd->state = HC_STATE_RUNNING; hcd->uses_new_polling = 1; @@ -1675,29 +1768,15 @@ static int oz_hcd_start(struct usb_hcd *hcd) */ static void oz_hcd_stop(struct usb_hcd *hcd) { - oz_trace("oz_hcd_stop()\n"); + oz_trace("%s:\n", __func__); } /*------------------------------------------------------------------------------ * Context: unknown */ static void oz_hcd_shutdown(struct usb_hcd *hcd) { - oz_trace("oz_hcd_shutdown()\n"); -} -/*------------------------------------------------------------------------------ - * Context: any - */ -#ifdef WANT_EVENT_TRACE -static u8 oz_get_irq_ctx(void) -{ - u8 irq_info = 0; - if (in_interrupt()) - irq_info |= 1; - if (in_irq()) - irq_info |= 2; - return irq_info; + oz_trace("%s:\n", __func__); } -#endif /* WANT_EVENT_TRACE */ /*------------------------------------------------------------------------------ * Called to queue an urb for the device. * This function should return a non-zero error code if it fails the urb but @@ -1713,30 +1792,24 @@ static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, struct oz_port *port; unsigned long irq_state; struct oz_urb_link *urbl; - oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_enqueue(%p)\n", - jiffies, urb); - oz_event_log(OZ_EVT_URB_SUBMIT, oz_get_irq_ctx(), - (u16)urb->number_of_packets, urb, urb->pipe); if (unlikely(ozhcd == 0)) { - oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not ozhcd.\n", - jiffies, urb); - return -EPIPE; + oz_trace("Refused urb(%p) not ozhcd.\n", urb); + return -ENODEV; } if (unlikely(hcd->state != HC_STATE_RUNNING)) { - oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not running.\n", - jiffies, urb); - return -EPIPE; + oz_trace("Refused urb(%p) not running.\n", urb); + return -ENODEV; } - port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum); + port_ix = oz_get_port_from_addr(ozhcd, (usb_pipedevice(urb->pipe))); if (port_ix < 0) - return -EPIPE; + return -ENODEV; port = &ozhcd->ports[port_ix]; if (port == 0) - return -EPIPE; + return -ENODEV; if ((port->flags & OZ_PORT_F_PRESENT) == 0) { oz_trace("Refusing URB port_ix = %d devnum = %d\n", port_ix, urb->dev->devnum); - return -EPIPE; + return -ENODEV; } urb->hcpriv = port; /* Put request in queue for processing by tasklet. @@ -1746,6 +1819,7 @@ static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, return -ENOMEM; urbl->urb = urb; spin_lock_irqsave(&g_tasklet_lock, irq_state); + oz_trace_urb_in(urb); rc = usb_hcd_link_urb_to_ep(hcd, urb); if (unlikely(rc)) { spin_unlock_irqrestore(&g_tasklet_lock, irq_state); @@ -1773,13 +1847,10 @@ static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep, if (urbl->urb == urb) { list_del_init(e); if (usb_pipeisoc(urb->pipe)) { + oz_trace_msg(M, "oz_remove_urb:%p\n", urb); ep->credit -= urb->number_of_packets; if (ep->credit < 0) ep->credit = 0; - oz_event_log(OZ_EVT_EP_CREDIT, - usb_pipein(urb->pipe) ? - (ep->ep_num | USB_DIR_IN) : ep->ep_num, - 0, 0, ep->credit); } return urbl; } @@ -1796,7 +1867,7 @@ static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) struct oz_urb_link *urbl = 0; int rc; unsigned long irq_state; - oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_dequeue(%p)\n", jiffies, urb); + urbl = oz_alloc_urb_link(); if (unlikely(urbl == 0)) return -ENOMEM; @@ -1832,7 +1903,7 @@ static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static void oz_hcd_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { - oz_trace("oz_hcd_endpoint_disable\n"); + oz_trace("%s:\n", __func__); } /*------------------------------------------------------------------------------ * Context: unknown @@ -1840,14 +1911,13 @@ static void oz_hcd_endpoint_disable(struct usb_hcd *hcd, static void oz_hcd_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { - oz_trace("oz_hcd_endpoint_reset\n"); + oz_trace("%s:\n", __func__); } /*------------------------------------------------------------------------------ * Context: unknown */ static int oz_hcd_get_frame_number(struct usb_hcd *hcd) { - oz_trace("oz_hcd_get_frame_number\n"); return oz_usb_get_frame_number(); } /*------------------------------------------------------------------------------ @@ -1860,19 +1930,24 @@ static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf) struct oz_hcd *ozhcd = oz_hcd_private(hcd); int i; - oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_status_data()\n"); buf[0] = 0; - + buf[1] = 0; spin_lock_bh(&ozhcd->hcd_lock); for (i = 0; i < OZ_NB_PORTS; i++) { if (ozhcd->ports[i].flags & OZ_PORT_F_CHANGED) { - oz_trace2(OZ_TRACE_HUB, "Port %d changed\n", i); - ozhcd->ports[i].flags &= ~OZ_PORT_F_CHANGED; - buf[0] |= 1<<(i+1); + if (i < 7) + buf[0] |= 1<<(i+1); + else + buf[1] |= 1<<(i-7); } } + oz_trace_msg(H, "HUBSTS : %02X%02X\n", + buf[1], buf[0]); spin_unlock_bh(&ozhcd->hcd_lock); - return buf[0] ? 1 : 0; + if (buf[1] != 0 || buf[0] != 0) + return 2; + else + return 1; } /*------------------------------------------------------------------------------ * Context: process @@ -1880,7 +1955,6 @@ static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf) static void oz_get_hub_descriptor(struct usb_hcd *hcd, struct usb_hub_descriptor *desc) { - oz_trace2(OZ_TRACE_HUB, "GetHubDescriptor\n"); memset(desc, 0, sizeof(*desc)); desc->bDescriptorType = 0x29; desc->bDescLength = 9; @@ -1899,59 +1973,59 @@ static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex) struct oz_hcd *ozhcd = oz_hcd_private(hcd); unsigned set_bits = 0; unsigned clear_bits = 0; - oz_trace2(OZ_TRACE_HUB, "SetPortFeature\n"); + if ((port_id < 1) || (port_id > OZ_NB_PORTS)) - return -EPIPE; + return -ENODEV; port = &ozhcd->ports[port_id-1]; switch (wvalue) { case USB_PORT_FEAT_CONNECTION: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n"); + oz_trace("USB_PORT_FEAT_CONNECTION\n"); break; case USB_PORT_FEAT_ENABLE: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n"); + oz_trace("USB_PORT_FEAT_ENABLE\n"); break; case USB_PORT_FEAT_SUSPEND: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n"); + oz_trace("USB_PORT_FEAT_SUSPEND\n"); break; case USB_PORT_FEAT_OVER_CURRENT: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n"); + oz_trace("USB_PORT_FEAT_OVER_CURRENT\n"); break; case USB_PORT_FEAT_RESET: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n"); + oz_trace("USB_PORT_FEAT_RESET\n"); set_bits = USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET<<16); clear_bits = USB_PORT_STAT_RESET; ozhcd->ports[port_id-1].bus_addr = 0; break; case USB_PORT_FEAT_POWER: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n"); + oz_trace("USB_PORT_FEAT_POWER\n"); set_bits |= USB_PORT_STAT_POWER; break; case USB_PORT_FEAT_LOWSPEED: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n"); + oz_trace("USB_PORT_FEAT_LOWSPEED\n"); break; case USB_PORT_FEAT_C_CONNECTION: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n"); + oz_trace("USB_PORT_FEAT_C_CONNECTION\n"); break; case USB_PORT_FEAT_C_ENABLE: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n"); + oz_trace("USB_PORT_FEAT_C_ENABLE\n"); break; case USB_PORT_FEAT_C_SUSPEND: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n"); + oz_trace("USB_PORT_FEAT_C_SUSPEND\n"); break; case USB_PORT_FEAT_C_OVER_CURRENT: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n"); + oz_trace("USB_PORT_FEAT_C_OVER_CURRENT\n"); break; case USB_PORT_FEAT_C_RESET: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n"); + oz_trace("USB_PORT_FEAT_C_RESET\n"); break; case USB_PORT_FEAT_TEST: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n"); + oz_trace("USB_PORT_FEAT_TEST\n"); break; case USB_PORT_FEAT_INDICATOR: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n"); + oz_trace("USB_PORT_FEAT_INDICATOR\n"); break; default: - oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue); + oz_trace("Other %d\n", wvalue); break; } if (set_bits || clear_bits) { @@ -1960,8 +2034,9 @@ static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex) port->status |= set_bits; spin_unlock_bh(&port->port_lock); } - oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id, - port->status); + + oz_trace_msg(H, "Port[%d]: %08X\n", port_id, + ozhcd->ports[port_id-1].status); return err; } /*------------------------------------------------------------------------------ @@ -1974,60 +2049,60 @@ static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex) u8 port_id = (u8)windex; struct oz_hcd *ozhcd = oz_hcd_private(hcd); unsigned clear_bits = 0; - oz_trace2(OZ_TRACE_HUB, "ClearPortFeature\n"); + if ((port_id < 1) || (port_id > OZ_NB_PORTS)) - return -EPIPE; + return -ENODEV; port = &ozhcd->ports[port_id-1]; switch (wvalue) { case USB_PORT_FEAT_CONNECTION: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_CONNECTION\n"); + oz_trace("USB_PORT_FEAT_CONNECTION\n"); break; case USB_PORT_FEAT_ENABLE: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n"); + oz_trace("USB_PORT_FEAT_ENABLE\n"); clear_bits = USB_PORT_STAT_ENABLE; break; case USB_PORT_FEAT_SUSPEND: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n"); + oz_trace("USB_PORT_FEAT_SUSPEND\n"); break; case USB_PORT_FEAT_OVER_CURRENT: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n"); + oz_trace("USB_PORT_FEAT_OVER_CURRENT\n"); break; case USB_PORT_FEAT_RESET: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n"); + oz_trace("USB_PORT_FEAT_RESET\n"); break; case USB_PORT_FEAT_POWER: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n"); + oz_trace("USB_PORT_FEAT_POWER\n"); clear_bits |= USB_PORT_STAT_POWER; break; case USB_PORT_FEAT_LOWSPEED: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_LOWSPEED\n"); + oz_trace("USB_PORT_FEAT_LOWSPEED\n"); break; case USB_PORT_FEAT_C_CONNECTION: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n"); + oz_trace("USB_PORT_FEAT_C_CONNECTION\n"); clear_bits = (USB_PORT_STAT_C_CONNECTION << 16); break; case USB_PORT_FEAT_C_ENABLE: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_ENABLE\n"); + oz_trace("USB_PORT_FEAT_C_ENABLE\n"); clear_bits = (USB_PORT_STAT_C_ENABLE << 16); break; case USB_PORT_FEAT_C_SUSPEND: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_SUSPEND\n"); + oz_trace("USB_PORT_FEAT_C_SUSPEND\n"); break; case USB_PORT_FEAT_C_OVER_CURRENT: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n"); + oz_trace("USB_PORT_FEAT_C_OVER_CURRENT\n"); break; case USB_PORT_FEAT_C_RESET: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_RESET\n"); + oz_trace("USB_PORT_FEAT_C_RESET\n"); clear_bits = (USB_PORT_FEAT_C_RESET << 16); break; case USB_PORT_FEAT_TEST: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n"); + oz_trace("USB_PORT_FEAT_TEST\n"); break; case USB_PORT_FEAT_INDICATOR: - oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n"); + oz_trace("USB_PORT_FEAT_INDICATOR\n"); break; default: - oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue); + oz_trace("Other %d\n", wvalue); break; } if (clear_bits) { @@ -2035,7 +2110,8 @@ static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex) port->status &= ~clear_bits; spin_unlock_bh(&port->port_lock); } - oz_trace2(OZ_TRACE_HUB, "Port[%d] status = 0x%x\n", port_id, + + oz_trace_msg(H, "Port[%d]: %08X\n", port_id, ozhcd->ports[port_id-1].status); return err; } @@ -2047,12 +2123,12 @@ static int oz_get_port_status(struct usb_hcd *hcd, u16 windex, char *buf) struct oz_hcd *ozhcd; u32 status = 0; if ((windex < 1) || (windex > OZ_NB_PORTS)) - return -EPIPE; + return -ENODEV; ozhcd = oz_hcd_private(hcd); - oz_trace2(OZ_TRACE_HUB, "GetPortStatus windex = %d\n", windex); + ozhcd->ports[windex-1].flags &= ~OZ_PORT_F_CHANGED; status = ozhcd->ports[windex-1].status; put_unaligned(cpu_to_le32(status), (__le32 *)buf); - oz_trace2(OZ_TRACE_HUB, "Port[%d] status = %x\n", windex, status); + oz_trace_msg(H, "Port[%d]: %08X\n", windex, status); return 0; } /*------------------------------------------------------------------------------ @@ -2062,10 +2138,13 @@ static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue, u16 windex, char *buf, u16 wlength) { int err = 0; - oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_control()\n"); + + oz_trace_msg(H, "HUBCTL: %04X %04X %04X %04X\n", + req_type, wvalue, windex, wlength); + switch (req_type) { case ClearHubFeature: - oz_trace2(OZ_TRACE_HUB, "ClearHubFeature: %d\n", req_type); + oz_trace("ClearHubFeature: %d\n", req_type); break; case ClearPortFeature: err = oz_clear_port_feature(hcd, wvalue, windex); @@ -2074,7 +2153,7 @@ static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue, oz_get_hub_descriptor(hcd, (struct usb_hub_descriptor *)buf); break; case GetHubStatus: - oz_trace2(OZ_TRACE_HUB, "GetHubStatus: req_type = 0x%x\n", + oz_trace("GetHubStatus: req_type = 0x%x\n", req_type); put_unaligned(__constant_cpu_to_le32(0), (__le32 *)buf); break; @@ -2082,13 +2161,13 @@ static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue, err = oz_get_port_status(hcd, windex, buf); break; case SetHubFeature: - oz_trace2(OZ_TRACE_HUB, "SetHubFeature: %d\n", req_type); + oz_trace("SetHubFeature: %d\n", req_type); break; case SetPortFeature: err = oz_set_port_feature(hcd, wvalue, windex); break; default: - oz_trace2(OZ_TRACE_HUB, "Other: %d\n", req_type); + oz_trace("Other: %d\n", req_type); break; } return err; @@ -2099,7 +2178,7 @@ static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue, static int oz_hcd_bus_suspend(struct usb_hcd *hcd) { struct oz_hcd *ozhcd; - oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_suspend()\n"); + ozhcd = oz_hcd_private(hcd); spin_lock_bh(&ozhcd->hcd_lock); hcd->state = HC_STATE_SUSPENDED; @@ -2113,7 +2192,7 @@ static int oz_hcd_bus_suspend(struct usb_hcd *hcd) static int oz_hcd_bus_resume(struct usb_hcd *hcd) { struct oz_hcd *ozhcd; - oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_resume()\n"); + ozhcd = oz_hcd_private(hcd); spin_lock_bh(&ozhcd->hcd_lock); ozhcd->flags &= ~OZ_HDC_F_SUSPENDED; @@ -2125,7 +2204,7 @@ static int oz_hcd_bus_resume(struct usb_hcd *hcd) */ static void oz_plat_shutdown(struct platform_device *dev) { - oz_trace("oz_plat_shutdown()\n"); + oz_trace("%s:\n", __func__); } /*------------------------------------------------------------------------------ * Context: process @@ -2136,10 +2215,10 @@ static int oz_plat_probe(struct platform_device *dev) int err; struct usb_hcd *hcd; struct oz_hcd *ozhcd; - oz_trace("oz_plat_probe()\n"); + hcd = usb_create_hcd(&g_oz_hc_drv, &dev->dev, dev_name(&dev->dev)); if (hcd == 0) { - oz_trace("Failed to created hcd object OK\n"); + oz_trace("Failed to created hcd object\n"); return -ENOMEM; } ozhcd = oz_hcd_private(hcd); @@ -2158,9 +2237,9 @@ static int oz_plat_probe(struct platform_device *dev) port->bus_addr = 0xff; spin_lock_init(&port->port_lock); } - err = usb_add_hcd(hcd, 0, 0); + err = usb_add_hcd(hcd, -1, 0); if (err) { - oz_trace("Failed to add hcd object OK\n"); + oz_trace("Failed to add hcd object\n"); usb_put_hcd(hcd); return -1; } @@ -2176,7 +2255,7 @@ static int oz_plat_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct oz_hcd *ozhcd; - oz_trace("oz_plat_remove()\n"); + if (hcd == 0) return -1; ozhcd = oz_hcd_private(hcd); @@ -2184,9 +2263,7 @@ static int oz_plat_remove(struct platform_device *dev) if (ozhcd == g_ozhcd) g_ozhcd = 0; spin_unlock_bh(&g_hcdlock); - oz_trace("Clearing orphanage\n"); - oz_hcd_clear_orphanage(ozhcd, -EPIPE); - oz_trace("Removing hcd\n"); + oz_hcd_clear_orphanage(ozhcd, -ENODEV); usb_remove_hcd(hcd); usb_put_hcd(hcd); oz_empty_link_pool(); @@ -2197,7 +2274,7 @@ static int oz_plat_remove(struct platform_device *dev) */ static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg) { - oz_trace("oz_plat_suspend()\n"); + oz_trace("%s:\n", __func__); return 0; } /*------------------------------------------------------------------------------ @@ -2205,7 +2282,7 @@ static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg) */ static int oz_plat_resume(struct platform_device *dev) { - oz_trace("oz_plat_resume()\n"); + oz_trace("%s:\n", __func__); return 0; } /*------------------------------------------------------------------------------ @@ -2216,10 +2293,10 @@ int oz_hcd_init(void) int err; if (usb_disabled()) return -ENODEV; + tasklet_init(&g_urb_process_tasklet, oz_urb_process_tasklet, 0); tasklet_init(&g_urb_cancel_tasklet, oz_urb_cancel_tasklet, 0); err = platform_driver_register(&g_oz_plat_drv); - oz_trace("platform_driver_register() returned %d\n", err); if (err) goto error; g_plat_dev = platform_device_alloc(OZ_PLAT_DEV_NAME, -1); @@ -2227,11 +2304,9 @@ int oz_hcd_init(void) err = -ENOMEM; goto error1; } - oz_trace("platform_device_alloc() succeeded\n"); err = platform_device_add(g_plat_dev); if (err) goto error2; - oz_trace("platform_device_add() succeeded\n"); return 0; error2: platform_device_put(g_plat_dev); @@ -2240,7 +2315,7 @@ error1: error: tasklet_disable(&g_urb_process_tasklet); tasklet_disable(&g_urb_cancel_tasklet); - oz_trace("oz_hcd_init() failed %d\n", err); + oz_trace("HCD Init failed: %d\n", err); return err; } /*------------------------------------------------------------------------------ @@ -2248,6 +2323,7 @@ error: */ void oz_hcd_term(void) { + msleep(OZ_HUB_DEBOUNCE_TIMEOUT); tasklet_disable(&g_urb_process_tasklet); tasklet_disable(&g_urb_cancel_tasklet); platform_device_unregister(g_plat_dev); diff --git a/drivers/staging/ozwpan/ozkobject.c b/drivers/staging/ozwpan/ozkobject.c new file mode 100644 index 000000000000..9b85ef55da15 --- /dev/null +++ b/drivers/staging/ozwpan/ozkobject.c @@ -0,0 +1,304 @@ +/* ----------------------------------------------------------------------------- + * Copyright (c) 2011 Ozmo Inc + * Released under the GNU General Public License Version 2 (GPLv2). + * ----------------------------------------------------------------------------- + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/sysfs.h> +#include <linux/version.h> +#include "ozpd.h" +#include "ozcdev.h" +#include "ozproto.h" +#include "oztrace.h" +#include "ozkobject.h" +#include "ozappif.h" + +static ssize_t devices_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int i, count, s; + unsigned state; + int ret = 0; + u8 devices[(ETH_ALEN + sizeof(unsigned)) * OZ_MAX_PDS]; + + count = oz_get_pd_status_list(devices, OZ_MAX_PDS); + s = sprintf(buf, "Total: %d\n", count); + buf += s; + ret += s; + for (i = 0; i < count; i++) { + ret += sprintf(buf, "%pm", (void *)&devices[i * (ETH_ALEN + + sizeof(unsigned))]); + buf += (ETH_ALEN * 2); + ret += sprintf(buf++, "\t"); + memcpy(&state, &devices[(i * (ETH_ALEN + sizeof(unsigned))) + + ETH_ALEN], sizeof(unsigned)); + switch (state) { + case OZ_PD_S_IDLE: + s = sprintf(buf, "IDLE\n"); + buf += s; + ret += s; + break; + case OZ_PD_S_CONNECTED: + s = sprintf(buf, "CONNECTED\n"); + buf += s; + ret += s; + break; + case OZ_PD_S_STOPPED: + s = sprintf(buf, "STOPPED\n"); + buf += s; + ret += s; + break; + case OZ_PD_S_SLEEP: + s = sprintf(buf, "SLEEP\n"); + buf += s; + ret += s; + break; + } + + } + return ret; +} + +u8 oz_str_to_hex(const char *st) +{ + u8 t1 = 0; + char arr[3]; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) + char **pt = NULL; +#endif + + memcpy(arr, st, 2); + arr[2] = '\0'; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) + t1 = (u8) simple_strtoul(arr, pt, 16); +#else + if (kstrtou8(arr, 16, &t1)) + oz_trace("Invalid string received\n"); +#endif + return t1; +} + +static ssize_t stop_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int i; + u8 mac_addr[6]; + struct oz_pd *pd; + + if (count >= 12) { + for (i = 0; i < 6; i++) { + mac_addr[i] = oz_str_to_hex(buf); + buf += 2; + } + + pd = oz_pd_find(mac_addr); + if (pd && (!(pd->state & OZ_PD_S_CONNECTED))) { + oz_pd_stop(pd); + oz_pd_put(pd); + } else + oz_pd_put(pd); + } + + return count; +} + +static ssize_t select_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int i; + int ret = 0; + u8 mac_addr[6]; + + oz_get_active_pd(mac_addr); + + for (i = 0; i < 6; i++) { + ret += sprintf(buf, "%02x", mac_addr[i]); + buf += 2; + } + ret += sprintf(buf, "\n"); + return ret; +} + +static ssize_t select_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int i; + u8 mac_addr[6]; + + if (count >= 12) { + for (i = 0; i < 6; i++) { + mac_addr[i] = oz_str_to_hex(buf); + buf += 2; + } + + oz_set_active_pd(mac_addr); + } + return count; +} + +static ssize_t bind_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + char nw_list[OZ_MAX_NW_IF * OZ_MAX_BINDING_LEN] = {0}; + int count, i, s; + int ret = 0; + + count = oz_get_binding_list(nw_list, OZ_MAX_NW_IF); + for (i = 0; i < count; i++) { + s = sprintf(buf, "%s\n", nw_list + (i * OZ_MAX_BINDING_LEN)); + ret += s; + buf += s; + } + return ret; +} + +static ssize_t bind_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char name[OZ_MAX_BINDING_LEN]; + char *p = NULL; + + memcpy(name, buf + 2, count); + p = strstr(name, "\n"); + if (p) + *p = '\0'; + + switch (*buf) { + case 'a': + oz_binding_add(name); + break; + case 'r': + oz_binding_remove(name); + break; + } + return count; +} + +static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + u8 mode; + int ret; + + mode = oz_get_serial_mode(); + ret = sprintf(buf, "0x%02x\n", mode); + return ret; +} + +static ssize_t mode_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + u8 new_mode; + if (count >= 4) { + new_mode = oz_str_to_hex(buf + 2); + oz_set_serial_mode(new_mode); + } else { + printk(KERN_ERR "Invalid mode\n"); + } + return count; +} + +static ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int ret = 0; + u32 debug = g_debug; + int i; + + for (i = 0; i < 'Z'-'A'+1; i++) { + if (debug & (1<<i)) + *(buf + ret++) = 'A' + i; + } + + return ret; +} + +static ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + u32 new_debug = 0; + const char *t = buf; + + if (count > 1 && count < 33) { + while (*t) { + char symbol = *t; + if ('A' <= symbol && symbol <= 'Z') + new_debug |= 1<<(symbol - 'A'); + t++; + } + + if (0 != new_debug) { + g_debug = new_debug; + } + else + printk(KERN_ERR "Invalid debug\n"); + } else { + if (1 == count && *t == '\0') + g_debug = 0; + } + + return count; +} + +static ssize_t fptr_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + int ret; + + ret = sprintf(buf, "p->oz_protocol_init = 0x%p\n", oz_protocol_init); + return ret; + +} + +static struct kobj_attribute devices_attribute = + __ATTR(devices, 0400, devices_show, NULL); + +static struct kobj_attribute stop_attribute = + __ATTR(stop, 0200, NULL, stop_store); + +static struct kobj_attribute select_attribute = + __ATTR(select, 0600, select_show, select_store); + +static struct kobj_attribute bind_attribute = + __ATTR(bind, 0600, bind_show, bind_store); + +static struct kobj_attribute mode_attribute = + __ATTR(mode, 0600, mode_show, mode_store); + +static struct kobj_attribute debug_attribute = + __ATTR(debug, 0600, debug_show, debug_store); + +static struct kobj_attribute fptr_attribute = + __ATTR(fptr, 0400, fptr_show, NULL); + +static struct attribute *attrs[] = { + &devices_attribute.attr, + &stop_attribute.attr, + &select_attribute.attr, + &bind_attribute.attr, + &mode_attribute.attr, + &debug_attribute.attr, + &fptr_attribute.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +void oz_create_sys_entry(void) +{ + int retval; + + retval = sysfs_create_group(&g_oz_wpan_dev->kobj, &attr_group); + if (retval) + oz_trace("Can not create attribute group\n"); + +} + +void oz_destroy_sys_entry(void) +{ + sysfs_remove_group(&g_oz_wpan_dev->kobj, &attr_group); +} diff --git a/drivers/staging/ozwpan/ozkobject.h b/drivers/staging/ozwpan/ozkobject.h new file mode 100644 index 000000000000..0557228001d4 --- /dev/null +++ b/drivers/staging/ozwpan/ozkobject.h @@ -0,0 +1,17 @@ +/* ----------------------------------------------------------------------------- + * Copyright (c) 2011 Ozmo Inc + * Released under the GNU General Public License Version 2 (GPLv2). + * ----------------------------------------------------------------------------- + */ + +#ifndef _OZKOBJECT_H +#define _OZKOBJECT_H + +#define OZ_MAX_NW_IF 6 + +void oz_create_sys_entry(void); +void oz_destroy_sys_entry(void); +void oz_set_serial_mode(u8 mode); +u8 oz_get_serial_mode(void); + +#endif /* _OZKOBJECT_H */ diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c index aaf2ccc0bcfb..0b48cc8508ff 100644 --- a/drivers/staging/ozwpan/ozmain.c +++ b/drivers/staging/ozwpan/ozmain.c @@ -10,12 +10,10 @@ #include <linux/netdevice.h> #include <linux/errno.h> #include <linux/ieee80211.h> -#include "ozconfig.h" #include "ozpd.h" #include "ozproto.h" #include "ozcdev.h" #include "oztrace.h" -#include "ozevent.h" /*------------------------------------------------------------------------------ * The name of the 802.11 mac device. Empty string is the default value but a * value can be supplied as a parameter to the module. An empty string means @@ -28,11 +26,11 @@ char *g_net_dev = ""; */ static int __init ozwpan_init(void) { - oz_event_init(); oz_cdev_register(); oz_protocol_init(g_net_dev); oz_app_enable(OZ_APPID_USB, 1); oz_apps_init(); + printk(KERN_DEBUG "p->oz_protocol_init = 0x%p\n", oz_protocol_init); return 0; } /*------------------------------------------------------------------------------ @@ -43,7 +41,6 @@ static void __exit ozwpan_exit(void) oz_protocol_term(); oz_apps_term(); oz_cdev_deregister(); - oz_event_term(); } /*------------------------------------------------------------------------------ */ @@ -53,6 +50,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.2.3-rc2"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c index 04cd57f2a6da..e3bf27b6bee8 100644 --- a/drivers/staging/ozwpan/ozpd.c +++ b/drivers/staging/ozwpan/ozpd.c @@ -9,13 +9,11 @@ #include <linux/sched.h> #include <linux/netdevice.h> #include <linux/errno.h> -#include "ozconfig.h" #include "ozprotocol.h" #include "ozeltbuf.h" #include "ozpd.h" #include "ozproto.h" #include "oztrace.h" -#include "ozevent.h" #include "ozcdev.h" #include "ozusbsvc.h" #include <asm/unaligned.h> @@ -24,18 +22,17 @@ /*------------------------------------------------------------------------------ */ #define OZ_MAX_TX_POOL_SIZE 6 -/* Maximum number of uncompleted isoc frames that can be pending. - */ -#define OZ_MAX_SUBMITTED_ISOC 16 +#define AC_VO 0x106 /*------------------------------------------------------------------------------ */ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd); static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f); +static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f); static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f); static int oz_send_isoc_frame(struct oz_pd *pd); static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f); static void oz_isoc_stream_free(struct oz_isoc_stream *st); -static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data); +static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data); static void oz_isoc_destructor(struct sk_buff *skb); static int oz_def_app_init(void); static void oz_def_app_term(void); @@ -84,6 +81,33 @@ static struct oz_app_if g_app_if[OZ_APPID_MAX] = { 0, 0, OZ_APPID_SERIAL}, + + {oz_def_app_init, + oz_def_app_term, + oz_def_app_start, + oz_def_app_stop, + oz_def_app_rx, + 0, + 0, + OZ_APPID_UNUSED3}, + + {oz_def_app_init, + oz_def_app_term, + oz_def_app_start, + oz_def_app_stop, + oz_def_app_rx, + 0, + 0, + OZ_APPID_UNUSED4}, + + {0, + 0, + 0, + 0, + oz_cdev_rx, + 0, + 0, + OZ_APPID_TFTP}, }; /*------------------------------------------------------------------------------ * Context: process @@ -123,23 +147,6 @@ static void oz_def_app_rx(struct oz_pd *pd, struct oz_elt *elt) void oz_pd_set_state(struct oz_pd *pd, unsigned state) { pd->state = state; - oz_event_log(OZ_EVT_PD_STATE, 0, 0, 0, state); -#ifdef WANT_TRACE - switch (state) { - case OZ_PD_S_IDLE: - oz_trace("PD State: OZ_PD_S_IDLE\n"); - break; - case OZ_PD_S_CONNECTED: - oz_trace("PD State: OZ_PD_S_CONNECTED\n"); - break; - case OZ_PD_S_STOPPED: - oz_trace("PD State: OZ_PD_S_STOPPED\n"); - break; - case OZ_PD_S_SLEEP: - oz_trace("PD State: OZ_PD_S_SLEEP\n"); - break; - } -#endif /* WANT_TRACE */ } /*------------------------------------------------------------------------------ * Context: softirq or process @@ -164,6 +171,7 @@ struct oz_pd *oz_pd_alloc(u8 *mac_addr) struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC); if (pd) { int i; + atomic_set(&pd->ref_count, 2); for (i = 0; i < OZ_APPID_MAX; i++) spin_lock_init(&pd->app_lock[i]); @@ -181,19 +189,28 @@ struct oz_pd *oz_pd_alloc(u8 *mac_addr) pd->last_sent_frame = &pd->tx_queue; spin_lock_init(&pd->stream_lock); INIT_LIST_HEAD(&pd->stream_list); + tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler, + (unsigned long)pd); + tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler, + (unsigned long)pd); + hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + pd->heartbeat.function = oz_pd_heartbeat_event; + pd->timeout.function = oz_pd_timeout_event; } return pd; } -/*------------------------------------------------------------------------------ - * Context: softirq or process - */ -void oz_pd_destroy(struct oz_pd *pd) +static void oz_pd_free(struct work_struct *work) { + struct oz_pd *pd; struct list_head *e; struct oz_tx_frame *f; struct oz_isoc_stream *st; struct oz_farewell *fwell; + pd = container_of(work, struct oz_pd, workitem); oz_trace("Destroying PD\n"); + tasklet_kill(&pd->heartbeat_tasklet); + tasklet_kill(&pd->timeout_tasklet); /* Delete any streams. */ e = pd->stream_list.next; @@ -208,6 +225,8 @@ void oz_pd_destroy(struct oz_pd *pd) while (e != &pd->tx_queue) { f = container_of(e, struct oz_tx_frame, link); e = e->next; + if (f->skb != NULL) + kfree_skb(f->skb); oz_retire_frame(pd, f); } oz_elt_buf_term(&pd->elt_buff); @@ -230,6 +249,28 @@ void oz_pd_destroy(struct oz_pd *pd) dev_put(pd->net_dev); kfree(pd); } + + +/*------------------------------------------------------------------------------ + * Context: softirq or Process + */ +void oz_pd_destroy(struct oz_pd *pd) +{ + int ret; + + if (hrtimer_active(&pd->timeout)) + hrtimer_cancel(&pd->timeout); + if (hrtimer_active(&pd->heartbeat)) + hrtimer_cancel(&pd->heartbeat); + + memset(&pd->workitem, 0, sizeof(pd->workitem)); + INIT_WORK(&pd->workitem, oz_pd_free); + ret = schedule_work(&pd->workitem); + + if (ret) + oz_trace("failed to schedule workitem\n"); +} + /*------------------------------------------------------------------------------ * Context: softirq-serialized */ @@ -238,12 +279,12 @@ int oz_services_start(struct oz_pd *pd, u16 apps, int resume) struct oz_app_if *ai; int rc = 0; oz_trace("oz_services_start(0x%x) resume(%d)\n", apps, resume); + if (apps & (1<<OZ_APPID_TFTP)) + apps |= 1<<OZ_APPID_SERIAL; for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) { if (apps & (1<<ai->app_id)) { - if (ai->start(pd, resume)) { + if (ai->start && ai->start(pd, resume)) { rc = -1; - oz_trace("Unabled to start service %d\n", - ai->app_id); break; } oz_polling_lock_bh(); @@ -262,6 +303,8 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause) { struct oz_app_if *ai; oz_trace("oz_stop_services(0x%x) pause(%d)\n", apps, pause); + if (apps & (1<<OZ_APPID_TFTP)) + apps |= 1<<OZ_APPID_SERIAL; for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) { if (apps & (1<<ai->app_id)) { oz_polling_lock_bh(); @@ -272,7 +315,8 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause) pd->paused_apps &= ~(1<<ai->app_id); } oz_polling_unlock_bh(); - ai->stop(pd, pause); + if (ai->stop) + ai->stop(pd, pause); } } } @@ -289,8 +333,8 @@ void oz_pd_heartbeat(struct oz_pd *pd, u16 apps) more = 1; } } - if (more) - oz_pd_request_heartbeat(pd); + if ((!more) && (hrtimer_active(&pd->heartbeat))) + hrtimer_cancel(&pd->heartbeat); if (pd->mode & OZ_F_ISOC_ANYTIME) { int count = 8; while (count-- && (oz_send_isoc_frame(pd) >= 0)) @@ -303,9 +347,9 @@ void oz_pd_heartbeat(struct oz_pd *pd, u16 apps) void oz_pd_stop(struct oz_pd *pd) { u16 stop_apps = 0; - oz_trace("oz_pd_stop() State = 0x%x\n", pd->state); - oz_pd_indicate_farewells(pd); + oz_trace("%s: State = 0x%x\n", __func__, pd->state); oz_polling_lock_bh(); + oz_pd_indicate_farewells(pd); stop_apps = pd->total_apps; pd->total_apps = 0; pd->paused_apps = 0; @@ -315,9 +359,9 @@ void oz_pd_stop(struct oz_pd *pd) oz_pd_set_state(pd, OZ_PD_S_STOPPED); /* Remove from PD list.*/ list_del(&pd->link); + + oz_polling_unlock_bh(); - oz_trace("pd ref count = %d\n", atomic_read(&pd->ref_count)); - oz_timer_delete(pd, 0); oz_pd_put(pd); } /*------------------------------------------------------------------------------ @@ -332,11 +376,8 @@ int oz_pd_sleep(struct oz_pd *pd) oz_polling_unlock_bh(); return 0; } - if (pd->keep_alive_j && pd->session_id) { + if (pd->keep_alive && pd->session_id) { oz_pd_set_state(pd, OZ_PD_S_SLEEP); - pd->pulse_time_j = jiffies + pd->keep_alive_j; - oz_trace("Sleep Now %lu until %lu\n", - jiffies, pd->pulse_time_j); } else { do_stop = 1; } @@ -346,7 +387,7 @@ int oz_pd_sleep(struct oz_pd *pd) oz_pd_stop(pd); } else { oz_services_stop(pd, stop_apps, 1); - oz_timer_add(pd, OZ_TIMER_STOP, jiffies + pd->keep_alive_j, 1); + oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive); } return do_stop; } @@ -375,6 +416,21 @@ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd) /*------------------------------------------------------------------------------ * Context: softirq or process */ +static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f) +{ + pd->nb_queued_isoc_frames--; + list_del_init(&f->link); + if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) { + f->link.next = pd->tx_pool; + pd->tx_pool = &f->link; + pd->tx_pool_count++; + } else { + kfree(f); + } +} +/*------------------------------------------------------------------------------ + * Context: softirq or process + */ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f) { spin_lock_bh(&pd->tx_frame_lock); @@ -389,6 +445,22 @@ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f) kfree(f); } /*------------------------------------------------------------------------------ + * Context: softirq-serialized + */ +void oz_set_more_bit(struct sk_buff *skb) +{ + struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); + oz_hdr->control |= OZ_F_MORE_DATA; +} +/*------------------------------------------------------------------------------ + * Context: softirq-serialized + */ +void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb) +{ + struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); + oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK; +} +/*------------------------------------------------------------------------------ * Context: softirq */ int oz_prepare_frame(struct oz_pd *pd, int empty) @@ -403,6 +475,7 @@ int oz_prepare_frame(struct oz_pd *pd, int empty) f = oz_tx_frame_alloc(pd); if (f == 0) return -1; + f->skb = NULL; f->hdr.control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED; ++pd->last_tx_pkt_num; @@ -439,6 +512,7 @@ static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f) skb_reset_network_header(skb); skb->dev = dev; skb->protocol = htons(OZ_ETHERTYPE); + skb->priority = AC_VO; if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr, dev->dev_addr, skb->len) < 0) goto fail; @@ -486,33 +560,51 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f) /*------------------------------------------------------------------------------ * Context: softirq-serialized */ -static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data) +static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data) { struct sk_buff *skb; struct oz_tx_frame *f; struct list_head *e; - *more_data = 0; spin_lock(&pd->tx_frame_lock); e = pd->last_sent_frame->next; if (e == &pd->tx_queue) { spin_unlock(&pd->tx_frame_lock); return -1; } - pd->last_sent_frame = e; - if (e->next != &pd->tx_queue) - *more_data = 1; f = container_of(e, struct oz_tx_frame, link); - skb = oz_build_frame(pd, f); - spin_unlock(&pd->tx_frame_lock); - oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num); - if (skb) { - oz_event_log(OZ_EVT_TX_FRAME, - 0, - (((u16)f->hdr.control)<<8)|f->hdr.last_pkt_num, - 0, f->hdr.pkt_num); - if (dev_queue_xmit(skb) < 0) + + if (f->skb != NULL) { + skb = f->skb; + oz_tx_isoc_free(pd, f); + spin_unlock(&pd->tx_frame_lock); + if (more_data) + oz_set_more_bit(skb); + oz_set_last_pkt_nb(pd, skb); + if ((int)atomic_read(&g_submitted_isoc) < + OZ_MAX_SUBMITTED_ISOC) { + oz_trace_skb(skb, 'T'); + if (dev_queue_xmit(skb) < 0) { + return -1; + } + atomic_inc(&g_submitted_isoc); + return 0; + } else { + kfree_skb(skb); return -1; + } } + + pd->last_sent_frame = e; + skb = oz_build_frame(pd, f); + spin_unlock(&pd->tx_frame_lock); + if (skb == 0) + return -1; + + if (more_data) + oz_set_more_bit(skb); + oz_trace_skb(skb, 'T'); + if (dev_queue_xmit(skb) < 0) + return -1; return 0; } /*------------------------------------------------------------------------------ @@ -520,21 +612,38 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data) */ void oz_send_queued_frames(struct oz_pd *pd, int backlog) { - int more; - if (backlog < OZ_MAX_QUEUED_FRAMES) { - if (oz_send_next_queued_frame(pd, &more) >= 0) { - while (more && oz_send_next_queued_frame(pd, &more)) - ; - } else { - if (((pd->mode & OZ_F_ISOC_ANYTIME) == 0) - || (pd->isoc_sent == 0)) { - if (oz_prepare_frame(pd, 1) >= 0) - oz_send_next_queued_frame(pd, &more); - } + while (oz_prepare_frame(pd, 0) >= 0) + backlog++; + + switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) { + + case OZ_F_ISOC_NO_ELTS: { + backlog += pd->nb_queued_isoc_frames; + if (backlog <= 0) + goto out; + if (backlog > OZ_MAX_SUBMITTED_ISOC) + backlog = OZ_MAX_SUBMITTED_ISOC; + break; + } + case OZ_NO_ELTS_ANYTIME: { + if ((backlog <= 0) && (pd->isoc_sent == 0)) + goto out; + break; + } + default: { + if (backlog <= 0) + goto out; + break; } - } else { - oz_send_next_queued_frame(pd, &more); } + while (backlog--) { + if (oz_send_next_queued_frame(pd, backlog) < 0) + break; + } + return; + +out: oz_prepare_frame(pd, 1); + oz_send_next_queued_frame(pd, 0); } /*------------------------------------------------------------------------------ * Context: softirq @@ -556,7 +665,6 @@ static int oz_send_isoc_frame(struct oz_pd *pd) return 0; skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC); if (skb == 0) { - oz_trace("Cannot alloc skb\n"); oz_elt_info_free_chain(&pd->elt_buff, &list); return -1; } @@ -580,7 +688,7 @@ static int oz_send_isoc_frame(struct oz_pd *pd) memcpy(elt, ei->data, ei->length); elt = oz_next_elt(elt); } - oz_event_log(OZ_EVT_TX_ISOC, 0, 0, 0, 0); + oz_trace_skb(skb, 'T'); dev_queue_xmit(skb); oz_elt_info_free_chain(&pd->elt_buff, &list); return 0; @@ -603,7 +711,7 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn) f = container_of(e, struct oz_tx_frame, link); pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num)); diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK; - if (diff > OZ_LAST_PN_HALF_CYCLE) + if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0)) break; if (first == 0) first = e; @@ -689,8 +797,6 @@ int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num) static void oz_isoc_destructor(struct sk_buff *skb) { atomic_dec(&g_submitted_isoc); - oz_event_log(OZ_EVT_TX_ISOC_DONE, atomic_read(&g_submitted_isoc), - 0, skb, 0); } /*------------------------------------------------------------------------------ * Context: softirq @@ -727,6 +833,8 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len) skb_reset_network_header(skb); skb->dev = dev; skb->protocol = htons(OZ_ETHERTYPE); + /* For audio packet set priority to AC_VO */ + skb->priority = AC_VO; size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large); oz_hdr = (struct oz_hdr *)skb_put(skb, size); } @@ -756,21 +864,52 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len) memcpy(oz_hdr, &oz, sizeof(oz)); memcpy(oz_hdr+1, &iso, sizeof(iso)); if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr, - dev->dev_addr, skb->len) < 0) { - kfree_skb(skb); - return -1; + dev->dev_addr, skb->len) < 0) + goto out; + + skb->destructor = oz_isoc_destructor; + /*Queue for Xmit if mode is not ANYTIME*/ + if (!(pd->mode & OZ_F_ISOC_ANYTIME)) { + struct oz_tx_frame *isoc_unit = NULL; + int nb = pd->nb_queued_isoc_frames; + struct list_head *e; + struct oz_tx_frame *f; + if (nb >= pd->isoc_latency) { + spin_lock(&pd->tx_frame_lock); + list_for_each(e, &pd->tx_queue) { + f = container_of(e, struct oz_tx_frame, + link); + if (f->skb != NULL) { + oz_tx_isoc_free(pd, f); + break; + } + } + spin_unlock(&pd->tx_frame_lock); + } + isoc_unit = oz_tx_frame_alloc(pd); + if (isoc_unit == NULL) + goto out; + isoc_unit->hdr = oz; + isoc_unit->skb = skb; + spin_lock_bh(&pd->tx_frame_lock); + list_add_tail(&isoc_unit->link, &pd->tx_queue); + pd->nb_queued_isoc_frames++; + spin_unlock_bh(&pd->tx_frame_lock); + return 0; } + /*In ANYTIME mode Xmit unit immediately*/ if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) { - skb->destructor = oz_isoc_destructor; atomic_inc(&g_submitted_isoc); - oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number, - skb, atomic_read(&g_submitted_isoc)); - if (dev_queue_xmit(skb) < 0) + oz_trace_skb(skb, 'T'); + if (dev_queue_xmit(skb) < 0) { return -1; - } else { - oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0); - kfree_skb(skb); + } else + return 0; } + +out: kfree_skb(skb); + return -1; + } return 0; } @@ -813,18 +952,10 @@ void oz_pd_indicate_farewells(struct oz_pd *pd) { struct oz_farewell *f; struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1]; - while (1) { - oz_polling_lock_bh(); - if (list_empty(&pd->farewell_list)) { - oz_polling_unlock_bh(); - break; - } + if (!(list_empty(&pd->farewell_list))) { f = list_first_entry(&pd->farewell_list, - struct oz_farewell, link); - list_del(&f->link); - oz_polling_unlock_bh(); + struct oz_farewell, link); if (ai->farewell) ai->farewell(pd, f->ep_num, f->report, f->len); - kfree(f); } } diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h index afc77f0260f0..355f637e72c5 100644 --- a/drivers/staging/ozwpan/ozpd.h +++ b/drivers/staging/ozwpan/ozpd.h @@ -6,6 +6,7 @@ #ifndef _OZPD_H_ #define _OZPD_H_ +#include <linux/interrupt.h> #include "ozeltbuf.h" /* PD state @@ -21,6 +22,7 @@ #define OZ_TIMER_HEARTBEAT 2 #define OZ_TIMER_STOP 3 +#define ETH_STRING_LEN 17 /* Data structure that hold information on a frame for transmisson. This is * built when the frame is first transmitted and is used to rebuild the frame * if a re-transmission is required. @@ -29,6 +31,7 @@ struct oz_tx_frame { struct list_head link; struct list_head elt_list; struct oz_hdr hdr; + struct sk_buff *skb; int total_size; }; @@ -46,7 +49,7 @@ struct oz_farewell { struct list_head link; u8 ep_num; u8 index; - u8 report[1]; + u8 report[32]; u8 len; }; @@ -67,22 +70,22 @@ struct oz_pd { u8 isoc_sent; u32 last_rx_pkt_num; u32 last_tx_pkt_num; + struct timespec last_rx_timestamp; u32 trigger_pkt_num; - unsigned long pulse_time_j; - unsigned long timeout_time_j; - unsigned long pulse_period_j; - unsigned long presleep_j; - unsigned long keep_alive_j; - unsigned long last_rx_time_j; + unsigned long pulse_time; + ktime_t pulse_period; + unsigned long presleep; + unsigned long keep_alive; struct oz_elt_buf elt_buff; void *app_ctx[OZ_APPID_MAX]; spinlock_t app_lock[OZ_APPID_MAX]; int max_tx_size; - u8 heartbeat_requested; u8 mode; u8 ms_per_isoc; + unsigned isoc_latency; unsigned max_stream_buffering; int nb_queued_frames; + int nb_queued_isoc_frames; struct list_head *tx_pool; int tx_pool_count; spinlock_t tx_frame_lock; @@ -92,6 +95,13 @@ struct oz_pd { spinlock_t stream_lock; struct list_head stream_list; struct net_device *net_dev; + struct hrtimer heartbeat; + struct hrtimer timeout; + u8 timeout_type; + struct tasklet_struct heartbeat_tasklet; + struct tasklet_struct timeout_tasklet; + struct work_struct workitem; + u8 up_audio_buf; }; #define OZ_MAX_QUEUED_FRAMES 4 @@ -118,4 +128,3 @@ void oz_apps_init(void); void oz_apps_term(void); #endif /* Sentry */ - diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c index ad857eeabbb7..e222d0831f8f 100644 --- a/drivers/staging/ozwpan/ozproto.c +++ b/drivers/staging/ozwpan/ozproto.c @@ -10,7 +10,6 @@ #include <linux/netdevice.h> #include <linux/errno.h> #include <linux/ieee80211.h> -#include "ozconfig.h" #include "ozprotocol.h" #include "ozeltbuf.h" #include "ozpd.h" @@ -18,7 +17,6 @@ #include "ozusbsvc.h" #include "oztrace.h" #include "ozappif.h" -#include "ozevent.h" #include <asm/unaligned.h> #include <linux/uaccess.h> #include <net/psnap.h> @@ -30,48 +28,32 @@ #define OZ_DO_STOP 1 #define OZ_DO_SLEEP 2 -/* States of the timer. - */ -#define OZ_TIMER_IDLE 0 -#define OZ_TIMER_SET 1 -#define OZ_TIMER_IN_HANDLER 2 - #define OZ_MAX_TIMER_POOL_SIZE 16 +/*------------------------------------------------------------------------------ + * Number of units of buffering to capture for an isochronous IN endpoint before + * allowing data to be indicated up. + */ +#define OZ_IN_BUFFERING_UNITS 100 /*------------------------------------------------------------------------------ */ struct oz_binding { struct packet_type ptype; char name[OZ_MAX_BINDING_LEN]; - struct oz_binding *next; -}; - -struct oz_timer { struct list_head link; - struct oz_pd *pd; - unsigned long due_time; - int type; }; + /*------------------------------------------------------------------------------ * Static external variables. */ static DEFINE_SPINLOCK(g_polling_lock); static LIST_HEAD(g_pd_list); -static struct oz_binding *g_binding ; +static LIST_HEAD(g_binding); static DEFINE_SPINLOCK(g_binding_lock); static struct sk_buff_head g_rx_queue; static u8 g_session_id; static u16 g_apps = 0x1; static int g_processing_rx; -static struct timer_list g_timer; -static struct oz_timer *g_cur_timer; -static struct list_head *g_timer_pool; -static int g_timer_pool_count; -static int g_timer_state = OZ_TIMER_IDLE; -static LIST_HEAD(g_timer_list); -/*------------------------------------------------------------------------------ - */ -static void oz_protocol_timer_start(void); /*------------------------------------------------------------------------------ * Context: softirq-serialized */ @@ -116,7 +98,6 @@ static void oz_send_conn_rsp(struct oz_pd *pd, u8 status) oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT); oz_hdr->last_pkt_num = 0; put_unaligned(0, &oz_hdr->pkt_num); - oz_event_log(OZ_EVT_CONNECT_RSP, 0, 0, 0, 0); elt->type = OZ_ELT_CONNECT_RSP; elt->length = sizeof(struct oz_elt_connect_rsp); memset(body, 0, sizeof(struct oz_elt_connect_rsp)); @@ -126,7 +107,7 @@ static void oz_send_conn_rsp(struct oz_pd *pd, u8 status) body->session_id = pd->session_id; put_unaligned(cpu_to_le16(pd->total_apps), &body->apps); } - oz_trace("TX: OZ_ELT_CONNECT_RSP %d", status); + oz_trace_skb(skb, 'T'); dev_queue_xmit(skb); return; } @@ -139,33 +120,35 @@ static void pd_set_keepalive(struct oz_pd *pd, u8 kalive) switch (kalive & OZ_KALIVE_TYPE_MASK) { case OZ_KALIVE_SPECIAL: - pd->keep_alive_j = - oz_ms_to_jiffies(keep_alive * 1000*60*60*24*20); + pd->keep_alive = (keep_alive*1000*60*60*24*20); break; case OZ_KALIVE_SECS: - pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000); + pd->keep_alive = (keep_alive*1000); break; case OZ_KALIVE_MINS: - pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60); + pd->keep_alive = (keep_alive*1000*60); break; case OZ_KALIVE_HOURS: - pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60*60); + pd->keep_alive = (keep_alive*1000*60*60); break; default: - pd->keep_alive_j = 0; + pd->keep_alive = 0; } - oz_trace("Keepalive = %lu jiffies\n", pd->keep_alive_j); } /*------------------------------------------------------------------------------ * Context: softirq-serialized */ -static void pd_set_presleep(struct oz_pd *pd, u8 presleep) +static void pd_set_presleep(struct oz_pd *pd, u8 presleep, u8 start_timer) { if (presleep) - pd->presleep_j = oz_ms_to_jiffies(presleep*100); + pd->presleep = presleep*100; else - pd->presleep_j = OZ_PRESLEEP_TOUT_J; - oz_trace("Presleep time = %lu jiffies\n", pd->presleep_j); + pd->presleep = OZ_PRESLEEP_TOUT; + if (start_timer) { + spin_unlock(&g_polling_lock); + oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep); + spin_lock(&g_polling_lock); + } } /*------------------------------------------------------------------------------ * Context: softirq-serialized @@ -190,7 +173,7 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt, pd = oz_pd_alloc(pd_addr); if (pd == 0) return 0; - pd->last_rx_time_j = jiffies; + getnstimeofday(&pd->last_rx_timestamp); spin_lock_bh(&g_polling_lock); list_for_each(e, &g_pd_list) { pd2 = container_of(e, struct oz_pd, link); @@ -212,24 +195,35 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt, dev_hold(net_dev); pd->net_dev = net_dev; } - oz_trace("Host vendor: %d\n", body->host_vendor); pd->max_tx_size = OZ_MAX_TX_SIZE; pd->mode = body->mode; pd->pd_info = body->pd_info; + pd->up_audio_buf = body->up_audio_buf > 0 ? body->up_audio_buf : + OZ_IN_BUFFERING_UNITS; if (pd->mode & OZ_F_ISOC_NO_ELTS) { - pd->mode |= OZ_F_ISOC_ANYTIME; pd->ms_per_isoc = body->ms_per_isoc; if (!pd->ms_per_isoc) pd->ms_per_isoc = 4; + + switch (body->ms_isoc_latency & OZ_LATENCY_MASK) { + case OZ_ONE_MS_LATENCY: + pd->isoc_latency = (body->ms_isoc_latency & + ~OZ_LATENCY_MASK) / pd->ms_per_isoc; + break; + case OZ_TEN_MS_LATENCY: + pd->isoc_latency = ((body->ms_isoc_latency & + ~OZ_LATENCY_MASK) * 10) / pd->ms_per_isoc; + break; + default: + pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC; + } } if (body->max_len_div16) pd->max_tx_size = ((u16)body->max_len_div16)<<4; - oz_trace("Max frame:%u Ms per isoc:%u\n", - pd->max_tx_size, pd->ms_per_isoc); pd->max_stream_buffering = 3*1024; - pd->timeout_time_j = jiffies + OZ_CONNECTION_TOUT_J; - pd->pulse_period_j = OZ_QUANTUM_J; - pd_set_presleep(pd, body->presleep); + pd->pulse_period = ktime_set(OZ_QUANTUM / MSEC_PER_SEC, (OZ_QUANTUM % + MSEC_PER_SEC) * NSEC_PER_MSEC); + pd_set_presleep(pd, body->presleep, 0); pd_set_keepalive(pd, body->keep_alive); new_apps &= le16_to_cpu(get_unaligned(&body->apps)); @@ -261,9 +255,6 @@ done: u16 resume_apps = new_apps & pd->paused_apps & ~0x1; spin_unlock_bh(&g_polling_lock); oz_pd_set_state(pd, OZ_PD_S_CONNECTED); - oz_timer_delete(pd, OZ_TIMER_STOP); - oz_trace("new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n", - new_apps, pd->total_apps, pd->paused_apps); if (start_apps) { if (oz_services_start(pd, start_apps, 0)) rsp_status = OZ_STATUS_TOO_MANY_PDS; @@ -304,6 +295,7 @@ static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index, return; f->ep_num = ep_num; f->index = index; + f->len = len; memcpy(f->report, report, len); oz_trace("RX: Adding farewell report\n"); spin_lock(&g_polling_lock); @@ -330,15 +322,11 @@ static void oz_rx_frame(struct sk_buff *skb) int length; struct oz_pd *pd = 0; struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); + struct timespec current_time; int dup = 0; u32 pkt_num; - oz_event_log(OZ_EVT_RX_PROCESS, 0, - (((u16)oz_hdr->control)<<8)|oz_hdr->last_pkt_num, - 0, oz_hdr->pkt_num); - oz_trace2(OZ_TRACE_RX_FRAMES, - "RX frame PN=0x%x LPN=0x%x control=0x%x\n", - oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control); + oz_trace_skb(skb, 'R'); mac_hdr = skb_mac_header(skb); src_addr = &mac_hdr[ETH_ALEN] ; length = skb->len; @@ -350,18 +338,23 @@ static void oz_rx_frame(struct sk_buff *skb) goto done; } + pkt_num = le32_to_cpu(get_unaligned(&oz_hdr->pkt_num)); pd = oz_pd_find(src_addr); if (pd) { - pd->last_rx_time_j = jiffies; - oz_timer_add(pd, OZ_TIMER_TOUT, - pd->last_rx_time_j + pd->presleep_j, 1); + if (!(pd->state & OZ_PD_S_CONNECTED)) + oz_pd_set_state(pd, OZ_PD_S_CONNECTED); + getnstimeofday(¤t_time); + if ((current_time.tv_sec != pd->last_rx_timestamp.tv_sec) || + (pd->presleep < MSEC_PER_SEC)) { + oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep); + pd->last_rx_timestamp = current_time; + } if (pkt_num != pd->last_rx_pkt_num) { pd->last_rx_pkt_num = pkt_num; } else { dup = 1; - oz_trace("Duplicate frame\n"); } } @@ -376,8 +369,6 @@ static void oz_rx_frame(struct sk_buff *skb) int backlog = pd->nb_queued_frames; pd->trigger_pkt_num = pkt_num; /* Send queued frames */ - while (oz_prepare_frame(pd, 0) >= 0) - ; oz_send_queued_frames(pd, backlog); } } @@ -385,29 +376,25 @@ static void oz_rx_frame(struct sk_buff *skb) length -= sizeof(struct oz_hdr); elt = (struct oz_elt *)((u8 *)oz_hdr + sizeof(struct oz_hdr)); - while (length >= sizeof(struct oz_elt)) { - length -= sizeof(struct oz_elt) + elt->length; + while (length >= oz_elt_hdr_len(elt)) { + length -= oz_elt_len(elt); if (length < 0) break; switch (elt->type) { case OZ_ELT_CONNECT_REQ: - oz_event_log(OZ_EVT_CONNECT_REQ, 0, 0, 0, 0); - oz_trace("RX: OZ_ELT_CONNECT_REQ\n"); pd = oz_connect_req(pd, elt, src_addr, skb->dev); break; case OZ_ELT_DISCONNECT: - oz_trace("RX: OZ_ELT_DISCONNECT\n"); if (pd) oz_pd_sleep(pd); break; case OZ_ELT_UPDATE_PARAM_REQ: { struct oz_elt_update_param *body = (struct oz_elt_update_param *)(elt + 1); - oz_trace("RX: OZ_ELT_UPDATE_PARAM_REQ\n"); if (pd && (pd->state & OZ_PD_S_CONNECTED)) { spin_lock(&g_polling_lock); pd_set_keepalive(pd, body->keepalive); - pd_set_presleep(pd, body->presleep); + pd_set_presleep(pd, body->presleep, 1); spin_unlock(&g_polling_lock); } } @@ -415,16 +402,16 @@ static void oz_rx_frame(struct sk_buff *skb) case OZ_ELT_FAREWELL_REQ: { struct oz_elt_farewell *body = (struct oz_elt_farewell *)(elt + 1); - oz_trace("RX: OZ_ELT_FAREWELL_REQ\n"); oz_add_farewell(pd, body->ep_num, body->index, body->report, elt->length + 1 - sizeof(*body)); } break; case OZ_ELT_APP_DATA: + case OZ_ELT_APP_DATA_EX: if (pd && (pd->state & OZ_PD_S_CONNECTED)) { struct oz_app_hdr *app_hdr = - (struct oz_app_hdr *)(elt+1); + (struct oz_app_hdr *)(oz_elt_data(elt)); if (dup) break; oz_handle_app_elt(pd, app_hdr->app_id, elt); @@ -445,14 +432,13 @@ done: */ void oz_protocol_term(void) { - struct list_head *chain = 0; - del_timer_sync(&g_timer); + struct oz_binding *b, *t; + /* Walk the list of bindings and remove each one. */ spin_lock_bh(&g_binding_lock); - while (g_binding) { - struct oz_binding *b = g_binding; - g_binding = b->next; + list_for_each_entry_safe(b, t, &g_binding, link) { + list_del(&b->link); spin_unlock_bh(&g_binding_lock); dev_remove_pack(&b->ptype); if (b->ptype.dev) @@ -475,251 +461,110 @@ void oz_protocol_term(void) oz_pd_put(pd); spin_lock_bh(&g_polling_lock); } - chain = g_timer_pool; - g_timer_pool = 0; spin_unlock_bh(&g_polling_lock); - while (chain) { - struct oz_timer *t = container_of(chain, struct oz_timer, link); - chain = chain->next; - kfree(t); - } oz_trace("Protocol stopped\n"); } /*------------------------------------------------------------------------------ * Context: softirq */ -static void oz_pd_handle_timer(struct oz_pd *pd, int type) +void oz_pd_heartbeat_handler(unsigned long data) { + struct oz_pd *pd = (struct oz_pd *)data; + u16 apps = 0; + spin_lock_bh(&g_polling_lock); + if (pd->state & OZ_PD_S_CONNECTED) + apps = pd->total_apps; + spin_unlock_bh(&g_polling_lock); + if (apps) + oz_pd_heartbeat(pd, apps); + + oz_pd_put(pd); +} +/*------------------------------------------------------------------------------ + * Context: softirq + */ +void oz_pd_timeout_handler(unsigned long data) +{ + int type; + struct oz_pd *pd = (struct oz_pd *)data; + + spin_lock_bh(&g_polling_lock); + type = pd->timeout_type; + spin_unlock_bh(&g_polling_lock); switch (type) { case OZ_TIMER_TOUT: + oz_trace_msg(M, "OZ_TIMER_TOUT:\n"); oz_pd_sleep(pd); break; case OZ_TIMER_STOP: + oz_trace_msg(M, "OZ_TIMER_STOP:\n"); oz_pd_stop(pd); break; - case OZ_TIMER_HEARTBEAT: { - u16 apps = 0; - spin_lock_bh(&g_polling_lock); - pd->heartbeat_requested = 0; - if (pd->state & OZ_PD_S_CONNECTED) - apps = pd->total_apps; - spin_unlock_bh(&g_polling_lock); - if (apps) - oz_pd_heartbeat(pd, apps); - } - break; } + oz_pd_put(pd); } /*------------------------------------------------------------------------------ - * Context: softirq + * Context: Interrupt */ -static void oz_protocol_timer(unsigned long arg) +enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer) { - struct oz_timer *t; - struct oz_timer *t2; struct oz_pd *pd; - spin_lock_bh(&g_polling_lock); - if (!g_cur_timer) { - /* This happens if we remove the current timer but can't stop - * the timer from firing. In this case just get out. - */ - oz_event_log(OZ_EVT_TIMER, 0, 0, 0, 0); - spin_unlock_bh(&g_polling_lock); - return; - } - g_timer_state = OZ_TIMER_IN_HANDLER; - t = g_cur_timer; - g_cur_timer = 0; - list_del(&t->link); - spin_unlock_bh(&g_polling_lock); - do { - pd = t->pd; - oz_event_log(OZ_EVT_TIMER, 0, t->type, 0, 0); - oz_pd_handle_timer(pd, t->type); - spin_lock_bh(&g_polling_lock); - if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) { - t->link.next = g_timer_pool; - g_timer_pool = &t->link; - g_timer_pool_count++; - t = 0; - } - if (!list_empty(&g_timer_list)) { - t2 = container_of(g_timer_list.next, - struct oz_timer, link); - if (time_before_eq(t2->due_time, jiffies)) - list_del(&t2->link); - else - t2 = 0; - } else { - t2 = 0; - } - spin_unlock_bh(&g_polling_lock); - oz_pd_put(pd); - if (t) - kfree(t); - t = t2; - } while (t); - g_timer_state = OZ_TIMER_IDLE; - oz_protocol_timer_start(); + + pd = container_of(timer, struct oz_pd, heartbeat); + hrtimer_forward(timer, + hrtimer_get_expires(timer), pd->pulse_period); + oz_pd_get(pd); + tasklet_schedule(&pd->heartbeat_tasklet); + return HRTIMER_RESTART; } /*------------------------------------------------------------------------------ - * Context: softirq + * Context: Interrupt */ -static void oz_protocol_timer_start(void) +enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer) { - spin_lock_bh(&g_polling_lock); - if (!list_empty(&g_timer_list)) { - g_cur_timer = - container_of(g_timer_list.next, struct oz_timer, link); - if (g_timer_state == OZ_TIMER_SET) { - oz_event_log(OZ_EVT_TIMER_CTRL, 3, - (u16)g_cur_timer->type, 0, - (unsigned)g_cur_timer->due_time); - mod_timer(&g_timer, g_cur_timer->due_time); - } else { - oz_event_log(OZ_EVT_TIMER_CTRL, 4, - (u16)g_cur_timer->type, 0, - (unsigned)g_cur_timer->due_time); - g_timer.expires = g_cur_timer->due_time; - g_timer.function = oz_protocol_timer; - g_timer.data = 0; - add_timer(&g_timer); - } - g_timer_state = OZ_TIMER_SET; - } else { - oz_trace("No queued timers\n"); - } - spin_unlock_bh(&g_polling_lock); + struct oz_pd *pd; + + pd = container_of(timer, struct oz_pd, timeout); + oz_pd_get(pd); + tasklet_schedule(&pd->timeout_tasklet); + return HRTIMER_NORESTART; } /*------------------------------------------------------------------------------ * Context: softirq or process */ -void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time, - int remove) +void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time) { - struct list_head *e; - struct oz_timer *t = 0; - int restart_needed = 0; - oz_event_log(OZ_EVT_TIMER_CTRL, 1, (u16)type, 0, (unsigned)due_time); - spin_lock(&g_polling_lock); - if (remove) { - list_for_each(e, &g_timer_list) { - t = container_of(e, struct oz_timer, link); - if ((t->pd == pd) && (t->type == type)) { - if (g_cur_timer == t) { - restart_needed = 1; - g_cur_timer = 0; - } - list_del(e); - break; - } - t = 0; - } - } - if (!t) { - if (g_timer_pool) { - t = container_of(g_timer_pool, struct oz_timer, link); - g_timer_pool = g_timer_pool->next; - g_timer_pool_count--; + spin_lock_bh(&g_polling_lock); + switch (type) { + case OZ_TIMER_TOUT: + case OZ_TIMER_STOP: + if (hrtimer_active(&pd->timeout)) { + hrtimer_set_expires(&pd->timeout, ktime_set(due_time / + MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * + NSEC_PER_MSEC)); + hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL); } else { - t = kmalloc(sizeof(struct oz_timer), GFP_ATOMIC); - } - if (t) { - t->pd = pd; - t->type = type; - oz_pd_get(pd); + hrtimer_start(&pd->timeout, ktime_set(due_time / + MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * + NSEC_PER_MSEC), HRTIMER_MODE_REL); } + pd->timeout_type = type; + break; + case OZ_TIMER_HEARTBEAT: + if (!hrtimer_active(&pd->heartbeat)) + hrtimer_start(&pd->heartbeat, ktime_set(due_time / + MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * + NSEC_PER_MSEC), HRTIMER_MODE_REL); + break; } - if (t) { - struct oz_timer *t2; - t->due_time = due_time; - list_for_each(e, &g_timer_list) { - t2 = container_of(e, struct oz_timer, link); - if (time_before(due_time, t2->due_time)) { - if (t2 == g_cur_timer) { - g_cur_timer = 0; - restart_needed = 1; - } - break; - } - } - list_add_tail(&t->link, e); - } - if (g_timer_state == OZ_TIMER_IDLE) - restart_needed = 1; - else if (g_timer_state == OZ_TIMER_IN_HANDLER) - restart_needed = 0; - spin_unlock(&g_polling_lock); - if (restart_needed) - oz_protocol_timer_start(); -} -/*------------------------------------------------------------------------------ - * Context: softirq or process - */ -void oz_timer_delete(struct oz_pd *pd, int type) -{ - struct list_head *chain = 0; - struct oz_timer *t; - struct oz_timer *n; - int restart_needed = 0; - int release = 0; - oz_event_log(OZ_EVT_TIMER_CTRL, 2, (u16)type, 0, 0); - spin_lock(&g_polling_lock); - list_for_each_entry_safe(t, n, &g_timer_list, link) { - if ((t->pd == pd) && ((type == 0) || (t->type == type))) { - if (g_cur_timer == t) { - restart_needed = 1; - g_cur_timer = 0; - del_timer(&g_timer); - } - list_del(&t->link); - release++; - if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE) { - t->link.next = g_timer_pool; - g_timer_pool = &t->link; - g_timer_pool_count++; - } else { - t->link.next = chain; - chain = &t->link; - } - if (type) - break; - } - } - if (g_timer_state == OZ_TIMER_IN_HANDLER) - restart_needed = 0; - else if (restart_needed) - g_timer_state = OZ_TIMER_IDLE; - spin_unlock(&g_polling_lock); - if (restart_needed) - oz_protocol_timer_start(); - while (release--) - oz_pd_put(pd); - while (chain) { - t = container_of(chain, struct oz_timer, link); - chain = chain->next; - kfree(t); - } + spin_unlock_bh(&g_polling_lock); } /*------------------------------------------------------------------------------ * Context: softirq or process */ void oz_pd_request_heartbeat(struct oz_pd *pd) { - unsigned long now = jiffies; - unsigned long t; - spin_lock(&g_polling_lock); - if (pd->heartbeat_requested) { - spin_unlock(&g_polling_lock); - return; - } - if (pd->pulse_period_j) - t = ((now / pd->pulse_period_j) + 1) * pd->pulse_period_j; - else - t = now + 1; - pd->heartbeat_requested = 1; - spin_unlock(&g_polling_lock); - oz_timer_add(pd, OZ_TIMER_HEARTBEAT, t, 0); + oz_timer_add(pd, OZ_TIMER_HEARTBEAT, OZ_QUANTUM); } /*------------------------------------------------------------------------------ * Context: softirq or process @@ -760,7 +605,6 @@ void oz_app_enable(int app_id, int enable) static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - oz_event_log(OZ_EVT_RX_FRAME, 0, 0, 0, 0); skb = skb_share_check(skb, GFP_ATOMIC); if (skb == 0) return 0; @@ -792,11 +636,11 @@ static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev, /*------------------------------------------------------------------------------ * Context: process */ -void oz_binding_add(char *net_dev) +void oz_binding_add(const char *net_dev) { struct oz_binding *binding; - binding = kmalloc(sizeof(struct oz_binding), GFP_ATOMIC); + binding = kmalloc(sizeof(struct oz_binding), GFP_KERNEL); if (binding) { binding->ptype.type = __constant_htons(OZ_ETHERTYPE); binding->ptype.func = oz_pkt_recv; @@ -817,8 +661,7 @@ void oz_binding_add(char *net_dev) if (binding) { dev_add_pack(&binding->ptype); spin_lock_bh(&g_binding_lock); - binding->next = g_binding; - g_binding = binding; + list_add_tail(&binding->link, &g_binding); spin_unlock_bh(&g_binding_lock); } } @@ -826,7 +669,7 @@ void oz_binding_add(char *net_dev) /*------------------------------------------------------------------------------ * Context: process */ -static int compare_binding_name(char *s1, char *s2) +static int compare_binding_name(const char *s1, const char *s2) { int i; for (i = 0; i < OZ_MAX_BINDING_LEN; i++) { @@ -864,37 +707,52 @@ static void pd_stop_all_for_device(struct net_device *net_dev) /*------------------------------------------------------------------------------ * Context: process */ -void oz_binding_remove(char *net_dev) +void oz_binding_remove(const char *net_dev) { - struct oz_binding *binding = 0; - struct oz_binding **link; + struct oz_binding *binding = NULL; + int found = 0; + oz_trace("Removing binding: %s\n", net_dev); spin_lock_bh(&g_binding_lock); - binding = g_binding; - link = &g_binding; - while (binding) { + list_for_each_entry(binding, &g_binding, link) { if (compare_binding_name(binding->name, net_dev)) { oz_trace("Binding '%s' found\n", net_dev); - *link = binding->next; + found = 1; break; - } else { - link = &binding; - binding = binding->next; } } spin_unlock_bh(&g_binding_lock); - if (binding) { + if (found) { dev_remove_pack(&binding->ptype); if (binding->ptype.dev) { dev_put(binding->ptype.dev); pd_stop_all_for_device(binding->ptype.dev); } + list_del(&binding->link); kfree(binding); } } /*------------------------------------------------------------------------------ * Context: process */ +int oz_get_binding_list(char *buf, int max_if) +{ + struct oz_binding *binding = 0; + int count = 0; + + spin_lock_bh(&g_binding_lock); + list_for_each_entry(binding, &g_binding, link) { + if (count++ > max_if) + break; + memcpy(buf, binding->name, OZ_MAX_BINDING_LEN); + buf += OZ_MAX_BINDING_LEN; + } + spin_unlock_bh(&g_binding_lock); + return count; +} +/*------------------------------------------------------------------------------ + * Context: process + */ static char *oz_get_next_device_name(char *s, char *dname, int max_size) { while (*s == ',') @@ -922,7 +780,6 @@ int oz_protocol_init(char *devs) oz_binding_add(d); } } - init_timer(&g_timer); return 0; } /*------------------------------------------------------------------------------ @@ -944,6 +801,32 @@ int oz_get_pd_list(struct oz_mac_addr *addr, int max_count) return count; } /*------------------------------------------------------------------------------ + * Context: process + */ +int oz_get_pd_status_list(u8 *pd_list, int max_count) +{ + struct oz_pd *pd; + struct list_head *e; + int count = 0; + + spin_lock_bh(&g_polling_lock); + list_for_each(e, &g_pd_list) { + if (count >= max_count) + break; + pd = container_of(e, struct oz_pd, link); + if (pd_list) { + memcpy(&pd_list[count * (ETH_ALEN + sizeof(pd->state))], + pd->mac_addr, ETH_ALEN); + memcpy(&pd_list[(count * (ETH_ALEN + sizeof(pd->state))) + + ETH_ALEN], + &pd->state, sizeof(pd->state)); + count++; + } + } + spin_unlock_bh(&g_polling_lock); + return count; +} +/*------------------------------------------------------------------------------ */ void oz_polling_lock_bh(void) { diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h index 89aea28bd8d5..9b100a5b479c 100644 --- a/drivers/staging/ozwpan/ozproto.h +++ b/drivers/staging/ozwpan/ozproto.h @@ -7,28 +7,25 @@ #define _OZPROTO_H #include <asm/byteorder.h> -#include "ozconfig.h" #include "ozappif.h" #define OZ_ALLOCATED_SPACE(__x) (LL_RESERVED_SPACE(__x)+(__x)->needed_tailroom) -/* Converts millisecs to jiffies. - */ -#define oz_ms_to_jiffies(__x) (((__x)*1000)/HZ) -/* Quantum milliseconds. - */ -#define OZ_QUANTUM_MS 8 -/* Quantum jiffies - */ -#define OZ_QUANTUM_J (oz_ms_to_jiffies(OZ_QUANTUM_MS)) +/* Quantum in MS */ +#define OZ_QUANTUM 8 /* Default timeouts. */ -#define OZ_CONNECTION_TOUT_J (2*HZ) -#define OZ_PRESLEEP_TOUT_J (11*HZ) +#define OZ_PRESLEEP_TOUT 11 /* Maximun sizes of tx frames. */ -#define OZ_MAX_TX_SIZE 1514 +#define OZ_MAX_TX_SIZE 760 + +/* Maximum number of uncompleted isoc frames that can be pending in network. */ +#define OZ_MAX_SUBMITTED_ISOC 16 + +/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue. */ +#define OZ_MAX_TX_QUEUE_ISOC 32 /* Application handler functions. */ @@ -57,13 +54,17 @@ void oz_protocol_term(void); int oz_get_pd_list(struct oz_mac_addr *addr, int max_count); void oz_app_enable(int app_id, int enable); struct oz_pd *oz_pd_find(u8 *mac_addr); -void oz_binding_add(char *net_dev); -void oz_binding_remove(char *net_dev); -void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time, - int remove); +void oz_binding_add(const char *net_dev); +void oz_binding_remove(const char *net_dev); +void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time); void oz_timer_delete(struct oz_pd *pd, int type); void oz_pd_request_heartbeat(struct oz_pd *pd); void oz_polling_lock_bh(void); void oz_polling_unlock_bh(void); - +void oz_pd_heartbeat_handler(unsigned long data); +void oz_pd_timeout_handler(unsigned long data); +enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer); +enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer); +int oz_get_pd_status_list(u8 *pd_list, int max_count); +int oz_get_binding_list(char *buf, int max_if); #endif /* _OZPROTO_H */ diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h index b3e7d77f3fff..ee76c2e2e308 100644 --- a/drivers/staging/ozwpan/ozprotocol.h +++ b/drivers/staging/ozwpan/ozprotocol.h @@ -27,17 +27,51 @@ struct oz_elt { u8 length; } PACKED; -#define oz_next_elt(__elt) \ - (struct oz_elt *)((u8 *)((__elt) + 1) + (__elt)->length) +/* This is an extended element header. + */ +struct oz_ext_elt { + u8 type; + u16 length; +} PACKED; + + + +#define oz_is_ext_elt(__elt) \ + (((struct oz_elt *)(__elt))->type >= OZ_ELT_EXTENDED) + +#define oz_elt_hdr_len(__elt) \ + (int)(oz_is_ext_elt(__elt) ? \ + (sizeof(struct oz_ext_elt)) \ + : (sizeof(struct oz_elt))) + +#define oz_elt_data_len(__elt) \ + (int)(oz_is_ext_elt(__elt) ? \ + (le16_to_cpu((((struct oz_ext_elt *)(__elt))->length))) \ + : (__elt)->length) + +#define oz_elt_len(__elt) \ + (oz_elt_hdr_len(__elt) + oz_elt_data_len(__elt)) + +#define oz_elt_data(__elt) \ + ((u8 *)(((u8 *)(__elt)) + oz_elt_hdr_len(__elt))) + + +#define oz_next_elt(__elt) \ + (struct oz_elt *)((u8 *)(__elt) + oz_elt_len(__elt)) + /* Protocol element IDs. */ +#define OZ_ELT_EXTENDED 0xC0 +#define OZ_ELT_ID_MASK 0x3F #define OZ_ELT_CONNECT_REQ 0x06 #define OZ_ELT_CONNECT_RSP 0x07 #define OZ_ELT_DISCONNECT 0x08 #define OZ_ELT_UPDATE_PARAM_REQ 0x11 #define OZ_ELT_FAREWELL_REQ 0x12 #define OZ_ELT_APP_DATA 0x31 +#define OZ_ELT_APP_DATA_EX (OZ_ELT_EXTENDED|OZ_ELT_APP_DATA) + /* This is the Ozmo header which is the first Ozmo specific part * of a frame and comes after the MAC header. @@ -65,6 +99,10 @@ struct oz_hdr { #define OZ_LAST_PN_HALF_CYCLE 127 +#define OZ_LATENCY_MASK 0xc0 +#define OZ_ONE_MS_LATENCY 0x40 +#define OZ_TEN_MS_LATENCY 0x80 + /* Connect request data structure. */ struct oz_elt_connect_req { @@ -73,13 +111,14 @@ struct oz_elt_connect_req { u8 pd_info; u8 session_id; u8 presleep; - u8 resv2; + u8 ms_isoc_latency; u8 host_vendor; u8 keep_alive; u16 apps; u8 max_len_div16; u8 ms_per_isoc; - u8 resv3[2]; + u8 up_audio_buf; + u8 ms_per_elt; } PACKED; /* mode field bits. @@ -89,6 +128,7 @@ struct oz_elt_connect_req { #define OZ_MODE_MASK 0xf #define OZ_F_ISOC_NO_ELTS 0x40 #define OZ_F_ISOC_ANYTIME 0x80 +#define OZ_NO_ELTS_ANYTIME 0xc0 /* Keep alive field. */ @@ -137,7 +177,10 @@ struct oz_app_hdr { #define OZ_APPID_UNUSED1 0x2 #define OZ_APPID_UNUSED2 0x3 #define OZ_APPID_SERIAL 0x4 -#define OZ_APPID_MAX OZ_APPID_SERIAL +#define OZ_APPID_UNUSED3 0x5 +#define OZ_APPID_UNUSED4 0x6 +#define OZ_APPID_TFTP 0x7 +#define OZ_APPID_MAX OZ_APPID_TFTP #define OZ_NB_APPS (OZ_APPID_MAX+1) /* USB header common to all elements for the USB application. diff --git a/drivers/staging/ozwpan/oztrace.c b/drivers/staging/ozwpan/oztrace.c index 353ead24fd7d..6bb22572dd2a 100644 --- a/drivers/staging/ozwpan/oztrace.c +++ b/drivers/staging/ozwpan/oztrace.c @@ -3,34 +3,156 @@ * Released under the GNU General Public License Version 2 (GPLv2). * ----------------------------------------------------------------------------- */ -#include "ozconfig.h" #include "oztrace.h" +#define CREATE_TRACE_POINTS +#include "ozeventtrace.h" -#ifdef WANT_VERBOSE_TRACE -unsigned long trace_flags = - 0 -#ifdef WANT_TRACE_STREAM - | OZ_TRACE_STREAM -#endif /* WANT_TRACE_STREAM */ -#ifdef WANT_TRACE_URB - | OZ_TRACE_URB -#endif /* WANT_TRACE_URB */ - -#ifdef WANT_TRACE_CTRL_DETAIL - | OZ_TRACE_CTRL_DETAIL -#endif /* WANT_TRACE_CTRL_DETAIL */ - -#ifdef WANT_TRACE_HUB - | OZ_TRACE_HUB -#endif /* WANT_TRACE_HUB */ - -#ifdef WANT_TRACE_RX_FRAMES - | OZ_TRACE_RX_FRAMES -#endif /* WANT_TRACE_RX_FRAMES */ - -#ifdef WANT_TRACE_TX_FRAMES - | OZ_TRACE_TX_FRAMES -#endif /* WANT_TRACE_TX_FRAMES */ - ; -#endif /* WANT_VERBOSE_TRACE */ +#define OZ_TRACE_DUMP_SKB_LEN_MAX 32 +#define OZ_TRACE_DUMP_URB_LEN_MAX 16 +u32 g_debug = +#ifdef WANT_TRACE_DATA_FLOW + TRC_M|TRC_R|TRC_T|TRC_S|TRC_E|TRC_C; +#else + 0; +#endif + +void (*func[]) (char *fmt, va_list arg) = { + trace_hcd_msg_evt, + trace_isoc_msg_evt, + trace_info_msg_evt +}; + +void oz_dump_data(char *buf, unsigned char *data, int len, int lmt) +{ + int i = 0; + if (len > lmt) + len = lmt; + while (len--) { + *buf = (*data>>4) + '0'; + if (*data > (0xA0-1)) + *buf += 'A' - '9' - 1; + *++buf = (*data++&0xF) + '0'; + if (*buf > '9') + *buf += 'A' - '9' - 1; + if (buf++ && !(++i%4)) + *buf++ = ' '; + } + *buf++ = '\n'; + *buf = 0; +} + +void oz_trace_f_urb_in(struct urb *urb) +{ + int i = 0; + char buf[128*2]; + int endpoint = usb_pipeendpoint(urb->pipe); + + if (usb_pipein(urb->pipe)) + endpoint |= 0x80; + + if (endpoint == 0x00 || endpoint == 0x80) { + i += sprintf(&buf[i], "OZ S %08X %02X %02X ", + (unsigned int)((uintptr_t)urb), endpoint, + urb->transfer_buffer_length); + + oz_dump_data(&buf[i], urb->setup_packet, 8, 8); + + } else { + i += sprintf(&buf[i], "OZ S %08X %02X %02X ", + (unsigned int)((uintptr_t)urb), endpoint, + urb->transfer_buffer_length); + if (!usb_pipein(urb->pipe)) { + oz_dump_data(&buf[i], (u8 *)(urb->transfer_buffer), + urb->transfer_buffer_length, + OZ_TRACE_DUMP_URB_LEN_MAX); + + } else { + oz_dump_data(&buf[i], NULL, 0, 0); + } + + } + printk(buf); +} + +void oz_trace_f_urb_out(struct urb *urb, int status) +{ + int i = 0; + char buf[128*2]; + int endpoint = usb_pipeendpoint(urb->pipe); + int length = urb->actual_length; + + if (usb_pipeisoc(urb->pipe)) + length = urb->transfer_buffer_length; + + if (usb_pipein(urb->pipe)) + endpoint |= 0x80; + + if (status != 0) { + printk("OZ E %08X %08X\n", + (unsigned int)((uintptr_t)urb), status); + } else { + i += sprintf(&buf[i], "OZ C %08X %02X %02X ", + (unsigned int)((uintptr_t)urb), + endpoint, urb->actual_length); + + if (usb_pipein(urb->pipe)) { + oz_dump_data(&buf[i], + (u8 *)(urb->transfer_buffer), + urb->actual_length, + OZ_TRACE_DUMP_URB_LEN_MAX); + } else { + oz_dump_data(&buf[i], NULL, 0, 0); + } + printk(buf); + } +} + +void oz_trace_f_skb(struct sk_buff *skb, char dir) +{ + int i = 0; + char buf[128*2]; + int len = skb->len; + + if (dir == 'T') + len -= 14; + + i += sprintf(&buf[i], "OZ %c %04X ", dir, len); + oz_dump_data(&buf[i], (u8 *)skb_network_header(skb), + len, OZ_TRACE_DUMP_SKB_LEN_MAX); + printk(buf); +} + +void oz_trace_f_dbg(void) +{ +} + +void trace_dbg_msg(int c, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + func[c](fmt, arg); + va_end(arg); +} + +void trace_debug_log(char *log_type, ...) +{ + va_list arg; + char *fmt; + + va_start(arg, log_type); + fmt = va_arg(arg, char *); + switch (*log_type) { + case 'H': + trace_hcd_msg_evt(fmt, arg); + break; + case 'I': + trace_isoc_msg_evt(fmt, arg); + break; + default: + trace_info_msg_evt(fmt, arg); + break; + } + va_end(arg); +} diff --git a/drivers/staging/ozwpan/oztrace.h b/drivers/staging/ozwpan/oztrace.h index 8293b24c5a77..fe1322104c49 100644 --- a/drivers/staging/ozwpan/oztrace.h +++ b/drivers/staging/ozwpan/oztrace.h @@ -5,31 +5,93 @@ */ #ifndef _OZTRACE_H_ #define _OZTRACE_H_ -#include "ozconfig.h" - -#define TRACE_PREFIX KERN_ALERT "OZWPAN: " - -#ifdef WANT_TRACE -#define oz_trace(...) printk(TRACE_PREFIX __VA_ARGS__) -#ifdef WANT_VERBOSE_TRACE -extern unsigned long trace_flags; -#define oz_trace2(_flag, ...) \ - do { if (trace_flags & _flag) printk(TRACE_PREFIX __VA_ARGS__); \ - } while (0) -#else -#define oz_trace2(...) -#endif /* #ifdef WANT_VERBOSE_TRACE */ -#else -#define oz_trace(...) -#define oz_trace2(...) -#endif /* #ifdef WANT_TRACE */ - -#define OZ_TRACE_STREAM 0x1 -#define OZ_TRACE_URB 0x2 -#define OZ_TRACE_CTRL_DETAIL 0x4 -#define OZ_TRACE_HUB 0x8 -#define OZ_TRACE_RX_FRAMES 0x10 -#define OZ_TRACE_TX_FRAMES 0x20 +#include <linux/usb.h> +#include <linux/netdevice.h> +#include "ozeventtrace.h" + +extern struct device *g_oz_wpan_dev; + +#define oz_trace(fmt, ...) \ + do { dev_dbg(g_oz_wpan_dev, fmt, ##__VA_ARGS__); } while (0) + +void oz_trace_f_urb_out(struct urb *urb, int status); +void oz_trace_f_urb_in(struct urb *urb); +void oz_trace_f_skb(struct sk_buff *skb, char dir); +void oz_trace_f_dbg(void); +void trace_dbg_msg(int c, char *fmt, ...); +void trace_debug_log(char *log_type, ...); + +extern u32 g_debug; + +#define TRC_A 0x00000001 +#define TRC_B 0x00000002 +#define TRC_C 0x00000004 /* urb Completion */ +#define TRC_D 0x00000008 /* Debug */ +#define TRC_E 0x00000010 /* urb Error */ +#define TRC_F 0x00000020 +#define TRC_G 0x00000040 +#define TRC_H 0x00000080 /* Hcd message */ +#define TRC_I 0x00000100 /* Isoc buffer depth */ +#define TRC_J 0x00000200 +#define TRC_K 0x00000400 +#define TRC_L 0x00000800 +#define TRC_M 0x00001000 /* Message */ +#define TRC_N 0x00002000 +#define TRC_O 0x00004000 +#define TRC_P 0x00008000 +#define TRC_Q 0x00010000 +#define TRC_R 0x00020000 /* Rx Ozmo frame */ +#define TRC_S 0x00040000 /* urb Submission */ +#define TRC_T 0x00080000 /* Tx ozmo frame */ +#define TRC_U 0x00100000 +#define TRC_V 0x00200000 +#define TRC_W 0x00400000 +#define TRC_X 0x00800000 +#define TRC_Y 0x01000000 +#define TRC_Z 0x02000000 + + +#define oz_trace_urb_out(u, s) \ + do { if (!g_debug) \ + trace_urb_out(u, s); \ + else if ((g_debug & TRC_C) || ((g_debug & TRC_E) && (u->status != 0))) \ + oz_trace_f_urb_out(u, s); } while (0) + +#define oz_trace_urb_in(u) \ + do { if (!g_debug) \ + trace_urb_in(u); \ + else if (g_debug & TRC_S) \ + oz_trace_f_urb_in(u); } while (0) + +#define oz_trace_skb(u, d) \ + do { if ((!g_debug) && ('T' == d)) \ + trace_tx_frame(u); \ + else if ((!g_debug) && ('R' == d)) \ + trace_rx_frame(u); \ + else if ((('T' == d) && (g_debug & TRC_T)) || \ + (('R' == d) && (g_debug & TRC_R))) \ + oz_trace_f_skb(u, d); } while(0) + +#define oz_trace_msg(f, ...) \ + do { if (!g_debug) \ + trace_debug_log(#f, __VA_ARGS__); \ + else if (g_debug & TRC_##f) \ + printk("OZ " #f " " __VA_ARGS__); } while(0) + +enum { + TRACE_HCD_MSG, + TRACE_ISOC_MSG, + TRACE_INFO_MSG +}; + +#define trace_hcd_msg(fmt, ...)\ + trace_dbg_msg(TRACE_HCD_MSG, fmt, ##__VA_ARGS__) + +#define trace_isoc_msg(fmt, ...)\ + trace_dbg_msg(TRACE_ISOC_MSG, fmt, ##__VA_ARGS__) + +#define trace_info_msg(fmt, ...)\ + trace_dbg_msg(TRACE_INFO_MSG, fmt, ##__VA_ARGS__) #endif /* Sentry */ diff --git a/drivers/staging/ozwpan/ozurbparanoia.c b/drivers/staging/ozwpan/ozurbparanoia.c index 55b9afbbe47b..b05519534444 100644 --- a/drivers/staging/ozwpan/ozurbparanoia.c +++ b/drivers/staging/ozwpan/ozurbparanoia.c @@ -4,7 +4,6 @@ * ----------------------------------------------------------------------------- */ #include <linux/usb.h> -#include "ozconfig.h" #ifdef WANT_URB_PARANOIA #include "ozurbparanoia.h" #include "oztrace.h" @@ -22,7 +21,7 @@ void oz_remember_urb(struct urb *urb) spin_lock_irqsave(&g_urb_mem_lock, irq_state); if (g_nb_urbs < OZ_MAX_URBS) { g_urb_memory[g_nb_urbs++] = urb; - oz_trace("%lu: urb up = %d %p\n", jiffies, g_nb_urbs, urb); + oz_trace("urb up = %d %p\n", g_nb_urbs, urb); } else { oz_trace("ERROR urb buffer full\n"); } @@ -42,8 +41,8 @@ int oz_forget_urb(struct urb *urb) if (--g_nb_urbs > i) memcpy(&g_urb_memory[i], &g_urb_memory[i+1], (g_nb_urbs - i) * sizeof(struct urb *)); - oz_trace("%lu: urb down = %d %p\n", - jiffies, g_nb_urbs, urb); + oz_trace("urb down = %d %p\n", + g_nb_urbs, urb); } } spin_unlock_irqrestore(&g_urb_mem_lock, irq_state); diff --git a/drivers/staging/ozwpan/ozusbif.h b/drivers/staging/ozwpan/ozusbif.h index 3acf5980d7cc..7c59b22f8b9f 100644 --- a/drivers/staging/ozwpan/ozusbif.h +++ b/drivers/staging/ozwpan/ozusbif.h @@ -34,10 +34,16 @@ void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data, int data_len); +void oz_hcd_mark_urb_submitted(void *hport, int ep_ix, u8 req_id); + /* Indication functions. */ void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len); int oz_hcd_heartbeat(void *hport); +/* Get information. + */ +u8 oz_get_up_max_buffer_units(void *hpd); + #endif /* _OZUSBIF_H */ diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c index 9e74f9602384..3dae52f0af18 100644 --- a/drivers/staging/ozwpan/ozusbsvc.c +++ b/drivers/staging/ozwpan/ozusbsvc.c @@ -7,7 +7,7 @@ * The implementation of this service is split into two parts the first of which * is protocol independent and the second contains protocol specific details. * This split is to allow alternative protocols to be defined. - * The implemenation of this service uses ozhcd.c to implement a USB HCD. + * The implementation of this service uses ozhcd.c to implement a USB HCD. * ----------------------------------------------------------------------------- */ #include <linux/init.h> @@ -18,7 +18,6 @@ #include <linux/errno.h> #include <linux/input.h> #include <asm/unaligned.h> -#include "ozconfig.h" #include "ozprotocol.h" #include "ozeltbuf.h" #include "ozpd.h" @@ -27,14 +26,12 @@ #include "ozhcd.h" #include "oztrace.h" #include "ozusbsvc.h" -#include "ozevent.h" /*------------------------------------------------------------------------------ * This is called once when the driver is loaded to initialise the USB service. * Context: process */ int oz_usb_init(void) { - oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_USB, 0, 0); return oz_hcd_init(); } /*------------------------------------------------------------------------------ @@ -43,7 +40,6 @@ int oz_usb_init(void) */ void oz_usb_term(void) { - oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_USB, 0, 0); oz_hcd_term(); } /*------------------------------------------------------------------------------ @@ -55,7 +51,6 @@ int oz_usb_start(struct oz_pd *pd, int resume) int rc = 0; struct oz_usb_ctx *usb_ctx; struct oz_usb_ctx *old_ctx = 0; - oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_USB, 0, resume); if (resume) { oz_trace("USB service resumed.\n"); return 0; @@ -81,7 +76,6 @@ int oz_usb_start(struct oz_pd *pd, int resume) oz_usb_get(pd->app_ctx[OZ_APPID_USB-1]); spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); if (old_ctx) { - oz_trace("Already have USB context.\n"); kfree(usb_ctx); usb_ctx = old_ctx; } else if (usb_ctx) { @@ -99,7 +93,6 @@ int oz_usb_start(struct oz_pd *pd, int resume) } else { usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx); if (usb_ctx->hport == 0) { - oz_trace("USB hub returned null port.\n"); spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]); pd->app_ctx[OZ_APPID_USB-1] = 0; spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); @@ -117,7 +110,6 @@ int oz_usb_start(struct oz_pd *pd, int resume) void oz_usb_stop(struct oz_pd *pd, int pause) { struct oz_usb_ctx *usb_ctx; - oz_event_log(OZ_EVT_SERVICE, 4, OZ_APPID_USB, 0, pause); if (pause) { oz_trace("USB service paused.\n"); return; @@ -127,7 +119,8 @@ void oz_usb_stop(struct oz_pd *pd, int pause) pd->app_ctx[OZ_APPID_USB-1] = 0; spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); if (usb_ctx) { - unsigned long tout = jiffies + HZ; + struct timespec ts, now; + getnstimeofday(&ts); oz_trace("USB service stopping...\n"); usb_ctx->stopped = 1; /* At this point the reference count on the usb context should @@ -136,10 +129,13 @@ void oz_usb_stop(struct oz_pd *pd, int pause) * should get in but someone may already be in. So wait * until they leave but timeout after 1 second. */ - while ((atomic_read(&usb_ctx->ref_count) > 2) && - time_before(jiffies, tout)) - ; - oz_trace("USB service stopped.\n"); + while ((atomic_read(&usb_ctx->ref_count) > 2)) { + getnstimeofday(&now); + /*Approx 1 Sec. this is not perfect calculation*/ + if (now.tv_sec != ts.tv_sec) + break; + } + oz_trace_msg(M, "USB service stopped.\n"); oz_hcd_pd_departed(usb_ctx->hport); /* Release the reference taken in oz_usb_start. */ @@ -165,7 +161,6 @@ void oz_usb_put(void *hpd) { struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; if (atomic_dec_and_test(&usb_ctx->ref_count)) { - oz_trace("Dealloc USB context.\n"); oz_pd_put(usb_ctx->pd); kfree(usb_ctx); } @@ -200,7 +195,6 @@ int oz_usb_stream_create(void *hpd, u8 ep_num) { struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; struct oz_pd *pd = usb_ctx->pd; - oz_trace("oz_usb_stream_create(0x%x)\n", ep_num); if (pd->mode & OZ_F_ISOC_NO_ELTS) { oz_isoc_stream_create(pd, ep_num); } else { @@ -222,7 +216,6 @@ int oz_usb_stream_delete(void *hpd, u8 ep_num) if (usb_ctx) { struct oz_pd *pd = usb_ctx->pd; if (pd) { - oz_trace("oz_usb_stream_delete(0x%x)\n", ep_num); if (pd->mode & OZ_F_ISOC_NO_ELTS) { oz_isoc_stream_delete(pd, ep_num); } else { diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c index 66bd576bb5e9..a66d2adca434 100644 --- a/drivers/staging/ozwpan/ozusbsvc1.c +++ b/drivers/staging/ozwpan/ozusbsvc1.c @@ -13,7 +13,6 @@ #include <linux/errno.h> #include <linux/input.h> #include <asm/unaligned.h> -#include "ozconfig.h" #include "ozprotocol.h" #include "ozeltbuf.h" #include "ozpd.h" @@ -22,10 +21,24 @@ #include "ozhcd.h" #include "oztrace.h" #include "ozusbsvc.h" -#include "ozevent.h" /*------------------------------------------------------------------------------ */ #define MAX_ISOC_FIXED_DATA (253-sizeof(struct oz_isoc_fixed)) + +/*------------------------------------------------------------------------------ + * Context: softirq + */ +static void oz_usb_setup_elt_completion_callback(struct oz_pd *pd, long context) +{ + struct oz_usb_ctx *ctx; + spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]); + ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1]; + if (ctx) { + u8 req_id = (u8)context; + oz_hcd_mark_urb_submitted(ctx->hport, 0, req_id); + } + spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); +} /*------------------------------------------------------------------------------ * Context: softirq */ @@ -63,16 +76,12 @@ int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type, struct oz_get_desc_req *body; struct oz_elt_buf *eb = &pd->elt_buff; struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); - oz_trace(" req_type = 0x%x\n", req_type); - oz_trace(" desc_type = 0x%x\n", desc_type); - oz_trace(" index = 0x%x\n", index); - oz_trace(" windex = 0x%x\n", windex); - oz_trace(" offset = 0x%x\n", offset); - oz_trace(" len = 0x%x\n", len); if (len > 200) len = 200; if (ei == 0) return -1; + ei->callback = oz_usb_setup_elt_completion_callback; + ei->context = req_id; elt = (struct oz_elt *)ei->data; elt->length = sizeof(struct oz_get_desc_req); body = (struct oz_get_desc_req *)(elt+1); @@ -99,6 +108,8 @@ static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index) struct oz_set_config_req *body; if (ei == 0) return -1; + ei->callback = oz_usb_setup_elt_completion_callback; + ei->context = req_id; elt = (struct oz_elt *)ei->data; elt->length = sizeof(struct oz_set_config_req); body = (struct oz_set_config_req *)(elt+1); @@ -120,6 +131,8 @@ static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt) struct oz_set_interface_req *body; if (ei == 0) return -1; + ei->callback = oz_usb_setup_elt_completion_callback; + ei->context = req_id; elt = (struct oz_elt *)ei->data; elt->length = sizeof(struct oz_set_interface_req); body = (struct oz_set_interface_req *)(elt+1); @@ -144,6 +157,8 @@ static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type, if (ei == 0) return -1; elt = (struct oz_elt *)ei->data; + ei->callback = oz_usb_setup_elt_completion_callback; + ei->context = req_id; elt->length = sizeof(struct oz_feature_req); body = (struct oz_feature_req *)(elt+1); body->type = type; @@ -167,6 +182,8 @@ static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type, struct oz_vendor_class_req *body; if (ei == 0) return -1; + ei->callback = oz_usb_setup_elt_completion_callback; + ei->context = req_id; elt = (struct oz_elt *)ei->data; elt->length = sizeof(struct oz_vendor_class_req) - 1 + data_len; body = (struct oz_vendor_class_req *)(elt+1); @@ -190,10 +207,7 @@ int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup, unsigned windex = le16_to_cpu(setup->wIndex); unsigned wlength = le16_to_cpu(setup->wLength); int rc = 0; - oz_event_log(OZ_EVT_CTRL_REQ, setup->bRequest, req_id, - (void *)(((unsigned long)(setup->wValue))<<16 | - ((unsigned long)setup->wIndex)), - setup->bRequestType); + if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (setup->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -381,7 +395,6 @@ void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt) u16 offs = le16_to_cpu(get_unaligned(&body->offset)); u16 total_size = le16_to_cpu(get_unaligned(&body->total_size)); - oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n"); oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id, body->rcode, body->data, data_len, offs, total_size); @@ -435,3 +448,11 @@ void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len) } oz_usb_put(usb_ctx); } +/*------------------------------------------------------------------------------ + * Context: softirq or process + */ +u8 oz_get_up_max_buffer_units(void *hpd) +{ + struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; + return usb_ctx->pd->up_audio_buf; +} |