aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/ozwpan
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/ozwpan')
-rw-r--r--drivers/staging/ozwpan/TODO11
-rw-r--r--drivers/staging/ozwpan/ozappif.h6
-rw-r--r--drivers/staging/ozwpan/ozcdev.c28
-rw-r--r--drivers/staging/ozwpan/ozmain.c2
-rw-r--r--drivers/staging/ozwpan/ozpd.c182
-rw-r--r--drivers/staging/ozwpan/ozpd.h3
-rw-r--r--drivers/staging/ozwpan/ozproto.c6
-rw-r--r--drivers/staging/ozwpan/ozprotocol.h1
8 files changed, 194 insertions, 45 deletions
diff --git a/drivers/staging/ozwpan/TODO b/drivers/staging/ozwpan/TODO
index c2d30a7112f..b5db2456bff 100644
--- a/drivers/staging/ozwpan/TODO
+++ b/drivers/staging/ozwpan/TODO
@@ -1,10 +1,11 @@
TODO:
- - 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.
+ - 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.
- 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.
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
index 1b59b0748c6..449a6ba8233 100644
--- a/drivers/staging/ozwpan/ozappif.h
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -30,9 +30,9 @@ struct oz_binding_info {
#define OZ_IOCTL_GET_PD_LIST _IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
#define OZ_IOCTL_SET_ACTIVE_PD _IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
#define OZ_IOCTL_GET_ACTIVE_PD _IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
-#define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
-#define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
-#define OZ_IOCTL_MAX 9
+#define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 3, struct oz_binding_info)
+#define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 4, struct oz_binding_info)
+#define OZ_IOCTL_MAX 5
#endif /* _OZAPPIF_H */
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 27325f74ecd..d9832194580 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -42,6 +42,7 @@ struct oz_serial_ctx {
/*------------------------------------------------------------------------------
*/
static struct oz_cdev g_cdev;
+struct class *g_oz_class;
/*------------------------------------------------------------------------------
* Context: process and softirq
*/
@@ -330,10 +331,11 @@ const struct file_operations oz_fops = {
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)
- return err;
+ 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);
@@ -342,7 +344,27 @@ int oz_cdev_register(void)
spin_lock_init(&g_cdev.lock);
init_waitqueue_head(&g_cdev.rdq);
err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
+ if (err < 0) {
+ oz_trace("Failed to add cdev\n");
+ goto out2;
+ }
+ g_oz_class = class_create(THIS_MODULE, "ozmo_wpan");
+ if (IS_ERR(g_oz_class)) {
+ oz_trace("Failed to register ozmo_wpan class\n");
+ goto out1;
+ }
+ dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan");
+ if (IS_ERR(dev)) {
+ oz_trace("Failed to create sysfs entry for cdev\n");
+ goto out1;
+ }
return 0;
+out1:
+ cdev_del(&g_cdev.cdev);
+out2:
+ unregister_chrdev_region(g_cdev.devnum, 1);
+out3:
+ return err;
}
/*------------------------------------------------------------------------------
* Context: process
@@ -351,6 +373,10 @@ int oz_cdev_deregister(void)
{
cdev_del(&g_cdev.cdev);
unregister_chrdev_region(g_cdev.devnum, 1);
+ if (g_oz_class) {
+ device_destroy(g_oz_class, g_cdev.devnum);
+ class_destroy(g_oz_class);
+ }
return 0;
}
/*------------------------------------------------------------------------------
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index 7579645d642..c1ed6b2522e 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -59,6 +59,6 @@ module_exit(ozwpan_exit);
MODULE_AUTHOR("Chris Kelly");
MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.9");
+MODULE_VERSION("1.0.10");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
index 04cd57f2a6d..6c287ac6eae 100644
--- a/drivers/staging/ozwpan/ozpd.c
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -24,18 +24,22 @@
/*------------------------------------------------------------------------------
*/
#define OZ_MAX_TX_POOL_SIZE 6
-/* Maximum number of uncompleted isoc frames that can be pending.
+/* Maximum number of uncompleted isoc frames that can be pending in network.
*/
#define OZ_MAX_SUBMITTED_ISOC 16
+/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue.
+ */
+#define OZ_MAX_TX_QUEUE_ISOC 32
/*------------------------------------------------------------------------------
*/
static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f);
+static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f);
static int oz_send_isoc_frame(struct oz_pd *pd);
static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f);
static void oz_isoc_stream_free(struct oz_isoc_stream *st);
-static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data);
+static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data);
static void oz_isoc_destructor(struct sk_buff *skb);
static int oz_def_app_init(void);
static void oz_def_app_term(void);
@@ -208,6 +212,8 @@ void oz_pd_destroy(struct oz_pd *pd)
while (e != &pd->tx_queue) {
f = container_of(e, struct oz_tx_frame, link);
e = e->next;
+ if (f->skb != NULL)
+ kfree_skb(f->skb);
oz_retire_frame(pd, f);
}
oz_elt_buf_term(&pd->elt_buff);
@@ -375,6 +381,23 @@ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
/*------------------------------------------------------------------------------
* Context: softirq or process
*/
+static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
+{
+ pd->nb_queued_isoc_frames--;
+ list_del_init(&f->link);
+ if (pd->tx_pool_count < OZ_MAX_TX_POOL_SIZE) {
+ f->link.next = pd->tx_pool;
+ pd->tx_pool = &f->link;
+ pd->tx_pool_count++;
+ } else {
+ kfree(f);
+ }
+ oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
+ pd->nb_queued_isoc_frames);
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq or process
+ */
static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
{
spin_lock_bh(&pd->tx_frame_lock);
@@ -389,6 +412,22 @@ static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
kfree(f);
}
/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_set_more_bit(struct sk_buff *skb)
+{
+ struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+ oz_hdr->control |= OZ_F_MORE_DATA;
+}
+/*------------------------------------------------------------------------------
+ * Context: softirq-serialized
+ */
+void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
+{
+ struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+ oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
+}
+/*------------------------------------------------------------------------------
* Context: softirq
*/
int oz_prepare_frame(struct oz_pd *pd, int empty)
@@ -403,6 +442,7 @@ int oz_prepare_frame(struct oz_pd *pd, int empty)
f = oz_tx_frame_alloc(pd);
if (f == 0)
return -1;
+ f->skb = NULL;
f->hdr.control =
(OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT) | OZ_F_ACK_REQUESTED;
++pd->last_tx_pkt_num;
@@ -486,24 +526,52 @@ static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f)
/*------------------------------------------------------------------------------
* Context: softirq-serialized
*/
-static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
+static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data)
{
struct sk_buff *skb;
struct oz_tx_frame *f;
struct list_head *e;
- *more_data = 0;
spin_lock(&pd->tx_frame_lock);
e = pd->last_sent_frame->next;
if (e == &pd->tx_queue) {
spin_unlock(&pd->tx_frame_lock);
return -1;
}
- pd->last_sent_frame = e;
- if (e->next != &pd->tx_queue)
- *more_data = 1;
f = container_of(e, struct oz_tx_frame, link);
+
+ if (f->skb != NULL) {
+ skb = f->skb;
+ oz_tx_isoc_free(pd, f);
+ spin_unlock(&pd->tx_frame_lock);
+ if (more_data)
+ oz_set_more_bit(skb);
+ oz_set_last_pkt_nb(pd, skb);
+ if ((int)atomic_read(&g_submitted_isoc) <
+ OZ_MAX_SUBMITTED_ISOC) {
+ 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, 0, 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, 0, 0);
+ return -1;
+ }
+ }
+
+ pd->last_sent_frame = e;
skb = oz_build_frame(pd, f);
spin_unlock(&pd->tx_frame_lock);
+ 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,
@@ -512,6 +580,7 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
0, f->hdr.pkt_num);
if (dev_queue_xmit(skb) < 0)
return -1;
+
}
return 0;
}
@@ -520,21 +589,38 @@ static int oz_send_next_queued_frame(struct oz_pd *pd, int *more_data)
*/
void oz_send_queued_frames(struct oz_pd *pd, int backlog)
{
- int more;
- if (backlog < OZ_MAX_QUEUED_FRAMES) {
- if (oz_send_next_queued_frame(pd, &more) >= 0) {
- while (more && oz_send_next_queued_frame(pd, &more))
- ;
- } else {
- if (((pd->mode & OZ_F_ISOC_ANYTIME) == 0)
- || (pd->isoc_sent == 0)) {
- if (oz_prepare_frame(pd, 1) >= 0)
- oz_send_next_queued_frame(pd, &more);
- }
+ while (oz_prepare_frame(pd, 0) >= 0)
+ backlog++;
+
+ switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) {
+
+ case OZ_F_ISOC_NO_ELTS: {
+ backlog += pd->nb_queued_isoc_frames;
+ if (backlog <= 0)
+ goto out;
+ if (backlog > OZ_MAX_SUBMITTED_ISOC)
+ backlog = OZ_MAX_SUBMITTED_ISOC;
+ break;
+ }
+ case OZ_NO_ELTS_ANYTIME: {
+ if ((backlog <= 0) && (pd->isoc_sent == 0))
+ goto out;
+ break;
+ }
+ default: {
+ if (backlog <= 0)
+ goto out;
+ break;
}
- } else {
- oz_send_next_queued_frame(pd, &more);
}
+ while (backlog--) {
+ if (oz_send_next_queued_frame(pd, backlog) < 0)
+ break;
+ }
+ return;
+
+out: oz_prepare_frame(pd, 1);
+ oz_send_next_queued_frame(pd, 0);
}
/*------------------------------------------------------------------------------
* Context: softirq
@@ -603,8 +689,10 @@ void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn)
f = container_of(e, struct oz_tx_frame, link);
pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num));
diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
- if (diff > OZ_LAST_PN_HALF_CYCLE)
+ if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
break;
+ oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
+ pkt_num, pd->nb_queued_frames);
if (first == 0)
first = e;
last = e;
@@ -727,6 +815,8 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
skb_reset_network_header(skb);
skb->dev = dev;
skb->protocol = htons(OZ_ETHERTYPE);
+ /* For audio packet set priority to AC_VO */
+ skb->priority = 0x7;
size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large);
oz_hdr = (struct oz_hdr *)skb_put(skb, size);
}
@@ -756,21 +846,53 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
memcpy(oz_hdr, &oz, sizeof(oz));
memcpy(oz_hdr+1, &iso, sizeof(iso));
if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
- dev->dev_addr, skb->len) < 0) {
- kfree_skb(skb);
- return -1;
+ dev->dev_addr, skb->len) < 0)
+ goto out;
+
+ skb->destructor = oz_isoc_destructor;
+ /*Queue for Xmit if mode is not ANYTIME*/
+ if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
+ struct oz_tx_frame *isoc_unit = NULL;
+ int nb = pd->nb_queued_isoc_frames;
+ if (nb >= OZ_MAX_TX_QUEUE_ISOC) {
+ oz_trace2(OZ_TRACE_TX_FRAMES,
+ "Dropping ISOC Unit nb= %d\n",
+ nb);
+ goto out;
+ }
+ isoc_unit = oz_tx_frame_alloc(pd);
+ if (isoc_unit == NULL)
+ goto out;
+ isoc_unit->hdr = oz;
+ isoc_unit->skb = skb;
+ spin_lock_bh(&pd->tx_frame_lock);
+ list_add_tail(&isoc_unit->link, &pd->tx_queue);
+ pd->nb_queued_isoc_frames++;
+ spin_unlock_bh(&pd->tx_frame_lock);
+ 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) {
- skb->destructor = oz_isoc_destructor;
atomic_inc(&g_submitted_isoc);
oz_event_log(OZ_EVT_TX_ISOC, nb_units, iso.frame_number,
- skb, atomic_read(&g_submitted_isoc));
- if (dev_queue_xmit(skb) < 0)
+ skb, atomic_read(&g_submitted_isoc));
+ if (dev_queue_xmit(skb) < 0) {
+ oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
return -1;
- } else {
- oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
- kfree_skb(skb);
+ } else
+ return 0;
}
+
+out: oz_event_log(OZ_EVT_TX_ISOC_DROP, 0, 0, 0, 0);
+ kfree_skb(skb);
+ return -1;
+
}
return 0;
}
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
index afc77f0260f..ddf1341b4e6 100644
--- a/drivers/staging/ozwpan/ozpd.h
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -29,6 +29,7 @@ struct oz_tx_frame {
struct list_head link;
struct list_head elt_list;
struct oz_hdr hdr;
+ struct sk_buff *skb;
int total_size;
};
@@ -83,6 +84,7 @@ struct oz_pd {
u8 ms_per_isoc;
unsigned max_stream_buffering;
int nb_queued_frames;
+ int nb_queued_isoc_frames;
struct list_head *tx_pool;
int tx_pool_count;
spinlock_t tx_frame_lock;
@@ -118,4 +120,3 @@ void oz_apps_init(void);
void oz_apps_term(void);
#endif /* Sentry */
-
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index ad857eeabbb..a50ab18a598 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -217,7 +217,6 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
pd->mode = body->mode;
pd->pd_info = body->pd_info;
if (pd->mode & OZ_F_ISOC_NO_ELTS) {
- pd->mode |= OZ_F_ISOC_ANYTIME;
pd->ms_per_isoc = body->ms_per_isoc;
if (!pd->ms_per_isoc)
pd->ms_per_isoc = 4;
@@ -366,6 +365,7 @@ static void oz_rx_frame(struct sk_buff *skb)
}
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 */
@@ -376,8 +376,6 @@ static void oz_rx_frame(struct sk_buff *skb)
int backlog = pd->nb_queued_frames;
pd->trigger_pkt_num = pkt_num;
/* Send queued frames */
- while (oz_prepare_frame(pd, 0) >= 0)
- ;
oz_send_queued_frames(pd, backlog);
}
}
@@ -796,7 +794,7 @@ void oz_binding_add(char *net_dev)
{
struct oz_binding *binding;
- binding = kmalloc(sizeof(struct oz_binding), GFP_ATOMIC);
+ binding = kmalloc(sizeof(struct oz_binding), GFP_KERNEL);
if (binding) {
binding->ptype.type = __constant_htons(OZ_ETHERTYPE);
binding->ptype.func = oz_pkt_recv;
diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h
index b3e7d77f3ff..1e4edbeb61c 100644
--- a/drivers/staging/ozwpan/ozprotocol.h
+++ b/drivers/staging/ozwpan/ozprotocol.h
@@ -89,6 +89,7 @@ struct oz_elt_connect_req {
#define OZ_MODE_MASK 0xf
#define OZ_F_ISOC_NO_ELTS 0x40
#define OZ_F_ISOC_ANYTIME 0x80
+#define OZ_NO_ELTS_ANYTIME 0xc0
/* Keep alive field.
*/