ozcdev.o \
ozurbparanoia.o \
oztrace.o \
- ozevent.o
+ ozkobject.o
To operate the driver must be bound to a suitable network interface. This can
be done when the module is loaded (specifying the name of the network interface
-as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
+as a paramter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
loading using an ioctl call. See the ozappif.h file and the ioctls
OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING.
TODO:
- - Convert event tracing code to in-kernel tracing infrastructure
- - Check for remaining ioctl & check if that can be converted into
- sysfs entries
- - Convert debug prints to appropriate dev_debug or something better
- - Modify Kconfig to add CONFIG option for enabling/disabling event
- tracing.
+ - review user mode interface and determine if ioctls can be replaced
+ with something better. correctly export data structures to user mode
+ if ioctls are still required and allocate ioctl numbers from
+ ioctl-number.txt.
- check USB HCD implementation is complete and correct.
+ - remove any debug and trace code.
- code review by USB developer community.
- testing with as many devices as possible.
Please send any patches for this driver to
-Rupesh Gujare <rupesh.gujare@atmel.com>
+Rupesh Gujare <rgujare@ozmodevices.com>
+Chris Kelly <ckelly@ozmodevices.com>
and Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
#ifndef _OZAPPIF_H
#define _OZAPPIF_H
-#include "ozeventdef.h"
-
#define OZ_IOCTL_MAGIC 0xf4
struct oz_mac_addr {
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/netdevice.h>
-#include <linux/etherdevice.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 "ozcdev.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;
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. */
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;
};
/*------------------------------------------------------------------------------
*/
static struct oz_cdev g_cdev;
-static struct class *g_oz_class;
+struct class *g_oz_class;
+struct device *g_oz_wpan_dev;
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+
+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
*/
*/
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);
}
/*------------------------------------------------------------------------------
* Context: process
*/
-static int oz_cdev_open(struct inode *inode, struct file *filp)
+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;
/*------------------------------------------------------------------------------
* Context: process
*/
-static int oz_cdev_release(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;
}
/*------------------------------------------------------------------------------
* Context: process
*/
-static ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count,
+ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count,
loff_t *fpos)
{
int n;
int ix;
-
+ int is_tftp;
struct oz_pd *pd;
- struct oz_serial_ctx *ctx;
+ struct oz_serial_ctx *ctx = 0;
spin_lock_bh(&g_cdev.lock);
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 == NULL)
+ if (pd == 0)
return -1;
ctx = oz_cdev_claim_ctx(pd);
- if (ctx == NULL)
+ 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:
/*------------------------------------------------------------------------------
* Context: process
*/
-static ssize_t oz_cdev_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *fpos)
+ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *fpos)
{
struct oz_pd *pd;
struct oz_elt_buf *eb;
- struct oz_elt_info *ei;
+ 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;
if (pd)
oz_pd_get(pd);
spin_unlock_bh(&g_cdev.lock);
- if (pd == NULL)
+ 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 == NULL) {
+ 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 = NULL;
+ 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;
/*------------------------------------------------------------------------------
* Context: process
*/
-static int oz_set_active_pd(const 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 (is_zero_ether_addr(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 = NULL;
+ g_cdev.active_pd = 0;
memset(g_cdev.active_addr, 0,
sizeof(g_cdev.active_addr));
spin_unlock_bh(&g_cdev.lock);
/*------------------------------------------------------------------------------
* Context: process
*/
-static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
+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;
if (_IOC_TYPE(cmd) != OZ_IOCTL_MAGIC)
switch (cmd) {
case OZ_IOCTL_GET_PD_LIST: {
struct oz_pd_list list;
- oz_trace("OZ_IOCTL_GET_PD_LIST\n");
- memset(&list, 0, sizeof(list));
list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS);
if (copy_to_user((void __user *)arg, &list,
sizeof(list)))
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);
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);
/*------------------------------------------------------------------------------
* Context: process
*/
-static unsigned int oz_cdev_poll(struct file *filp, poll_table *wait)
+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;
}
/*------------------------------------------------------------------------------
*/
-static const struct file_operations oz_fops = {
+const struct file_operations oz_fops = {
.owner = THIS_MODULE,
.open = oz_cdev_open,
.release = oz_cdev_release,
int oz_cdev_register(void)
{
int err;
- struct device *dev;
memset(&g_cdev, 0, sizeof(g_cdev));
err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan");
if (err < 0)
goto out3;
- oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum),
- MINOR(g_cdev.devnum));
cdev_init(&g_cdev.cdev, &oz_fops);
g_cdev.cdev.owner = THIS_MODULE;
g_cdev.cdev.ops = &oz_fops;
oz_trace("Failed to register ozmo_wpan class\n");
goto out1;
}
- dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan");
- if (IS_ERR(dev)) {
+ 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);
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);
}
*/
int oz_cdev_init(void)
{
- oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_SERIAL, NULL, 0);
oz_app_enable(OZ_APPID_SERIAL, 1);
return 0;
}
*/
void oz_cdev_term(void)
{
- oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_SERIAL, NULL, 0);
oz_app_enable(OZ_APPID_SERIAL, 0);
}
/*------------------------------------------------------------------------------
int oz_cdev_start(struct oz_pd *pd, int resume)
{
struct oz_serial_ctx *ctx;
- struct oz_serial_ctx *old_ctx;
- oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_SERIAL, NULL, resume);
+ struct oz_serial_ctx *old_ctx = 0;
if (resume) {
oz_trace("Serial service resumed.\n");
return 0;
}
ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
- if (ctx == NULL)
+ if (ctx == 0)
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) {
spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
}
spin_lock(&g_cdev.lock);
- if ((g_cdev.active_pd == NULL) &&
+ if ((g_cdev.active_pd == 0) &&
(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");
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, NULL, pause);
if (pause) {
oz_trace("Serial service paused.\n");
return;
}
spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1];
- pd->app_ctx[OZ_APPID_SERIAL-1] = NULL;
+ pd->app_ctx[OZ_APPID_SERIAL-1] = 0;
spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
if (ctx)
oz_cdev_release_ctx(ctx);
spin_lock(&g_cdev.lock);
if (pd == g_cdev.active_pd)
- g_cdev.active_pd = NULL;
+ g_cdev.active_pd = 0;
else
- pd = NULL;
+ pd = 0;
spin_unlock(&g_cdev.lock);
if (pd) {
oz_pd_put(pd);
- oz_trace("Active PD departed.\n");
}
oz_trace("Serial service stopped.\n");
}
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 == NULL) {
+ if (ctx == 0) {
oz_trace("Cannot claim serial context.\n");
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) {
}
}
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;
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)
ix = len;
}
ctx->rd_in = ix;
+ spin_unlock_bh(&ctx->rd_lock);
wake_up(&g_cdev.rdq);
out:
oz_cdev_release_ctx(ctx);
}
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_cdev_heartbeat(struct oz_pd *pd)
+{
+}
#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);
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 */
+++ /dev/null
-/* -----------------------------------------------------------------------------
- * 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 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include "ozconfig.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
*/
struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf)
{
- struct oz_elt_info *ei = NULL;
+ struct oz_elt_info *ei = 0;
spin_lock_bh(&buf->lock);
if (buf->free_elts && buf->elt_pool) {
ei = container_of(buf->elt_pool, struct oz_elt_info, link);
if (ei) {
ei->flags = 0;
ei->app_id = 0;
- ei->callback = NULL;
+ ei->callback = 0;
ei->context = 0;
- ei->stream = NULL;
+ ei->stream = 0;
ei->magic = OZ_ELT_INFO_MAGIC_USED;
INIT_LIST_HEAD(&ei->link);
INIT_LIST_HEAD(&ei->link_order);
{
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 == NULL)
+ if (st == 0)
return -ENOMEM;
atomic_set(&st->ref_count, 1);
st->id = id;
int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id)
{
struct list_head *e;
- struct oz_elt_stream *st = NULL;
- oz_trace("oz_elt_stream_delete(0x%x)\n", id);
+ struct oz_elt_stream *st;
+
spin_lock_bh(&buf->lock);
e = buf->stream_list.next;
while (e != &buf->stream_list) {
list_del(e);
break;
}
- st = NULL;
+ st = 0;
}
if (!st) {
spin_unlock_bh(&buf->lock);
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);
}
int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id,
struct oz_elt_info *ei)
{
- struct oz_elt_stream *st = NULL;
+ struct oz_elt_stream *st = 0;
struct list_head *e;
if (id) {
list_for_each(e, &buf->stream_list) {
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.
*/
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;
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 = NULL;
+ ei->stream = 0;
}
INIT_LIST_HEAD(&ei->link_order);
list_add_tail(&ei->link, list);
*/
void oz_trim_elt_pool(struct oz_elt_buf *buf)
{
- struct list_head *free = NULL;
+ struct list_head *free = 0;
struct list_head *e;
spin_lock_bh(&buf->lock);
while (buf->free_elts > buf->max_free_elts) {
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;
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;
+++ /dev/null
-/* -----------------------------------------------------------------------------
- * Copyright (c) 2011 Ozmo Inc
- * Released under the GNU General Public License Version 2 (GPLv2).
- * -----------------------------------------------------------------------------
- */
-#include "ozconfig.h"
-#ifdef WANT_EVENT_TRACE
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-#include "oztrace.h"
-#include "ozevent.h"
-#include "ozappif.h"
-/*------------------------------------------------------------------------------
- * Although the event mask is logically part of the oz_evtdev structure, it is
- * needed outside of this file so define it separately to avoid the need to
- * export definition of struct oz_evtdev.
- */
-u32 g_evt_mask;
-/*------------------------------------------------------------------------------
- */
-#define OZ_MAX_EVTS 2048 /* Must be power of 2 */
-struct oz_evtdev {
- struct dentry *root_dir;
- int evt_in;
- int evt_out;
- int missed_events;
- int present;
- atomic_t users;
- spinlock_t lock;
- struct oz_event evts[OZ_MAX_EVTS];
-};
-
-static struct oz_evtdev g_evtdev;
-
-/*------------------------------------------------------------------------------
- * Context: process
- */
-void oz_event_init(void)
-{
- /* Because g_evtdev is static external all fields initially zero so no
- * need to reinitialized those.
- */
- oz_trace("Event tracing initialized\n");
- spin_lock_init(&g_evtdev.lock);
- atomic_set(&g_evtdev.users, 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_evtdev.lock, irqstate);
- ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1);
- if (ix != g_evtdev.evt_out) {
- struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in];
- e->jiffies = jiffies;
- e->evt = evt;
- e->ctx1 = ctx1;
- e->ctx2 = ctx2;
- e->ctx3 = (__u32)(unsigned long)ctx3;
- e->ctx4 = ctx4;
- g_evtdev.evt_in = ix;
- } else {
- g_evtdev.missed_events++;
- }
- spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
-}
-/*------------------------------------------------------------------------------
- * Context: process
- */
-#ifdef CONFIG_DEBUG_FS
-static void oz_events_clear(struct oz_evtdev *dev)
-{
- unsigned long irqstate;
- oz_trace("Clearing events\n");
- spin_lock_irqsave(&dev->lock, irqstate);
- dev->evt_in = dev->evt_out = 0;
- dev->missed_events = 0;
- spin_unlock_irqrestore(&dev->lock, irqstate);
-}
-/*------------------------------------------------------------------------------
- * Context: process
- */
-static int oz_events_open(struct inode *inode, struct file *filp)
-{
- oz_trace("oz_evt_open()\n");
- oz_trace("Open flags: 0x%x\n", filp->f_flags);
- if (atomic_add_return(1, &g_evtdev.users) == 1) {
- oz_events_clear(&g_evtdev);
- return nonseekable_open(inode, filp);
- } else {
- atomic_dec(&g_evtdev.users);
- return -EBUSY;
- }
-}
-/*------------------------------------------------------------------------------
- * Context: process
- */
-static int oz_events_release(struct inode *inode, struct file *filp)
-{
- oz_events_clear(&g_evtdev);
- atomic_dec(&g_evtdev.users);
- g_evt_mask = 0;
- oz_trace("oz_evt_release()\n");
- return 0;
-}
-/*------------------------------------------------------------------------------
- * Context: process
- */
-static ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
- loff_t *fpos)
-{
- struct oz_evtdev *dev = &g_evtdev;
- int rc = 0;
- int nb_evts = count / sizeof(struct oz_event);
- int n;
- int sz;
-
- n = dev->evt_in - dev->evt_out;
- if (n < 0)
- n += OZ_MAX_EVTS;
- if (nb_evts > n)
- nb_evts = n;
- if (nb_evts == 0)
- goto out;
- n = OZ_MAX_EVTS - dev->evt_out;
- if (n > nb_evts)
- n = nb_evts;
- sz = n * sizeof(struct oz_event);
- if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) {
- rc = -EFAULT;
- goto out;
- }
- if (n == nb_evts)
- goto out2;
- n = nb_evts - n;
- if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) {
- rc = -EFAULT;
- goto out;
- }
-out2:
- dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
- rc = nb_evts * sizeof(struct oz_event);
-out:
- return rc;
-}
-/*------------------------------------------------------------------------------
- */
-static const struct file_operations oz_events_fops = {
- .owner = THIS_MODULE,
- .open = oz_events_open,
- .release = oz_events_release,
- .read = oz_events_read,
-};
-/*------------------------------------------------------------------------------
- * Context: process
- */
-void oz_debugfs_init(void)
-{
- struct dentry *parent;
-
- parent = debugfs_create_dir("ozwpan", NULL);
- if (parent == NULL) {
- oz_trace("Failed to create debugfs directory ozmo\n");
- return;
- } else {
- g_evtdev.root_dir = parent;
- if (debugfs_create_file("events", S_IRUSR, parent, NULL,
- &oz_events_fops) == NULL)
- oz_trace("Failed to create file ozmo/events\n");
- if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent,
- &g_evt_mask) == NULL)
- oz_trace("Failed to create file ozmo/event_mask\n");
- }
-}
-/*------------------------------------------------------------------------------
- * Context: process
- */
-void oz_debugfs_remove(void)
-{
- debugfs_remove_recursive(g_evtdev.root_dir);
-}
-#endif /* CONFIG_DEBUG_FS */
-#endif /* WANT_EVENT_TRACE */
+++ /dev/null
-/* -----------------------------------------------------------------------------
- * 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 u32 g_evt_mask;
-void oz_event_init(void);
-void oz_event_term(void);
-void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
-void oz_debugfs_init(void);
-void oz_debugfs_remove(void);
-#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)
-
-#else
-#define oz_event_init()
-#define oz_event_term()
-#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4)
-#define oz_debugfs_init()
-#define oz_debugfs_remove()
-#endif /* WANT_EVENT_TRACE */
-
-#endif /* _OZEVENT_H */
+++ /dev/null
-/* -----------------------------------------------------------------------------
- * 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 {
- __u32 jiffies;
- __u8 evt;
- __u8 ctx1;
- __u16 ctx2;
- __u32 ctx3;
- __u32 ctx4;
-};
-
-#endif /* _OZEVENTDEF_H */
--- /dev/null
+/* -----------------------------------------------------------------------------
+ * 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>
*/
#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"
-#include "ozhcd.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"
/* 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.
struct oz_port *port;
u8 req_id;
u8 ep_num;
- unsigned long submit_jiffies;
+ unsigned submit_counter;
};
/* Holds state information about a USB 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;
int in_ix;
int out_ix;
int buffered_units;
+ u8 max_buffer_units;
unsigned flags;
int start_frame;
};
#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 {
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",
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;
}
*/
static struct oz_urb_link *oz_alloc_urb_link(void)
{
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl = 0;
unsigned long irq_state;
spin_lock_irqsave(&g_link_lock, irq_state);
if (g_link_pool) {
--g_link_pool_size;
}
spin_unlock_irqrestore(&g_link_lock, irq_state);
- if (urbl == NULL)
+ if (urbl == 0)
urbl = kmalloc(sizeof(struct oz_urb_link), GFP_ATOMIC);
return urbl;
}
if (g_link_pool_size < OZ_MAX_LINK_POOL_SIZE) {
urbl->link.next = g_link_pool;
g_link_pool = &urbl->link;
- urbl = NULL;
+ urbl = 0;
g_link_pool_size++;
}
spin_unlock_irqrestore(&g_link_lock, irq_state);
- kfree(urbl);
+ if (urbl)
+ kfree(urbl);
}
}
/*------------------------------------------------------------------------------
unsigned long irq_state;
spin_lock_irqsave(&g_link_lock, irq_state);
e = g_link_pool;
- g_link_pool = NULL;
+ g_link_pool = 0;
g_link_pool_size = 0;
spin_unlock_irqrestore(&g_link_lock, irq_state);
while (e) {
* disabled.
* Context: softirq or process
*/
-static struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb)
+struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, struct urb *urb)
{
struct oz_urb_link *urbl;
struct list_head *e;
return urbl;
}
}
- return NULL;
+ return 0;
}
/*------------------------------------------------------------------------------
* This is called when we have finished processing an urb. It unlinks it from
* 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 = NULL;
+ 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.
*/
- urb->hcpriv = NULL;
+ urb->hcpriv = 0;
/* Walk the cancel list in case the urb is already sitting there.
* Since we process the cancel list in a tasklet rather than in
* the dequeue function this could happen.
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);
*/
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;
list_splice_tail(&list, &ozhcd->orphanage);
spin_unlock_bh(&ozhcd->hcd_lock);
}
- oz_trace("Freeing endpoint memory\n");
kfree(ep);
}
/*------------------------------------------------------------------------------
* Context: softirq
*/
-static void oz_complete_buffered_urb(struct oz_port *port,
- struct oz_endpoint *ep,
+void oz_complete_buffered_urb(struct oz_port *port, struct oz_endpoint *ep,
struct urb *urb)
{
- u8 data_len, available_space, copy_len;
+ int data_len, available_space, copy_len;
- memcpy(&data_len, &ep->buffer[ep->out_ix], sizeof(u8));
+ data_len = ep->buffer[ep->out_ix];
if (data_len <= urb->transfer_buffer_length)
available_space = data_len;
else
ep->out_ix = 0;
ep->buffered_units--;
- oz_trace("Trying to give back buffered frame of size=%d\n",
- available_space);
- oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+ oz_complete_urb(port->ozhcd->hcd, urb, 0);
}
/*------------------------------------------------------------------------------
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;
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 && 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, NULL, ep->credit);
}
} else {
err = -EPIPE;
}
+out:
spin_unlock_bh(&port->ozhcd->hcd_lock);
if (err)
oz_free_urb_link(urbl);
static int oz_dequeue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
struct urb *urb)
{
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl = 0;
struct oz_endpoint *ep;
spin_lock_bh(&port->ozhcd->hcd_lock);
if (in_dir)
list_del_init(e);
break;
}
- urbl = NULL;
+ urbl = 0;
}
}
spin_unlock_bh(&port->ozhcd->hcd_lock);
u8 req_id)
{
struct oz_hcd *ozhcd = port->ozhcd;
- struct urb *urb = NULL;
- struct oz_urb_link *urbl = NULL;
+ struct urb *urb = 0;
+ struct oz_urb_link *urbl = 0;
struct oz_endpoint *ep;
spin_lock_bh(&ozhcd->hcd_lock);
oz_free_urb_link(urbl);
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
void *oz_hcd_pd_arrived(void *hpd)
{
int i;
- void *hport = NULL;
- struct oz_hcd *ozhcd = NULL;
+ 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 == NULL)
- return NULL;
+ if (ozhcd == 0)
+ return 0;
/* Allocate an endpoint object in advance (before holding hcd lock) to
* use for out endpoint 0.
*/
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;
- ep = NULL;
- hport = &ozhcd->ports[i];
+ ozhcd->ports[j].out_ep[0] = ep;
+ ep = 0;
+ 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);
}
out:
if (ep) /* ep is non-null if not used. */
- oz_ep_free(NULL, ep);
+ oz_ep_free(0, ep);
oz_hcd_put(ozhcd);
return hport;
}
struct oz_port *port = (struct oz_port *)hport;
struct oz_hcd *ozhcd;
void *hpd;
- struct oz_endpoint *ep = NULL;
+ struct oz_endpoint *ep = 0;
- oz_trace("oz_hcd_pd_departed()\n");
- if (port == NULL) {
- oz_trace("oz_hcd_pd_departed() port = 0\n");
+ oz_trace("%s:\n", __func__);
+ if (port == 0) {
+ oz_trace("%s: port = 0\n", __func__);
return;
}
ozhcd = port->ozhcd;
- if (ozhcd == NULL)
+ if (ozhcd == 0)
return;
/* Check if this is the connection port - if so clear it.
*/
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);
oz_clean_endpoints_for_config(ozhcd->hcd, port);
spin_lock_bh(&port->port_lock);
hpd = port->hpd;
- port->hpd = NULL;
+ 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.
*/
if (port->out_ep[0]) {
ep = port->out_ep[0];
- port->out_ep[0] = NULL;
+ port->out_ep[0] = 0;
}
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);
}
/*------------------------------------------------------------------------------
* Context: softirq
*/
-void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, const u8 *desc,
+void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status, u8 *desc,
int length, int offset, int total_size)
{
struct oz_port *port = (struct oz_port *)hport;
struct urb *urb;
int err = 0;
- oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, NULL, 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;
}
}
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
*/
} else {
rc = -ENOMEM;
}
- oz_complete_urb(hcd, urb, rc, 0);
+ oz_complete_urb(hcd, urb, rc);
}
/*------------------------------------------------------------------------------
* Context: softirq
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
*/
-void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data,
+void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data,
int data_len)
{
struct oz_port *port = (struct oz_port *)hport;
unsigned windex;
unsigned wvalue;
- oz_event_log(OZ_EVT_CTRL_CNF, 0, req_id, NULL, 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;
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,
(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) {
if (data_len <= urb->transfer_buffer_length)
copy_len = data_len;
memcpy(urb->transfer_buffer, data, copy_len);
urb->actual_length = copy_len;
}
- oz_complete_urb(hcd, urb, 0, 0);
+ oz_complete_urb(hcd, urb, 0);
}
}
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-static int oz_hcd_buffer_data(struct oz_endpoint *ep, const u8 *data,
- int data_len)
+static int oz_hcd_buffer_data(struct oz_endpoint *ep, u8 *data, int data_len)
{
int space;
int copy_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;
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len)
+void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len)
{
struct oz_port *port = (struct oz_port *)hport;
struct oz_endpoint *ep;
struct oz_hcd *ozhcd = port->ozhcd;
spin_lock_bh(&ozhcd->hcd_lock);
ep = port->in_ep[endpoint & USB_ENDPOINT_NUMBER_MASK];
- if (ep == NULL)
+ if (ep == 0)
goto done;
switch (ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_INT:
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_trace("buffering frame as URB is not available\n");
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:
*/
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
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.
*/
ep = ep_from_link(e);
if (ep->credit < 0)
continue;
- ep->credit += jiffies_to_msecs(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, NULL,
- 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);
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, NULL,
- ep->credit);
- list_move_tail(&urbl->link, &xfr_list);
+ if (ep->credit < 0)
+ ep->credit = 0;
+ list_del(&urbl->link);
+ list_add_tail(&urbl->link, &xfr_list);
}
}
spin_unlock_bh(&ozhcd->hcd_lock);
/* 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, NULL, 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, NULL, 0);
}
continue;
}
- ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
- oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
- 0, NULL, 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,
int len = 0;
int copy_len;
int i;
- if ((ep->credit + 1) < urb->number_of_packets)
- break;
if (ep->buffered_units < urb->number_of_packets)
break;
urb->actual_length = 0;
urb->error_count = 0;
urb->start_frame = ep->start_frame;
ep->start_frame += urb->number_of_packets;
- list_move_tail(&urbl->link, &xfr_list);
+ 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, NULL, 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))
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.
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;
- list_move_tail(e, &xfr_list);
+ 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))
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);
}
{
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;
struct oz_endpoint *ep;
int buffer_size = 0;
- oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
if (ep_addr & USB_ENDPOINT_DIR_MASK) {
switch (hep->desc.bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_ISOC:
- buffer_size = 24*1024;
+ buffer_size = OZ_EP_BUFFER_SIZE_ISOC;
break;
case USB_ENDPOINT_XFER_INT:
- buffer_size = 128;
+ buffer_size = OZ_EP_BUFFER_SIZE_INT;
break;
}
}
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, NULL, 0);
} else {
ep->flags |= OZ_F_EP_HAVE_STREAM;
if (oz_usb_stream_create(port->hpd, ep_num))
*/
if ((mask & (1<<i)) && port->out_ep[i]) {
e = &port->out_ep[i]->link;
- port->out_ep[i] = NULL;
+ port->out_ep[i] = 0;
/* Remove from isoc list if present.
*/
- list_move_tail(e, &ep_list);
+ list_del(e);
+ list_add_tail(e, &ep_list);
}
/* Gather IN endpoints.
*/
if ((mask & (1<<(i+OZ_NB_ENDPOINTS))) && port->in_ep[i]) {
e = &port->in_ep[i]->link;
- port->in_ep[i] = NULL;
- list_move_tail(e, &ep_list);
+ port->in_ep[i] = 0;
+ list_del(e);
+ list_add_tail(e, &ep_list);
}
}
spin_unlock_bh(&ozhcd->hcd_lock);
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 = NULL;
+ port->iface = 0;
}
port->num_iface = 0;
spin_unlock_bh(&ozhcd->hcd_lock);
*/
static void *oz_claim_hpd(struct oz_port *port)
{
- void *hpd = NULL;
+ void *hpd = 0;
struct oz_hcd *ozhcd = port->ozhcd;
spin_lock_bh(&ozhcd->hcd_lock);
hpd = port->hpd;
unsigned windex;
unsigned wvalue;
unsigned wlength;
- void *hpd = NULL;
+ void *hpd = 0;
u8 req_id;
int rc = 0;
unsigned complete = 0;
int port_ix = -1;
- struct oz_port *port = NULL;
+ 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;
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 == NULL) {
- oz_trace("Cannot claim port\n");
+ if (hpd == 0) {
rc = -EPIPE;
goto out;
}
*/
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, NULL, 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 circuit this case and reply directly since
* we have the selected configuration number cached.
*/
- oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0,
- NULL, 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) =
/* 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,
- NULL, 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;
}
}
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);
}
/* 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);
}
struct urb *urb;
struct oz_hcd *ozhcd = oz_hcd_claim();
int rc = 0;
- if (ozhcd == NULL)
+ if (ozhcd == 0)
return;
/* This is called from a tasklet so is in softirq context but the urb
* list is filled from any context so we need to lock
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);
*/
static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb)
{
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl = 0;
struct list_head *e;
struct oz_hcd *ozhcd;
unsigned long irq_state;
u8 ix;
- if (port == NULL) {
- oz_trace("ERRORERROR: oz_urb_cancel(%p) port is null\n", urb);
+ if (port == 0) {
+ oz_trace("%s: urb=%p port is null\n", __func__, urb);
return;
}
ozhcd = port->ozhcd;
- if (ozhcd == NULL) {
- oz_trace("ERRORERROR: oz_urb_cancel(%p) ozhcd is null\n", urb);
+ if (ozhcd == 0) {
+ oz_trace("%s: urb=%p ozhcd is null\n", __func__, urb);
return;
}
}
}
spin_unlock_irqrestore(&g_tasklet_lock, irq_state);
- urbl = NULL;
+ urbl = 0;
/* Look in the orphanage.
*/
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;
}
}
ix = (ep_num & 0xf);
- urbl = NULL;
+ urbl = 0;
if ((ep_num & USB_DIR_IN) && ix)
urbl = oz_remove_urb(port->in_ep[ix], urb);
else
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);
}
}
/*------------------------------------------------------------------------------
unsigned long irq_state;
struct urb *urb;
struct oz_hcd *ozhcd = oz_hcd_claim();
- if (ozhcd == NULL)
+ if (ozhcd == 0)
return;
spin_lock_irqsave(&g_tasklet_lock, irq_state);
while (!list_empty(&ozhcd->urb_cancel_list)) {
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);
}
}
*/
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;
*/
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");
+ oz_trace("%s:\n", __func__);
}
-/*------------------------------------------------------------------------------
- * 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;
-}
-#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
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 == NULL)) {
- oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not ozhcd.\n",
- jiffies, urb);
- return -EPIPE;
+ if (unlikely(ozhcd == 0)) {
+ 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 == NULL)
- return -EPIPE;
+ if (port == 0)
+ 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.
*/
urbl = oz_alloc_urb_link();
- if (unlikely(urbl == NULL))
+ if (unlikely(urbl == 0))
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);
static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep,
struct urb *urb)
{
- struct oz_urb_link *urbl = NULL;
+ struct oz_urb_link *urbl = 0;
struct list_head *e;
- if (unlikely(ep == NULL))
- return NULL;
+ if (unlikely(ep == 0))
+ return 0;
list_for_each(e, &ep->urb_list) {
urbl = container_of(e, struct oz_urb_link, link);
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, NULL, ep->credit);
}
return urbl;
}
}
- return NULL;
+ return 0;
}
/*------------------------------------------------------------------------------
* Called to dequeue a previously submitted urb for the device.
static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct oz_hcd *ozhcd = oz_hcd_private(hcd);
- struct oz_urb_link *urbl = NULL;
+ 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 == NULL))
+ if (unlikely(urbl == 0))
return -ENOMEM;
spin_lock_irqsave(&g_tasklet_lock, irq_state);
/* The following function checks the urb is still in the queue
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
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();
}
/*------------------------------------------------------------------------------
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
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;
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) {
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;
}
/*------------------------------------------------------------------------------
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) {
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;
}
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;
}
/*------------------------------------------------------------------------------
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);
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;
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;
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;
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;
*/
static void oz_plat_shutdown(struct platform_device *dev)
{
- oz_trace("oz_plat_shutdown()\n");
+ oz_trace("%s:\n", __func__);
}
/*------------------------------------------------------------------------------
* Context: process
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 == NULL) {
- oz_trace("Failed to created hcd object OK\n");
+ if (hcd == 0) {
+ oz_trace("Failed to created hcd object\n");
return -ENOMEM;
}
ozhcd = oz_hcd_private(hcd);
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;
}
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct oz_hcd *ozhcd;
- oz_trace("oz_plat_remove()\n");
- if (hcd == NULL)
+
+ if (hcd == 0)
return -1;
ozhcd = oz_hcd_private(hcd);
spin_lock_bh(&g_hcdlock);
if (ozhcd == g_ozhcd)
- g_ozhcd = NULL;
+ 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();
*/
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;
}
/*------------------------------------------------------------------------------
*/
static int oz_plat_resume(struct platform_device *dev)
{
- oz_trace("oz_plat_resume()\n");
+ oz_trace("%s:\n", __func__);
return 0;
}
/*------------------------------------------------------------------------------
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);
- if (g_plat_dev == NULL) {
+ if (g_plat_dev == 0) {
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);
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;
}
/*------------------------------------------------------------------------------
*/
void oz_hcd_term(void)
{
- tasklet_kill(&g_urb_process_tasklet);
- tasklet_kill(&g_urb_cancel_tasklet);
+ msleep(OZ_HUB_DEBOUNCE_TIMEOUT);
+ tasklet_disable(&g_urb_process_tasklet);
+ tasklet_disable(&g_urb_cancel_tasklet);
platform_device_unregister(g_plat_dev);
platform_driver_unregister(&g_oz_plat_drv);
oz_trace("Pending urbs:%d\n", atomic_read(&g_pending_urbs));
--- /dev/null
+/* -----------------------------------------------------------------------------
+ * 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);
+}
--- /dev/null
+/* -----------------------------------------------------------------------------
+ * 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 */
#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
* bind to nothing. '*' means bind to all netcards - this includes non-802.11
* netcards. Bindings can be added later using an IOCTL.
*/
-static char *g_net_dev = "";
+char *g_net_dev = "";
/*------------------------------------------------------------------------------
* Context: process
*/
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();
-#ifdef CONFIG_DEBUG_FS
- oz_debugfs_init();
-#endif
+ printk(KERN_DEBUG "p->oz_protocol_init = 0x%p\n", oz_protocol_init);
return 0;
}
/*------------------------------------------------------------------------------
oz_protocol_term();
oz_apps_term();
oz_cdev_deregister();
- oz_event_term();
-#ifdef CONFIG_DEBUG_FS
- oz_debugfs_remove();
-#endif
}
/*------------------------------------------------------------------------------
*/
MODULE_AUTHOR("Chris Kelly");
MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.13");
+MODULE_VERSION("1.2.3-rc2");
MODULE_LICENSE("GPL");
#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>
/*------------------------------------------------------------------------------
*/
#define OZ_MAX_TX_POOL_SIZE 6
+#define AC_VO 0x106
/*------------------------------------------------------------------------------
*/
static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
static atomic_t g_submitted_isoc = ATOMIC_INIT(0);
/* Application handler functions.
*/
-static const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
+static struct oz_app_if g_app_if[OZ_APPID_MAX] = {
{oz_usb_init,
oz_usb_term,
oz_usb_start,
oz_def_app_start,
oz_def_app_stop,
oz_def_app_rx,
- NULL,
- NULL,
+ 0,
+ 0,
OZ_APPID_UNUSED1},
{oz_def_app_init,
oz_def_app_start,
oz_def_app_stop,
oz_def_app_rx,
- NULL,
- NULL,
+ 0,
+ 0,
OZ_APPID_UNUSED2},
{oz_cdev_init,
oz_cdev_start,
oz_cdev_stop,
oz_cdev_rx,
- NULL,
- NULL,
+ 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
void oz_pd_set_state(struct oz_pd *pd, unsigned state)
{
pd->state = state;
- oz_event_log(OZ_EVT_PD_STATE, 0, 0, NULL, 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
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
+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]);
memcpy(pd->mac_addr, mac_addr, ETH_ALEN);
if (0 != oz_elt_buf_init(&pd->elt_buff)) {
kfree(pd);
- pd = NULL;
+ pd = 0;
}
spin_lock_init(&pd->tx_frame_lock);
INIT_LIST_HEAD(&pd->tx_queue);
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;
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
*/
int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
{
- const struct oz_app_if *ai;
+ 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();
*/
void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
{
- const struct oz_app_if *ai;
+ 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();
pd->paused_apps &= ~(1<<ai->app_id);
}
oz_polling_unlock_bh();
- ai->stop(pd, pause);
+ if (ai->stop)
+ ai->stop(pd, pause);
}
}
}
*/
void oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
{
- const struct oz_app_if *ai;
+ struct oz_app_if *ai;
int more = 0;
for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) {
if (ai->heartbeat && (apps & (1<<ai->app_id))) {
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))
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;
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);
}
/*------------------------------------------------------------------------------
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;
}
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;
}
*/
static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
{
- struct oz_tx_frame *f = NULL;
+ struct oz_tx_frame *f = 0;
spin_lock_bh(&pd->tx_frame_lock);
if (pd->tx_pool) {
f = container_of(pd->tx_pool, struct oz_tx_frame, link);
pd->tx_pool_count--;
}
spin_unlock_bh(&pd->tx_frame_lock);
- if (f == NULL)
+ if (f == 0)
f = kmalloc(sizeof(struct oz_tx_frame), GFP_ATOMIC);
if (f) {
f->total_size = sizeof(struct oz_hdr);
} else {
kfree(f);
}
- oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
- pd->nb_queued_isoc_frames);
}
/*------------------------------------------------------------------------------
* Context: softirq or process
f->link.next = pd->tx_pool;
pd->tx_pool = &f->link;
pd->tx_pool_count++;
- f = NULL;
+ f = 0;
}
spin_unlock_bh(&pd->tx_frame_lock);
- kfree(f);
+ if (f)
+ kfree(f);
}
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-static void oz_set_more_bit(struct sk_buff *skb)
+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
*/
-static void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
+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;
if (!empty && !oz_are_elts_available(&pd->elt_buff))
return -1;
f = oz_tx_frame_alloc(pd);
- if (f == NULL)
+ if (f == 0)
return -1;
f->skb = NULL;
f->hdr.control =
*/
static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = 0;
struct net_device *dev = pd->net_dev;
struct oz_hdr *oz_hdr;
struct oz_elt *elt;
* as the space we need.
*/
skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
- if (skb == NULL)
- return NULL;
+ if (skb == 0)
+ return 0;
/* Reserve the head room for lower layers.
*/
skb_reserve(skb, LL_RESERVED_SPACE(dev));
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;
return skb;
fail:
kfree_skb(skb);
- return NULL;
+ return 0;
}
/*------------------------------------------------------------------------------
* Context: softirq or process
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) {
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Dropping ISOC Frame\n");
- oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, NULL, 0);
return -1;
}
atomic_inc(&g_submitted_isoc);
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Sending ISOC Frame, nb_isoc= %d\n",
- pd->nb_queued_isoc_frames);
return 0;
} else {
kfree_skb(skb);
- oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
- oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, NULL, 0);
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_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,
- NULL, f->hdr.pkt_num);
- if (dev_queue_xmit(skb) < 0)
- return -1;
-
- }
+ oz_trace_skb(skb, 'T');
+ if (dev_queue_xmit(skb) < 0)
+ return -1;
return 0;
}
/*------------------------------------------------------------------------------
*/
static int oz_send_isoc_frame(struct oz_pd *pd)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = 0;
struct net_device *dev = pd->net_dev;
struct oz_hdr *oz_hdr;
struct oz_elt *elt;
if (list.next == &list)
return 0;
skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
- if (skb == NULL) {
- oz_trace("Cannot alloc skb\n");
+ if (skb == 0) {
oz_elt_info_free_chain(&pd->elt_buff, &list);
return -1;
}
memcpy(elt, ei->data, ei->length);
elt = oz_next_elt(elt);
}
- oz_event_log(OZ_EVT_TX_ISOC, 0, 0, NULL, 0);
+ oz_trace_skb(skb, 'T');
dev_queue_xmit(skb);
oz_elt_info_free_chain(&pd->elt_buff, &list);
return 0;
{
struct list_head *e;
struct oz_tx_frame *f;
- struct list_head *first = NULL;
- struct list_head *last = NULL;
+ struct list_head *first = 0;
+ struct list_head *last = 0;
u8 diff;
u32 pkt_num;
diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
break;
- oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
- pkt_num, pd->nb_queued_frames);
- if (first == NULL)
+ if (first == 0)
first = e;
last = e;
e = e->next;
if (first) {
last->next->prev = &pd->tx_queue;
pd->tx_queue.next = last->next;
- last->next = NULL;
+ last->next = 0;
}
pd->last_sent_frame = &pd->tx_queue;
spin_unlock(&pd->tx_frame_lock);
if (st->ep_num == ep_num)
return st;
}
- return NULL;
+ return 0;
}
/*------------------------------------------------------------------------------
* Context: softirq
spin_lock_bh(&pd->stream_lock);
if (!pd_stream_find(pd, ep_num)) {
list_add(&st->link, &pd->stream_list);
- st = NULL;
+ st = 0;
}
spin_unlock_bh(&pd->stream_lock);
- kfree(st);
+ if (st)
+ kfree(st);
return 0;
}
/*------------------------------------------------------------------------------
*/
static void oz_isoc_stream_free(struct oz_isoc_stream *st)
{
- kfree_skb(st->skb);
+ if (st->skb)
+ kfree_skb(st->skb);
kfree(st);
}
/*------------------------------------------------------------------------------
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
*/
-int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
+int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
{
struct net_device *dev = pd->net_dev;
struct oz_isoc_stream *st;
u8 nb_units = 0;
- struct sk_buff *skb = NULL;
- struct oz_hdr *oz_hdr = NULL;
+ struct sk_buff *skb = 0;
+ struct oz_hdr *oz_hdr = 0;
int size = 0;
spin_lock_bh(&pd->stream_lock);
st = pd_stream_find(pd, ep_num);
if (st) {
skb = st->skb;
- st->skb = NULL;
+ st->skb = 0;
nb_units = st->nb_units;
st->nb_units = 0;
oz_hdr = st->oz_hdr;
/* Allocate enough space for max size frame. */
skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev),
GFP_ATOMIC);
- if (skb == NULL)
+ if (skb == 0)
return 0;
/* Reserve the head room for lower layers. */
skb_reserve(skb, LL_RESERVED_SPACE(dev));
skb->dev = dev;
skb->protocol = htons(OZ_ETHERTYPE);
/* For audio packet set priority to AC_VO */
- skb->priority = 0x7;
+ skb->priority = AC_VO;
size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
oz_hdr = (struct oz_hdr *)skb_put(skb, size);
}
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) {
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Dropping ISOC Unit nb= %d\n",
- nb);
- goto out;
+ 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)
list_add_tail(&isoc_unit->link, &pd->tx_queue);
pd->nb_queued_isoc_frames++;
spin_unlock_bh(&pd->tx_frame_lock);
- oz_trace2(OZ_TRACE_TX_FRAMES,
- "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
- pd->nb_queued_isoc_frames, pd->nb_queued_frames);
- oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
- skb, atomic_read(&g_submitted_isoc));
return 0;
}
-
/*In ANYTIME mode Xmit unit immediately*/
if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) {
atomic_inc(&g_submitted_isoc);
- oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
- skb, atomic_read(&g_submitted_isoc));
+ oz_trace_skb(skb, 'T');
if (dev_queue_xmit(skb) < 0) {
- oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, NULL, 0);
return -1;
} else
return 0;
}
-out: oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, NULL, 0);
- kfree_skb(skb);
+out: kfree_skb(skb);
return -1;
}
*/
void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt)
{
- const struct oz_app_if *ai;
+ struct oz_app_if *ai;
if (app_id == 0 || app_id > OZ_APPID_MAX)
return;
ai = &g_app_if[app_id-1];
void oz_pd_indicate_farewells(struct oz_pd *pd)
{
struct oz_farewell *f;
- const 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;
- }
+ struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
+ 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);
}
}
#ifndef _OZPD_H_
#define _OZPD_H_
+#include <linux/interrupt.h>
#include "ozeltbuf.h"
/* PD state
#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.
struct list_head link;
u8 ep_num;
u8 index;
- u8 report[1];
+ u8 report[32];
u8 len;
};
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;
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
-struct oz_pd *oz_pd_alloc(const u8 *mac_addr);
+struct oz_pd *oz_pd_alloc(u8 *mac_addr);
void oz_pd_destroy(struct oz_pd *pd);
void oz_pd_get(struct oz_pd *pd);
void oz_pd_put(struct oz_pd *pd);
void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn);
int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num);
int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num);
-int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len);
+int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len);
void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt);
void oz_apps_init(void);
void oz_apps_term(void);
#include <linux/netdevice.h>
#include <linux/errno.h>
#include <linux/ieee80211.h>
-#include "ozconfig.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#include "ozusbsvc.h"
#include "oztrace.h"
#include "ozappif.h"
-#include "ozevent.h"
#include <asm/unaligned.h>
#include <linux/uaccess.h>
#include <net/psnap.h>
#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
*/
int sz = sizeof(struct oz_hdr) + sizeof(struct oz_elt) +
sizeof(struct oz_elt_connect_rsp);
skb = alloc_skb(sz + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
- if (skb == NULL)
+ if (skb == 0)
return;
skb_reserve(skb, LL_RESERVED_SPACE(dev));
skb_reset_network_header(skb);
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, NULL, 0);
elt->type = OZ_ELT_CONNECT_RSP;
elt->length = sizeof(struct oz_elt_connect_rsp);
memset(body, 0, sizeof(struct oz_elt_connect_rsp));
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;
}
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
*/
static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
- const u8 *pd_addr, struct net_device *net_dev)
+ u8 *pd_addr, struct net_device *net_dev)
{
struct oz_pd *pd;
struct oz_elt_connect_req *body =
u8 rsp_status = OZ_STATUS_SUCCESS;
u8 stop_needed = 0;
u16 new_apps = g_apps;
- struct net_device *old_net_dev = NULL;
- struct oz_pd *free_pd = NULL;
+ struct net_device *old_net_dev = 0;
+ struct oz_pd *free_pd = 0;
if (cur_pd) {
pd = cur_pd;
spin_lock_bh(&g_polling_lock);
} else {
- struct oz_pd *pd2 = NULL;
+ struct oz_pd *pd2 = 0;
struct list_head *e;
pd = oz_pd_alloc(pd_addr);
- if (pd == NULL)
- return NULL;
- pd->last_rx_time_j = jiffies;
+ if (pd == 0)
+ return 0;
+ 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);
if (pd != pd2)
list_add_tail(&pd->link, &g_pd_list);
}
- if (pd == NULL) {
+ if (pd == 0) {
spin_unlock_bh(&g_polling_lock);
- return NULL;
+ return 0;
}
if (pd->net_dev != net_dev) {
old_net_dev = pd->net_dev;
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->ms_per_isoc = body->ms_per_isoc;
if (!pd->ms_per_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));
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;
if (stop_needed)
oz_pd_stop(pd);
oz_pd_put(pd);
- pd = NULL;
+ pd = 0;
}
if (old_net_dev)
dev_put(old_net_dev);
* Context: softirq-serialized
*/
static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
- const u8 *report, u8 len)
+ u8 *report, u8 len)
{
struct oz_farewell *f;
struct oz_farewell *f2;
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);
u8 *src_addr;
struct oz_elt *elt;
int length;
- struct oz_pd *pd = NULL;
+ 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,
- NULL, 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;
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");
}
}
if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
- oz_trace2(OZ_TRACE_RX_FRAMES, "Received TRIGGER Frame\n");
pd->last_sent_frame = &pd->tx_queue;
if (oz_hdr->control & OZ_F_ACK) {
/* Retire completed frames */
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, NULL, 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);
}
}
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);
*/
void oz_protocol_term(void)
{
- struct list_head *chain;
- 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)
oz_pd_put(pd);
spin_lock_bh(&g_polling_lock);
}
- chain = g_timer_pool;
- g_timer_pool = NULL;
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, NULL, 0);
- spin_unlock_bh(&g_polling_lock);
- return;
- }
- g_timer_state = OZ_TIMER_IN_HANDLER;
- t = g_cur_timer;
- g_cur_timer = NULL;
- list_del(&t->link);
- spin_unlock_bh(&g_polling_lock);
- do {
- pd = t->pd;
- oz_event_log(OZ_EVT_TIMER, 0, t->type, NULL, 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 = NULL;
- }
- 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 = NULL;
- } else {
- t2 = NULL;
- }
- spin_unlock_bh(&g_polling_lock);
- oz_pd_put(pd);
- 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, NULL,
- (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, NULL,
- (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 = NULL;
- int restart_needed = 0;
- oz_event_log(OZ_EVT_TIMER_CTRL, 1, (u16)type, NULL, (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 = NULL;
- }
- list_del(e);
- break;
- }
- t = NULL;
- }
- }
- 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);
+ hrtimer_start(&pd->timeout, ktime_set(due_time /
+ MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+ NSEC_PER_MSEC), HRTIMER_MODE_REL);
}
- if (t) {
- t->pd = pd;
- t->type = type;
- oz_pd_get(pd);
- }
- }
- 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 = NULL;
- 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 = NULL;
- 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, NULL, 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 = NULL;
- 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);
+ 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;
}
+ 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
*/
-struct oz_pd *oz_pd_find(const u8 *mac_addr)
+struct oz_pd *oz_pd_find(u8 *mac_addr)
{
struct oz_pd *pd;
struct list_head *e;
}
}
spin_unlock_bh(&g_polling_lock);
- return NULL;
+ return 0;
}
/*------------------------------------------------------------------------------
* Context: process
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, NULL, 0);
skb = skb_share_check(skb, GFP_ATOMIC);
- if (skb == NULL)
+ if (skb == 0)
return 0;
spin_lock_bh(&g_rx_queue.lock);
if (g_processing_rx) {
/*------------------------------------------------------------------------------
* Context: process
*/
-void oz_binding_add(char *net_dev)
+void oz_binding_add(const char *net_dev)
{
struct oz_binding *binding;
oz_trace("Adding binding: %s\n", net_dev);
binding->ptype.dev =
dev_get_by_name(&init_net, net_dev);
- if (binding->ptype.dev == NULL) {
+ if (binding->ptype.dev == 0) {
oz_trace("Netdev %s not found\n", net_dev);
kfree(binding);
- binding = NULL;
+ binding = 0;
}
} else {
oz_trace("Binding to all netcards\n");
- binding->ptype.dev = NULL;
+ binding->ptype.dev = 0;
}
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);
}
}
/*------------------------------------------------------------------------------
* 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++) {
/*------------------------------------------------------------------------------
* Context: process
*/
-void oz_binding_remove(char *net_dev)
+void oz_binding_remove(const char *net_dev)
{
- struct oz_binding *binding;
- 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
*/
{
skb_queue_head_init(&g_rx_queue);
if (devs && (devs[0] == '*')) {
- oz_binding_add(NULL);
+ oz_binding_add(0);
} else {
char d[32];
while (*devs) {
oz_binding_add(d);
}
}
- init_timer(&g_timer);
return 0;
}
/*------------------------------------------------------------------------------
spin_unlock_bh(&g_polling_lock);
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)
#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) msecs_to_jiffies(__x)
-/* 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
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(const 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);
+struct oz_pd *oz_pd_find(u8 *mac_addr);
+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 */
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.
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.
#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.
* 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);
+}
*/
#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 */
* -----------------------------------------------------------------------------
*/
#include <linux/usb.h>
-#include "ozconfig.h"
#ifdef WANT_URB_PARANOIA
#include "ozurbparanoia.h"
#include "oztrace.h"
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");
}
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);
/* Request functions.
*/
int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
- const u8 *data, int data_len);
+ u8 *data, int data_len);
int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type,
u8 index, u16 windex, int offset, int len);
int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb);
/* Confirmation functions.
*/
void oz_hcd_get_desc_cnf(void *hport, u8 req_id, int status,
- const u8 *desc, int length, int offset, int total_size);
+ u8 *desc, int length, int offset, int total_size);
void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode,
- const u8 *data, int data_len);
+ 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, const u8 *data, int data_len);
+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 */
#include <linux/errno.h>
#include <linux/input.h>
#include <asm/unaligned.h>
-#include "ozconfig.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#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, NULL, 0);
return oz_hcd_init();
}
/*------------------------------------------------------------------------------
*/
void oz_usb_term(void)
{
- oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_USB, NULL, 0);
oz_hcd_term();
}
/*------------------------------------------------------------------------------
{
int rc = 0;
struct oz_usb_ctx *usb_ctx;
- struct oz_usb_ctx *old_ctx;
- oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_USB, NULL, resume);
+ struct oz_usb_ctx *old_ctx = 0;
if (resume) {
oz_trace("USB service resumed.\n");
return 0;
* has a USB context then we will destroy it.
*/
usb_ctx = kzalloc(sizeof(struct oz_usb_ctx), GFP_ATOMIC);
- if (usb_ctx == NULL)
+ if (usb_ctx == 0)
return -ENOMEM;
atomic_set(&usb_ctx->ref_count, 1);
usb_ctx->pd = pd;
*/
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
old_ctx = pd->app_ctx[OZ_APPID_USB-1];
- if (old_ctx == NULL)
+ if (old_ctx == 0)
pd->app_ctx[OZ_APPID_USB-1] = usb_ctx;
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) {
oz_hcd_pd_reset(usb_ctx, usb_ctx->hport);
} else {
usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx);
- if (usb_ctx->hport == NULL) {
- oz_trace("USB hub returned null port.\n");
+ if (usb_ctx->hport == 0) {
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
- pd->app_ctx[OZ_APPID_USB-1] = NULL;
+ pd->app_ctx[OZ_APPID_USB-1] = 0;
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
oz_usb_put(usb_ctx);
rc = -1;
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, NULL, pause);
if (pause) {
oz_trace("USB service paused.\n");
return;
}
spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB-1];
- pd->app_ctx[OZ_APPID_USB-1] = NULL;
+ 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
* 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.
*/
{
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);
}
if (usb_ctx)
oz_usb_get(usb_ctx);
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
- if (usb_ctx == NULL)
+ if (usb_ctx == 0)
return rc;
if (usb_ctx->stopped)
goto done;
{
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 {
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 {
#include <linux/errno.h>
#include <linux/input.h>
#include <asm/unaligned.h>
-#include "ozconfig.h"
#include "ozprotocol.h"
#include "ozeltbuf.h"
#include "ozpd.h"
#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
*/
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 == NULL)
+ 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);
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_set_config_req *body;
- if (ei == NULL)
+ 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);
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_set_interface_req *body;
- if (ei == NULL)
+ 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);
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_feature_req *body;
- if (ei == NULL)
+ 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;
* Context: tasklet
*/
static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type,
- u8 request, __le16 value, __le16 index, const u8 *data, int data_len)
+ u8 request, __le16 value, __le16 index, u8 *data, int data_len)
{
struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd;
struct oz_pd *pd = usb_ctx->pd;
struct oz_elt_buf *eb = &pd->elt_buff;
struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff);
struct oz_vendor_class_req *body;
- if (ei == NULL)
+ 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);
* Context: tasklet
*/
int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup,
- const u8 *data, int data_len)
+ u8 *data, int data_len)
{
unsigned wvalue = le16_to_cpu(setup->wValue);
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:
int unit_count;
int unit_size;
int rem;
- if (ei == NULL)
+ if (ei == 0)
return -1;
rem = MAX_ISOC_FIXED_DATA;
elt = (struct oz_elt *)ei->data;
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
+void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx,
struct oz_usb_hdr *usb_hdr, int len)
{
struct oz_data *data_hdr = (struct oz_data *)usb_hdr;
if (usb_ctx)
oz_usb_get(usb_ctx);
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
- if (usb_ctx == NULL)
+ if (usb_ctx == 0)
return; /* Context has gone so nothing to do. */
if (usb_ctx->stopped)
goto done;
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);
struct oz_set_config_rsp *body =
(struct oz_set_config_rsp *)usb_hdr;
oz_hcd_control_cnf(usb_ctx->hport, body->req_id,
- body->rcode, NULL, 0);
+ body->rcode, 0, 0);
}
break;
case OZ_SET_INTERFACE_RSP: {
struct oz_set_interface_rsp *body =
(struct oz_set_interface_rsp *)usb_hdr;
oz_hcd_control_cnf(usb_ctx->hport,
- body->req_id, body->rcode, NULL, 0);
+ body->req_id, body->rcode, 0, 0);
}
break;
case OZ_VENDOR_CLASS_RSP: {
if (usb_ctx)
oz_usb_get(usb_ctx);
spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
- if (usb_ctx == NULL)
+ if (usb_ctx == 0)
return; /* Context has gone so nothing to do. */
if (!usb_ctx->stopped) {
oz_trace("Farewell indicated ep = 0x%x\n", ep_num);
}
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;
+}