#include <linux/list.h>
#include <linux/usb.h>
#include <linux/time.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
*/
#define DATA_MAX 32
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_MAX 8
+
/*
* This limit exists to prevent OOMs when the user process stops reading.
*/
#define EVENT_MAX 25
-#define PRINTF_DFL 120
+#define PRINTF_DFL 130
struct mon_event_text {
struct list_head e_link;
unsigned int tstamp;
int length; /* Depends on type: xfer length or act length */
int status;
+ char setup_flag;
char data_flag;
+ unsigned char setup[SETUP_MAX];
unsigned char data[DATA_MAX];
};
wait_queue_head_t wait;
int printf_size;
char *printf_buf;
- struct semaphore printf_lock;
+ struct mutex printf_lock;
char slab_name[SLAB_NAME_SZ];
};
* This is called with the whole mon_bus locked, so no additional lock.
*/
+static inline char mon_text_get_setup(struct mon_event_text *ep,
+ struct urb *urb, char ev_type)
+{
+
+ if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ return '-';
+
+ if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
+ if (urb->setup_packet == NULL)
+ return 'Z'; /* '0' would be not as pretty. */
+
+ memcpy(ep->setup, urb->setup_packet, SETUP_MAX);
+ return 0;
+}
+
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type)
{
int pipe = urb->pipe;
- unsigned char *data;
+
+ if (len <= 0)
+ return 'L';
+ if (len >= DATA_MAX)
+ len = DATA_MAX;
+
+ if (usb_pipein(pipe)) {
+ if (ev_type == 'S')
+ return '<';
+ } else {
+ if (ev_type == 'C')
+ return '>';
+ }
/*
* The check to see if it's safe to poke at data has an enormous
* set DMA for the HCD.
*/
if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
- return 'D';
-
- if (len <= 0)
- return 'L';
+ return mon_dmapeek(ep->data, urb->transfer_dma, len);
- if ((data = urb->transfer_buffer) == NULL)
+ if (urb->transfer_buffer == NULL)
return 'Z'; /* '0' would be not as pretty. */
- /*
- * Bulk is easy to shortcut reliably.
- * XXX Control needs setup packet taken.
- * XXX Other pipe types need consideration. Currently, we overdo it
- * and collect garbage for them: better more than less.
- */
- if (usb_pipebulk(pipe) || usb_pipecontrol(pipe)) {
- if (usb_pipein(pipe)) {
- if (ev_type == 'S')
- return '<';
- } else {
- if (ev_type == 'C')
- return '>';
- }
- }
-
- if (len >= DATA_MAX)
- len = DATA_MAX;
memcpy(ep->data, urb->transfer_buffer, len);
return 0;
}
/* Collecting status makes debugging sense for submits, too */
ep->status = urb->status;
+ ep->setup_flag = mon_text_get_setup(ep, urb, ev_type);
ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
rp->nevents++;
struct mon_reader_text *rp;
int rc;
- down(&mon_lock);
+ mutex_lock(&mon_lock);
mbus = inode->u.generic_ip;
ubus = mbus->u_bus;
- rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
+ rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
if (rp == NULL) {
rc = -ENOMEM;
goto err_alloc;
}
- memset(rp, 0, sizeof(struct mon_reader_text));
INIT_LIST_HEAD(&rp->e_list);
init_waitqueue_head(&rp->wait);
- init_MUTEX(&rp->printf_lock);
+ mutex_init(&rp->printf_lock);
rp->printf_size = PRINTF_DFL;
rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL);
mon_reader_add(mbus, &rp->r);
file->private_data = rp;
- up(&mon_lock);
+ mutex_unlock(&mon_lock);
return 0;
// err_busy:
err_alloc_pr:
kfree(rp);
err_alloc:
- up(&mon_lock);
+ mutex_unlock(&mon_lock);
return rc;
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&rp->wait, &waita);
- down(&rp->printf_lock);
+ mutex_lock(&rp->printf_lock);
cnt = 0;
pbuf = rp->printf_buf;
limit = rp->printf_size;
default: /* PIPE_BULK */ utype = 'B';
}
cnt += snprintf(pbuf + cnt, limit - cnt,
- "%lx %u %c %c%c:%03u:%02u %d %d",
+ "%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
- utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe),
- ep->status, ep->length);
+ utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+
+ if (ep->setup_flag == 0) { /* Setup packet is present and captured */
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ " s %02x %02x %04x %04x %04x",
+ ep->setup[0],
+ ep->setup[1],
+ (ep->setup[3] << 8) | ep->setup[2],
+ (ep->setup[5] << 8) | ep->setup[4],
+ (ep->setup[7] << 8) | ep->setup[6]);
+ } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ " %c __ __ ____ ____ ____", ep->setup_flag);
+ } else { /* No setup for this kind of URB */
+ cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status);
+ }
+ cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length);
if ((data_len = ep->length) > 0) {
if (ep->data_flag == 0) {
if (copy_to_user(buf, rp->printf_buf, cnt))
cnt = -EFAULT;
- up(&rp->printf_lock);
+ mutex_unlock(&rp->printf_lock);
kmem_cache_free(rp->e_slab, ep);
return cnt;
}
struct list_head *p;
struct mon_event_text *ep;
- down(&mon_lock);
+ mutex_lock(&mon_lock);
mbus = inode->u.generic_ip;
if (mbus->nreaders <= 0) {
printk(KERN_ERR TAG ": consistency error on close\n");
- up(&mon_lock);
+ mutex_unlock(&mon_lock);
return 0;
}
mon_reader_del(mbus, &rp->r);
kfree(rp->printf_buf);
kfree(rp);
- up(&mon_lock);
+ mutex_unlock(&mon_lock);
return 0;
}