diff options
Diffstat (limited to 'drivers/staging/ozwpan')
-rw-r--r-- | drivers/staging/ozwpan/TODO | 11 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozappif.h | 6 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozcdev.c | 28 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozmain.c | 2 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozpd.c | 182 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozpd.h | 3 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozproto.c | 6 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozprotocol.h | 1 |
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. */ |