1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * The USB Monitor, inspired by Dave Harding's USBMon.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * This is a text format reader.
61da177e4SLinus Torvalds */
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds #include <linux/kernel.h>
91da177e4SLinus Torvalds #include <linux/list.h>
101da177e4SLinus Torvalds #include <linux/usb.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
12174cd4b1SIngo Molnar #include <linux/sched/signal.h>
131da177e4SLinus Torvalds #include <linux/time.h>
14ec4dca8bSTina Ruchandani #include <linux/ktime.h>
15f940fcd8SPaul Gortmaker #include <linux/export.h>
164186ecf8SArjan van de Ven #include <linux/mutex.h>
176f23ee1fSPete Zaitcev #include <linux/debugfs.h>
18b375e116SAlan Stern #include <linux/scatterlist.h>
197c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds #include "usb_mon.h"
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds /*
241da177e4SLinus Torvalds * No, we do not want arbitrarily long data strings.
251da177e4SLinus Torvalds * Use the binary interface if you want to capture bulk data!
261da177e4SLinus Torvalds */
271da177e4SLinus Torvalds #define DATA_MAX 32
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds /*
30ae0d6cceSPete Zaitcev * Defined by USB 2.0 clause 9.3, table 9.2.
31ae0d6cceSPete Zaitcev */
32ae0d6cceSPete Zaitcev #define SETUP_MAX 8
33ae0d6cceSPete Zaitcev
34ae0d6cceSPete Zaitcev /*
351da177e4SLinus Torvalds * This limit exists to prevent OOMs when the user process stops reading.
365b1c674dSPete Zaitcev * If usbmon were available to unprivileged processes, it might be open
375b1c674dSPete Zaitcev * to a local DoS. But we have to keep to root in order to prevent
385b1c674dSPete Zaitcev * password sniffing from HID devices.
391da177e4SLinus Torvalds */
40f1c9e30bSPete Zaitcev #define EVENT_MAX (4*PAGE_SIZE / sizeof(struct mon_event_text))
411da177e4SLinus Torvalds
42f1c9e30bSPete Zaitcev /*
43f1c9e30bSPete Zaitcev * Potentially unlimited number; we limit it for similar allocations.
44f1c9e30bSPete Zaitcev * The usbfs limits this to 128, but we're not quite as generous.
45f1c9e30bSPete Zaitcev */
46f1c9e30bSPete Zaitcev #define ISODESC_MAX 5
47f1c9e30bSPete Zaitcev
48f1c9e30bSPete Zaitcev #define PRINTF_DFL 250 /* with 5 ISOs segs */
49f1c9e30bSPete Zaitcev
50f1c9e30bSPete Zaitcev struct mon_iso_desc {
51f1c9e30bSPete Zaitcev int status;
52f1c9e30bSPete Zaitcev unsigned int offset;
53f1c9e30bSPete Zaitcev unsigned int length; /* Unsigned here, signed in URB. Historic. */
54f1c9e30bSPete Zaitcev };
551da177e4SLinus Torvalds
561da177e4SLinus Torvalds struct mon_event_text {
571da177e4SLinus Torvalds struct list_head e_link;
581da177e4SLinus Torvalds int type; /* submit, complete, etc. */
591da177e4SLinus Torvalds unsigned long id; /* From pointer, most of the time */
601da177e4SLinus Torvalds unsigned int tstamp;
61f1c9e30bSPete Zaitcev int busnum;
6230c7431dSPete Zaitcev char devnum;
6330c7431dSPete Zaitcev char epnum;
6430c7431dSPete Zaitcev char is_in;
6530c7431dSPete Zaitcev char xfertype;
661da177e4SLinus Torvalds int length; /* Depends on type: xfer length or act length */
671da177e4SLinus Torvalds int status;
68f1c9e30bSPete Zaitcev int interval;
69f1c9e30bSPete Zaitcev int start_frame;
70f1c9e30bSPete Zaitcev int error_count;
71ae0d6cceSPete Zaitcev char setup_flag;
721da177e4SLinus Torvalds char data_flag;
73f1c9e30bSPete Zaitcev int numdesc; /* Full number */
74f1c9e30bSPete Zaitcev struct mon_iso_desc isodesc[ISODESC_MAX];
75ae0d6cceSPete Zaitcev unsigned char setup[SETUP_MAX];
761da177e4SLinus Torvalds unsigned char data[DATA_MAX];
771da177e4SLinus Torvalds };
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds #define SLAB_NAME_SZ 30
801da177e4SLinus Torvalds struct mon_reader_text {
81e18b890bSChristoph Lameter struct kmem_cache *e_slab;
821da177e4SLinus Torvalds int nevents;
831da177e4SLinus Torvalds struct list_head e_list;
841da177e4SLinus Torvalds struct mon_reader r; /* In C, parent class can be placed anywhere */
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds wait_queue_head_t wait;
871da177e4SLinus Torvalds int printf_size;
88a5f59683SPete Zaitcev size_t printf_offset;
89a5f59683SPete Zaitcev size_t printf_togo;
901da177e4SLinus Torvalds char *printf_buf;
914186ecf8SArjan van de Ven struct mutex printf_lock;
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds char slab_name[SLAB_NAME_SZ];
941da177e4SLinus Torvalds };
951da177e4SLinus Torvalds
966f23ee1fSPete Zaitcev static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
976f23ee1fSPete Zaitcev
9851cc5068SAlexey Dobriyan static void mon_text_ctor(void *);
991da177e4SLinus Torvalds
100f1c9e30bSPete Zaitcev struct mon_text_ptr {
101f1c9e30bSPete Zaitcev int cnt, limit;
102f1c9e30bSPete Zaitcev char *pbuf;
103f1c9e30bSPete Zaitcev };
104f1c9e30bSPete Zaitcev
105f1c9e30bSPete Zaitcev static struct mon_event_text *
106f1c9e30bSPete Zaitcev mon_text_read_wait(struct mon_reader_text *rp, struct file *file);
107f1c9e30bSPete Zaitcev static void mon_text_read_head_t(struct mon_reader_text *rp,
108f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
109f1c9e30bSPete Zaitcev static void mon_text_read_head_u(struct mon_reader_text *rp,
110f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
111f1c9e30bSPete Zaitcev static void mon_text_read_statset(struct mon_reader_text *rp,
112f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
113f1c9e30bSPete Zaitcev static void mon_text_read_intstat(struct mon_reader_text *rp,
114f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
115f1c9e30bSPete Zaitcev static void mon_text_read_isostat(struct mon_reader_text *rp,
116f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
117f1c9e30bSPete Zaitcev static void mon_text_read_isodesc(struct mon_reader_text *rp,
118f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
119f1c9e30bSPete Zaitcev static void mon_text_read_data(struct mon_reader_text *rp,
120f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep);
121f1c9e30bSPete Zaitcev
1221da177e4SLinus Torvalds /*
1231da177e4SLinus Torvalds * mon_text_submit
1241da177e4SLinus Torvalds * mon_text_complete
1251da177e4SLinus Torvalds *
1261da177e4SLinus Torvalds * May be called from an interrupt.
1271da177e4SLinus Torvalds *
1281da177e4SLinus Torvalds * This is called with the whole mon_bus locked, so no additional lock.
1291da177e4SLinus Torvalds */
1301da177e4SLinus Torvalds
mon_text_get_setup(struct mon_event_text * ep,struct urb * urb,char ev_type,struct mon_bus * mbus)131ae0d6cceSPete Zaitcev static inline char mon_text_get_setup(struct mon_event_text *ep,
1324d6cd483SAlan Stern struct urb *urb, char ev_type, struct mon_bus *mbus)
133ae0d6cceSPete Zaitcev {
134ae0d6cceSPete Zaitcev
13518ea5d00SAlan Stern if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
136ae0d6cceSPete Zaitcev return '-';
137ae0d6cceSPete Zaitcev
138ae0d6cceSPete Zaitcev if (urb->setup_packet == NULL)
139ae0d6cceSPete Zaitcev return 'Z'; /* '0' would be not as pretty. */
140ae0d6cceSPete Zaitcev
141ae0d6cceSPete Zaitcev memcpy(ep->setup, urb->setup_packet, SETUP_MAX);
142ae0d6cceSPete Zaitcev return 0;
143ae0d6cceSPete Zaitcev }
144ae0d6cceSPete Zaitcev
mon_text_get_data(struct mon_event_text * ep,struct urb * urb,int len,char ev_type,struct mon_bus * mbus)1451da177e4SLinus Torvalds static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
1464d6cd483SAlan Stern int len, char ev_type, struct mon_bus *mbus)
1471da177e4SLinus Torvalds {
148b375e116SAlan Stern void *src;
149b375e116SAlan Stern
1501da177e4SLinus Torvalds if (len <= 0)
1511da177e4SLinus Torvalds return 'L';
15202568396SPete Zaitcev if (len >= DATA_MAX)
15302568396SPete Zaitcev len = DATA_MAX;
1541da177e4SLinus Torvalds
15518ea5d00SAlan Stern if (ep->is_in) {
156f1c9e30bSPete Zaitcev if (ev_type != 'C')
1571da177e4SLinus Torvalds return '<';
1581da177e4SLinus Torvalds } else {
159f1c9e30bSPete Zaitcev if (ev_type != 'S')
1601da177e4SLinus Torvalds return '>';
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds
163b375e116SAlan Stern if (urb->num_sgs == 0) {
164b375e116SAlan Stern src = urb->transfer_buffer;
165b375e116SAlan Stern if (src == NULL)
16602568396SPete Zaitcev return 'Z'; /* '0' would be not as pretty. */
167b375e116SAlan Stern } else {
168910f8d0cSMatthew Wilcox struct scatterlist *sg = urb->sg;
16902568396SPete Zaitcev
170ff9c895fSAlan Stern if (PageHighMem(sg_page(sg)))
171b375e116SAlan Stern return 'D';
172b375e116SAlan Stern
173b375e116SAlan Stern /* For the text interface we copy only the first sg buffer */
174b375e116SAlan Stern len = min_t(int, sg->length, len);
175b375e116SAlan Stern src = sg_virt(sg);
176b375e116SAlan Stern }
177b375e116SAlan Stern
178b375e116SAlan Stern memcpy(ep->data, src, len);
1791da177e4SLinus Torvalds return 0;
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds
mon_get_timestamp(void)1821da177e4SLinus Torvalds static inline unsigned int mon_get_timestamp(void)
1831da177e4SLinus Torvalds {
184ec4dca8bSTina Ruchandani struct timespec64 now;
1851da177e4SLinus Torvalds unsigned int stamp;
1861da177e4SLinus Torvalds
187ec4dca8bSTina Ruchandani ktime_get_ts64(&now);
188ec4dca8bSTina Ruchandani stamp = now.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */
189ec4dca8bSTina Ruchandani stamp = stamp * USEC_PER_SEC + now.tv_nsec / NSEC_PER_USEC;
1901da177e4SLinus Torvalds return stamp;
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds
mon_text_event(struct mon_reader_text * rp,struct urb * urb,char ev_type,int status)1931da177e4SLinus Torvalds static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
1949347d51cSAlan Stern char ev_type, int status)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds struct mon_event_text *ep;
1971da177e4SLinus Torvalds unsigned int stamp;
198f1c9e30bSPete Zaitcev struct usb_iso_packet_descriptor *fp;
199f1c9e30bSPete Zaitcev struct mon_iso_desc *dp;
200f1c9e30bSPete Zaitcev int i, ndesc;
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds stamp = mon_get_timestamp();
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds if (rp->nevents >= EVENT_MAX ||
20554e6ecb2SChristoph Lameter (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) {
2061da177e4SLinus Torvalds rp->r.m_bus->cnt_text_lost++;
2071da177e4SLinus Torvalds return;
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds ep->type = ev_type;
2111da177e4SLinus Torvalds ep->id = (unsigned long) urb;
212ecb658d3SPete Zaitcev ep->busnum = urb->dev->bus->busnum;
21318ea5d00SAlan Stern ep->devnum = urb->dev->devnum;
21418ea5d00SAlan Stern ep->epnum = usb_endpoint_num(&urb->ep->desc);
21518ea5d00SAlan Stern ep->xfertype = usb_endpoint_type(&urb->ep->desc);
21618ea5d00SAlan Stern ep->is_in = usb_urb_dir_in(urb);
2171da177e4SLinus Torvalds ep->tstamp = stamp;
2181da177e4SLinus Torvalds ep->length = (ev_type == 'S') ?
2191da177e4SLinus Torvalds urb->transfer_buffer_length : urb->actual_length;
2201da177e4SLinus Torvalds /* Collecting status makes debugging sense for submits, too */
2219347d51cSAlan Stern ep->status = status;
2221da177e4SLinus Torvalds
22318ea5d00SAlan Stern if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
224f1c9e30bSPete Zaitcev ep->interval = urb->interval;
22518ea5d00SAlan Stern } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
226f1c9e30bSPete Zaitcev ep->interval = urb->interval;
227f1c9e30bSPete Zaitcev ep->start_frame = urb->start_frame;
228f1c9e30bSPete Zaitcev ep->error_count = urb->error_count;
229f1c9e30bSPete Zaitcev }
230f1c9e30bSPete Zaitcev ep->numdesc = urb->number_of_packets;
23118ea5d00SAlan Stern if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
23218ea5d00SAlan Stern urb->number_of_packets > 0) {
233f1c9e30bSPete Zaitcev if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
234f1c9e30bSPete Zaitcev ndesc = ISODESC_MAX;
235f1c9e30bSPete Zaitcev fp = urb->iso_frame_desc;
236f1c9e30bSPete Zaitcev dp = ep->isodesc;
237f1c9e30bSPete Zaitcev for (i = 0; i < ndesc; i++) {
238f1c9e30bSPete Zaitcev dp->status = fp->status;
239f1c9e30bSPete Zaitcev dp->offset = fp->offset;
240f1c9e30bSPete Zaitcev dp->length = (ev_type == 'S') ?
241f1c9e30bSPete Zaitcev fp->length : fp->actual_length;
242f1c9e30bSPete Zaitcev fp++;
243f1c9e30bSPete Zaitcev dp++;
244f1c9e30bSPete Zaitcev }
245d25bc4dbSPete Zaitcev /* Wasteful, but simple to understand: ISO 'C' is sparse. */
246d25bc4dbSPete Zaitcev if (ev_type == 'C')
247d25bc4dbSPete Zaitcev ep->length = urb->transfer_buffer_length;
248f1c9e30bSPete Zaitcev }
249f1c9e30bSPete Zaitcev
2504d6cd483SAlan Stern ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus);
2514d6cd483SAlan Stern ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type,
2524d6cd483SAlan Stern rp->r.m_bus);
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds rp->nevents++;
2551da177e4SLinus Torvalds list_add_tail(&ep->e_link, &rp->e_list);
2561da177e4SLinus Torvalds wake_up(&rp->wait);
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds
mon_text_submit(void * data,struct urb * urb)2591da177e4SLinus Torvalds static void mon_text_submit(void *data, struct urb *urb)
2601da177e4SLinus Torvalds {
2611da177e4SLinus Torvalds struct mon_reader_text *rp = data;
2629347d51cSAlan Stern mon_text_event(rp, urb, 'S', -EINPROGRESS);
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds
mon_text_complete(void * data,struct urb * urb,int status)2659347d51cSAlan Stern static void mon_text_complete(void *data, struct urb *urb, int status)
2661da177e4SLinus Torvalds {
2671da177e4SLinus Torvalds struct mon_reader_text *rp = data;
2689347d51cSAlan Stern mon_text_event(rp, urb, 'C', status);
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds
mon_text_error(void * data,struct urb * urb,int error)27112e72feaSPete Zaitcev static void mon_text_error(void *data, struct urb *urb, int error)
27212e72feaSPete Zaitcev {
27312e72feaSPete Zaitcev struct mon_reader_text *rp = data;
27412e72feaSPete Zaitcev struct mon_event_text *ep;
27512e72feaSPete Zaitcev
27612e72feaSPete Zaitcev if (rp->nevents >= EVENT_MAX ||
27754e6ecb2SChristoph Lameter (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) {
27812e72feaSPete Zaitcev rp->r.m_bus->cnt_text_lost++;
27912e72feaSPete Zaitcev return;
28012e72feaSPete Zaitcev }
28112e72feaSPete Zaitcev
28212e72feaSPete Zaitcev ep->type = 'E';
28312e72feaSPete Zaitcev ep->id = (unsigned long) urb;
2842bc0d109SPete Zaitcev ep->busnum = urb->dev->bus->busnum;
28518ea5d00SAlan Stern ep->devnum = urb->dev->devnum;
28618ea5d00SAlan Stern ep->epnum = usb_endpoint_num(&urb->ep->desc);
28718ea5d00SAlan Stern ep->xfertype = usb_endpoint_type(&urb->ep->desc);
28818ea5d00SAlan Stern ep->is_in = usb_urb_dir_in(urb);
2892bc0d109SPete Zaitcev ep->tstamp = mon_get_timestamp();
29012e72feaSPete Zaitcev ep->length = 0;
29112e72feaSPete Zaitcev ep->status = error;
29212e72feaSPete Zaitcev
29312e72feaSPete Zaitcev ep->setup_flag = '-';
29412e72feaSPete Zaitcev ep->data_flag = 'E';
29512e72feaSPete Zaitcev
29612e72feaSPete Zaitcev rp->nevents++;
29712e72feaSPete Zaitcev list_add_tail(&ep->e_link, &rp->e_list);
29812e72feaSPete Zaitcev wake_up(&rp->wait);
29912e72feaSPete Zaitcev }
30012e72feaSPete Zaitcev
3011da177e4SLinus Torvalds /*
3021da177e4SLinus Torvalds * Fetch next event from the circular buffer.
3031da177e4SLinus Torvalds */
mon_text_fetch(struct mon_reader_text * rp,struct mon_bus * mbus)3041da177e4SLinus Torvalds static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp,
3051da177e4SLinus Torvalds struct mon_bus *mbus)
3061da177e4SLinus Torvalds {
3071da177e4SLinus Torvalds struct list_head *p;
3081da177e4SLinus Torvalds unsigned long flags;
3091da177e4SLinus Torvalds
3101da177e4SLinus Torvalds spin_lock_irqsave(&mbus->lock, flags);
3111da177e4SLinus Torvalds if (list_empty(&rp->e_list)) {
3121da177e4SLinus Torvalds spin_unlock_irqrestore(&mbus->lock, flags);
3131da177e4SLinus Torvalds return NULL;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds p = rp->e_list.next;
3161da177e4SLinus Torvalds list_del(p);
3171da177e4SLinus Torvalds --rp->nevents;
3181da177e4SLinus Torvalds spin_unlock_irqrestore(&mbus->lock, flags);
3191da177e4SLinus Torvalds return list_entry(p, struct mon_event_text, e_link);
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
3221da177e4SLinus Torvalds /*
3231da177e4SLinus Torvalds */
mon_text_open(struct inode * inode,struct file * file)3241da177e4SLinus Torvalds static int mon_text_open(struct inode *inode, struct file *file)
3251da177e4SLinus Torvalds {
3261da177e4SLinus Torvalds struct mon_bus *mbus;
3271da177e4SLinus Torvalds struct mon_reader_text *rp;
3281da177e4SLinus Torvalds int rc;
3291da177e4SLinus Torvalds
3304186ecf8SArjan van de Ven mutex_lock(&mon_lock);
3318e18e294STheodore Ts'o mbus = inode->i_private;
3321da177e4SLinus Torvalds
33380b6ca48SEric Sesterhenn rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
3341da177e4SLinus Torvalds if (rp == NULL) {
3351da177e4SLinus Torvalds rc = -ENOMEM;
3361da177e4SLinus Torvalds goto err_alloc;
3371da177e4SLinus Torvalds }
3381da177e4SLinus Torvalds INIT_LIST_HEAD(&rp->e_list);
3391da177e4SLinus Torvalds init_waitqueue_head(&rp->wait);
3404186ecf8SArjan van de Ven mutex_init(&rp->printf_lock);
3411da177e4SLinus Torvalds
3421da177e4SLinus Torvalds rp->printf_size = PRINTF_DFL;
3431da177e4SLinus Torvalds rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL);
3441da177e4SLinus Torvalds if (rp->printf_buf == NULL) {
3451da177e4SLinus Torvalds rc = -ENOMEM;
3461da177e4SLinus Torvalds goto err_alloc_pr;
3471da177e4SLinus Torvalds }
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds rp->r.m_bus = mbus;
3501da177e4SLinus Torvalds rp->r.r_data = rp;
3511da177e4SLinus Torvalds rp->r.rnf_submit = mon_text_submit;
35212e72feaSPete Zaitcev rp->r.rnf_error = mon_text_error;
3531da177e4SLinus Torvalds rp->r.rnf_complete = mon_text_complete;
3541da177e4SLinus Torvalds
355ecb658d3SPete Zaitcev snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
3561da177e4SLinus Torvalds rp->e_slab = kmem_cache_create(rp->slab_name,
3571da177e4SLinus Torvalds sizeof(struct mon_event_text), sizeof(long), 0,
35820c2df83SPaul Mundt mon_text_ctor);
3591da177e4SLinus Torvalds if (rp->e_slab == NULL) {
3601da177e4SLinus Torvalds rc = -ENOMEM;
3611da177e4SLinus Torvalds goto err_slab;
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds mon_reader_add(mbus, &rp->r);
3651da177e4SLinus Torvalds
3661da177e4SLinus Torvalds file->private_data = rp;
3674186ecf8SArjan van de Ven mutex_unlock(&mon_lock);
3681da177e4SLinus Torvalds return 0;
3691da177e4SLinus Torvalds
3701da177e4SLinus Torvalds // err_busy:
3711da177e4SLinus Torvalds // kmem_cache_destroy(rp->e_slab);
3721da177e4SLinus Torvalds err_slab:
3731da177e4SLinus Torvalds kfree(rp->printf_buf);
3741da177e4SLinus Torvalds err_alloc_pr:
3751da177e4SLinus Torvalds kfree(rp);
3761da177e4SLinus Torvalds err_alloc:
3774186ecf8SArjan van de Ven mutex_unlock(&mon_lock);
3781da177e4SLinus Torvalds return rc;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds
mon_text_copy_to_user(struct mon_reader_text * rp,char __user * const buf,const size_t nbytes)381a5f59683SPete Zaitcev static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
382a5f59683SPete Zaitcev char __user * const buf, const size_t nbytes)
383a5f59683SPete Zaitcev {
384a5f59683SPete Zaitcev const size_t togo = min(nbytes, rp->printf_togo);
385a5f59683SPete Zaitcev
386a5f59683SPete Zaitcev if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
387a5f59683SPete Zaitcev return -EFAULT;
388a5f59683SPete Zaitcev rp->printf_togo -= togo;
389a5f59683SPete Zaitcev rp->printf_offset += togo;
390a5f59683SPete Zaitcev return togo;
391a5f59683SPete Zaitcev }
392a5f59683SPete Zaitcev
393a5f59683SPete Zaitcev /* ppos is not advanced since the llseek operation is not permitted. */
mon_text_read_t(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)394f1c9e30bSPete Zaitcev static ssize_t mon_text_read_t(struct file *file, char __user *buf,
3951da177e4SLinus Torvalds size_t nbytes, loff_t *ppos)
3961da177e4SLinus Torvalds {
3971da177e4SLinus Torvalds struct mon_reader_text *rp = file->private_data;
398f1c9e30bSPete Zaitcev struct mon_event_text *ep;
399f1c9e30bSPete Zaitcev struct mon_text_ptr ptr;
400a5f59683SPete Zaitcev ssize_t ret;
401a5f59683SPete Zaitcev
402a5f59683SPete Zaitcev mutex_lock(&rp->printf_lock);
403a5f59683SPete Zaitcev
404a5f59683SPete Zaitcev if (rp->printf_togo == 0) {
405f1c9e30bSPete Zaitcev
40646c236dcSJulia Lawall ep = mon_text_read_wait(rp, file);
407a5f59683SPete Zaitcev if (IS_ERR(ep)) {
408a5f59683SPete Zaitcev mutex_unlock(&rp->printf_lock);
409f1c9e30bSPete Zaitcev return PTR_ERR(ep);
410a5f59683SPete Zaitcev }
411f1c9e30bSPete Zaitcev ptr.cnt = 0;
412f1c9e30bSPete Zaitcev ptr.pbuf = rp->printf_buf;
413f1c9e30bSPete Zaitcev ptr.limit = rp->printf_size;
414f1c9e30bSPete Zaitcev
415f1c9e30bSPete Zaitcev mon_text_read_head_t(rp, &ptr, ep);
416f1c9e30bSPete Zaitcev mon_text_read_statset(rp, &ptr, ep);
417*0de005d0STakashi Iwai ptr.cnt += scnprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
418f1c9e30bSPete Zaitcev " %d", ep->length);
419f1c9e30bSPete Zaitcev mon_text_read_data(rp, &ptr, ep);
420f1c9e30bSPete Zaitcev
421a5f59683SPete Zaitcev rp->printf_togo = ptr.cnt;
422a5f59683SPete Zaitcev rp->printf_offset = 0;
423a5f59683SPete Zaitcev
424f1c9e30bSPete Zaitcev kmem_cache_free(rp->e_slab, ep);
425f1c9e30bSPete Zaitcev }
426f1c9e30bSPete Zaitcev
427a5f59683SPete Zaitcev ret = mon_text_copy_to_user(rp, buf, nbytes);
428a5f59683SPete Zaitcev mutex_unlock(&rp->printf_lock);
429a5f59683SPete Zaitcev return ret;
430a5f59683SPete Zaitcev }
431a5f59683SPete Zaitcev
432a5f59683SPete Zaitcev /* ppos is not advanced since the llseek operation is not permitted. */
mon_text_read_u(struct file * file,char __user * buf,size_t nbytes,loff_t * ppos)433f1c9e30bSPete Zaitcev static ssize_t mon_text_read_u(struct file *file, char __user *buf,
434f1c9e30bSPete Zaitcev size_t nbytes, loff_t *ppos)
435f1c9e30bSPete Zaitcev {
436f1c9e30bSPete Zaitcev struct mon_reader_text *rp = file->private_data;
437f1c9e30bSPete Zaitcev struct mon_event_text *ep;
438f1c9e30bSPete Zaitcev struct mon_text_ptr ptr;
439a5f59683SPete Zaitcev ssize_t ret;
440a5f59683SPete Zaitcev
441a5f59683SPete Zaitcev mutex_lock(&rp->printf_lock);
442a5f59683SPete Zaitcev
443a5f59683SPete Zaitcev if (rp->printf_togo == 0) {
444f1c9e30bSPete Zaitcev
44546c236dcSJulia Lawall ep = mon_text_read_wait(rp, file);
446a5f59683SPete Zaitcev if (IS_ERR(ep)) {
447a5f59683SPete Zaitcev mutex_unlock(&rp->printf_lock);
448f1c9e30bSPete Zaitcev return PTR_ERR(ep);
449a5f59683SPete Zaitcev }
450f1c9e30bSPete Zaitcev ptr.cnt = 0;
451f1c9e30bSPete Zaitcev ptr.pbuf = rp->printf_buf;
452f1c9e30bSPete Zaitcev ptr.limit = rp->printf_size;
453f1c9e30bSPete Zaitcev
454f1c9e30bSPete Zaitcev mon_text_read_head_u(rp, &ptr, ep);
455f1c9e30bSPete Zaitcev if (ep->type == 'E') {
456f1c9e30bSPete Zaitcev mon_text_read_statset(rp, &ptr, ep);
45718ea5d00SAlan Stern } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
458f1c9e30bSPete Zaitcev mon_text_read_isostat(rp, &ptr, ep);
459f1c9e30bSPete Zaitcev mon_text_read_isodesc(rp, &ptr, ep);
46018ea5d00SAlan Stern } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
461f1c9e30bSPete Zaitcev mon_text_read_intstat(rp, &ptr, ep);
462f1c9e30bSPete Zaitcev } else {
463f1c9e30bSPete Zaitcev mon_text_read_statset(rp, &ptr, ep);
464f1c9e30bSPete Zaitcev }
465*0de005d0STakashi Iwai ptr.cnt += scnprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
466f1c9e30bSPete Zaitcev " %d", ep->length);
467f1c9e30bSPete Zaitcev mon_text_read_data(rp, &ptr, ep);
468f1c9e30bSPete Zaitcev
469a5f59683SPete Zaitcev rp->printf_togo = ptr.cnt;
470a5f59683SPete Zaitcev rp->printf_offset = 0;
471a5f59683SPete Zaitcev
472f1c9e30bSPete Zaitcev kmem_cache_free(rp->e_slab, ep);
473a5f59683SPete Zaitcev }
474a5f59683SPete Zaitcev
475a5f59683SPete Zaitcev ret = mon_text_copy_to_user(rp, buf, nbytes);
476a5f59683SPete Zaitcev mutex_unlock(&rp->printf_lock);
477a5f59683SPete Zaitcev return ret;
478f1c9e30bSPete Zaitcev }
479f1c9e30bSPete Zaitcev
mon_text_read_wait(struct mon_reader_text * rp,struct file * file)480f1c9e30bSPete Zaitcev static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
481f1c9e30bSPete Zaitcev struct file *file)
482f1c9e30bSPete Zaitcev {
4831da177e4SLinus Torvalds struct mon_bus *mbus = rp->r.m_bus;
4841da177e4SLinus Torvalds DECLARE_WAITQUEUE(waita, current);
4851da177e4SLinus Torvalds struct mon_event_text *ep;
4861da177e4SLinus Torvalds
4871da177e4SLinus Torvalds add_wait_queue(&rp->wait, &waita);
4881da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE);
4891da177e4SLinus Torvalds while ((ep = mon_text_fetch(rp, mbus)) == NULL) {
4901da177e4SLinus Torvalds if (file->f_flags & O_NONBLOCK) {
4911da177e4SLinus Torvalds set_current_state(TASK_RUNNING);
4921da177e4SLinus Torvalds remove_wait_queue(&rp->wait, &waita);
493f1c9e30bSPete Zaitcev return ERR_PTR(-EWOULDBLOCK);
4941da177e4SLinus Torvalds }
4951da177e4SLinus Torvalds /*
4961da177e4SLinus Torvalds * We do not count nwaiters, because ->release is supposed
4971da177e4SLinus Torvalds * to be called when all openers are gone only.
4981da177e4SLinus Torvalds */
4991da177e4SLinus Torvalds schedule();
5001da177e4SLinus Torvalds if (signal_pending(current)) {
5011da177e4SLinus Torvalds remove_wait_queue(&rp->wait, &waita);
502f1c9e30bSPete Zaitcev return ERR_PTR(-EINTR);
5031da177e4SLinus Torvalds }
5041da177e4SLinus Torvalds set_current_state(TASK_INTERRUPTIBLE);
5051da177e4SLinus Torvalds }
5061da177e4SLinus Torvalds set_current_state(TASK_RUNNING);
5071da177e4SLinus Torvalds remove_wait_queue(&rp->wait, &waita);
508f1c9e30bSPete Zaitcev return ep;
509f1c9e30bSPete Zaitcev }
5101da177e4SLinus Torvalds
mon_text_read_head_t(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)511f1c9e30bSPete Zaitcev static void mon_text_read_head_t(struct mon_reader_text *rp,
512f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
513f1c9e30bSPete Zaitcev {
514f1c9e30bSPete Zaitcev char udir, utype;
5151da177e4SLinus Torvalds
51618ea5d00SAlan Stern udir = (ep->is_in ? 'i' : 'o');
51718ea5d00SAlan Stern switch (ep->xfertype) {
51818ea5d00SAlan Stern case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
51918ea5d00SAlan Stern case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
52018ea5d00SAlan Stern case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
5211da177e4SLinus Torvalds default: /* PIPE_BULK */ utype = 'B';
5221da177e4SLinus Torvalds }
523*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
524ae0d6cceSPete Zaitcev "%lx %u %c %c%c:%03u:%02u",
5251da177e4SLinus Torvalds ep->id, ep->tstamp, ep->type,
52618ea5d00SAlan Stern utype, udir, ep->devnum, ep->epnum);
527f1c9e30bSPete Zaitcev }
528f1c9e30bSPete Zaitcev
mon_text_read_head_u(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)529f1c9e30bSPete Zaitcev static void mon_text_read_head_u(struct mon_reader_text *rp,
530f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
531f1c9e30bSPete Zaitcev {
532f1c9e30bSPete Zaitcev char udir, utype;
533f1c9e30bSPete Zaitcev
53418ea5d00SAlan Stern udir = (ep->is_in ? 'i' : 'o');
53518ea5d00SAlan Stern switch (ep->xfertype) {
53618ea5d00SAlan Stern case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
53718ea5d00SAlan Stern case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
53818ea5d00SAlan Stern case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
539f1c9e30bSPete Zaitcev default: /* PIPE_BULK */ utype = 'B';
540f1c9e30bSPete Zaitcev }
541*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
542f1c9e30bSPete Zaitcev "%lx %u %c %c%c:%d:%03u:%u",
543f1c9e30bSPete Zaitcev ep->id, ep->tstamp, ep->type,
54418ea5d00SAlan Stern utype, udir, ep->busnum, ep->devnum, ep->epnum);
545f1c9e30bSPete Zaitcev }
546f1c9e30bSPete Zaitcev
mon_text_read_statset(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)547f1c9e30bSPete Zaitcev static void mon_text_read_statset(struct mon_reader_text *rp,
548f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
549f1c9e30bSPete Zaitcev {
550ae0d6cceSPete Zaitcev
551ae0d6cceSPete Zaitcev if (ep->setup_flag == 0) { /* Setup packet is present and captured */
552*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
553ae0d6cceSPete Zaitcev " s %02x %02x %04x %04x %04x",
554ae0d6cceSPete Zaitcev ep->setup[0],
555ae0d6cceSPete Zaitcev ep->setup[1],
556ae0d6cceSPete Zaitcev (ep->setup[3] << 8) | ep->setup[2],
557ae0d6cceSPete Zaitcev (ep->setup[5] << 8) | ep->setup[4],
558ae0d6cceSPete Zaitcev (ep->setup[7] << 8) | ep->setup[6]);
559ae0d6cceSPete Zaitcev } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
560*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
561ae0d6cceSPete Zaitcev " %c __ __ ____ ____ ____", ep->setup_flag);
562ae0d6cceSPete Zaitcev } else { /* No setup for this kind of URB */
563*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
564f1c9e30bSPete Zaitcev " %d", ep->status);
565ae0d6cceSPete Zaitcev }
566f1c9e30bSPete Zaitcev }
567f1c9e30bSPete Zaitcev
mon_text_read_intstat(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)568f1c9e30bSPete Zaitcev static void mon_text_read_intstat(struct mon_reader_text *rp,
569f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
570f1c9e30bSPete Zaitcev {
571*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
572f1c9e30bSPete Zaitcev " %d:%d", ep->status, ep->interval);
573f1c9e30bSPete Zaitcev }
574f1c9e30bSPete Zaitcev
mon_text_read_isostat(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)575f1c9e30bSPete Zaitcev static void mon_text_read_isostat(struct mon_reader_text *rp,
576f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
577f1c9e30bSPete Zaitcev {
578f1c9e30bSPete Zaitcev if (ep->type == 'S') {
579*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
580f1c9e30bSPete Zaitcev " %d:%d:%d", ep->status, ep->interval, ep->start_frame);
581f1c9e30bSPete Zaitcev } else {
582*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
583f1c9e30bSPete Zaitcev " %d:%d:%d:%d",
584f1c9e30bSPete Zaitcev ep->status, ep->interval, ep->start_frame, ep->error_count);
585f1c9e30bSPete Zaitcev }
586f1c9e30bSPete Zaitcev }
587f1c9e30bSPete Zaitcev
mon_text_read_isodesc(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)588f1c9e30bSPete Zaitcev static void mon_text_read_isodesc(struct mon_reader_text *rp,
589f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
590f1c9e30bSPete Zaitcev {
591f1c9e30bSPete Zaitcev int ndesc; /* Display this many */
592f1c9e30bSPete Zaitcev int i;
593f1c9e30bSPete Zaitcev const struct mon_iso_desc *dp;
594f1c9e30bSPete Zaitcev
595*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
596f1c9e30bSPete Zaitcev " %d", ep->numdesc);
597f1c9e30bSPete Zaitcev ndesc = ep->numdesc;
598f1c9e30bSPete Zaitcev if (ndesc > ISODESC_MAX)
599f1c9e30bSPete Zaitcev ndesc = ISODESC_MAX;
600f1c9e30bSPete Zaitcev if (ndesc < 0)
601f1c9e30bSPete Zaitcev ndesc = 0;
602f1c9e30bSPete Zaitcev dp = ep->isodesc;
603f1c9e30bSPete Zaitcev for (i = 0; i < ndesc; i++) {
604*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
605f1c9e30bSPete Zaitcev " %d:%u:%u", dp->status, dp->offset, dp->length);
606f1c9e30bSPete Zaitcev dp++;
607f1c9e30bSPete Zaitcev }
608f1c9e30bSPete Zaitcev }
609f1c9e30bSPete Zaitcev
mon_text_read_data(struct mon_reader_text * rp,struct mon_text_ptr * p,const struct mon_event_text * ep)610f1c9e30bSPete Zaitcev static void mon_text_read_data(struct mon_reader_text *rp,
611f1c9e30bSPete Zaitcev struct mon_text_ptr *p, const struct mon_event_text *ep)
612f1c9e30bSPete Zaitcev {
613f1c9e30bSPete Zaitcev int data_len, i;
6141da177e4SLinus Torvalds
6151da177e4SLinus Torvalds if ((data_len = ep->length) > 0) {
6161da177e4SLinus Torvalds if (ep->data_flag == 0) {
617*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
618f1c9e30bSPete Zaitcev " =");
6191da177e4SLinus Torvalds if (data_len >= DATA_MAX)
6201da177e4SLinus Torvalds data_len = DATA_MAX;
6211da177e4SLinus Torvalds for (i = 0; i < data_len; i++) {
6221da177e4SLinus Torvalds if (i % 4 == 0) {
623*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt,
624f1c9e30bSPete Zaitcev p->limit - p->cnt,
6251da177e4SLinus Torvalds " ");
6261da177e4SLinus Torvalds }
627*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt,
628f1c9e30bSPete Zaitcev p->limit - p->cnt,
6291da177e4SLinus Torvalds "%02x", ep->data[i]);
6301da177e4SLinus Torvalds }
631*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
632f1c9e30bSPete Zaitcev "\n");
6331da177e4SLinus Torvalds } else {
634*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
6351da177e4SLinus Torvalds " %c\n", ep->data_flag);
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds } else {
638*0de005d0STakashi Iwai p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n");
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds
mon_text_release(struct inode * inode,struct file * file)6421da177e4SLinus Torvalds static int mon_text_release(struct inode *inode, struct file *file)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds struct mon_reader_text *rp = file->private_data;
6451da177e4SLinus Torvalds struct mon_bus *mbus;
6461da177e4SLinus Torvalds /* unsigned long flags; */
6471da177e4SLinus Torvalds struct list_head *p;
6481da177e4SLinus Torvalds struct mon_event_text *ep;
6491da177e4SLinus Torvalds
6504186ecf8SArjan van de Ven mutex_lock(&mon_lock);
6518e18e294STheodore Ts'o mbus = inode->i_private;
6521da177e4SLinus Torvalds
6531da177e4SLinus Torvalds if (mbus->nreaders <= 0) {
6541da177e4SLinus Torvalds printk(KERN_ERR TAG ": consistency error on close\n");
6554186ecf8SArjan van de Ven mutex_unlock(&mon_lock);
6561da177e4SLinus Torvalds return 0;
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds mon_reader_del(mbus, &rp->r);
6591da177e4SLinus Torvalds
6601da177e4SLinus Torvalds /*
6611da177e4SLinus Torvalds * In theory, e_list is protected by mbus->lock. However,
6621da177e4SLinus Torvalds * after mon_reader_del has finished, the following is the case:
6631da177e4SLinus Torvalds * - we are not on reader list anymore, so new events won't be added;
6641da177e4SLinus Torvalds * - whole mbus may be dropped if it was orphaned.
6651da177e4SLinus Torvalds * So, we better not touch mbus.
6661da177e4SLinus Torvalds */
6671da177e4SLinus Torvalds /* spin_lock_irqsave(&mbus->lock, flags); */
6681da177e4SLinus Torvalds while (!list_empty(&rp->e_list)) {
6691da177e4SLinus Torvalds p = rp->e_list.next;
6701da177e4SLinus Torvalds ep = list_entry(p, struct mon_event_text, e_link);
6711da177e4SLinus Torvalds list_del(p);
6721da177e4SLinus Torvalds --rp->nevents;
6731da177e4SLinus Torvalds kmem_cache_free(rp->e_slab, ep);
6741da177e4SLinus Torvalds }
6751da177e4SLinus Torvalds /* spin_unlock_irqrestore(&mbus->lock, flags); */
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds kmem_cache_destroy(rp->e_slab);
6781da177e4SLinus Torvalds kfree(rp->printf_buf);
6791da177e4SLinus Torvalds kfree(rp);
6801da177e4SLinus Torvalds
6814186ecf8SArjan van de Ven mutex_unlock(&mon_lock);
6821da177e4SLinus Torvalds return 0;
6831da177e4SLinus Torvalds }
6841da177e4SLinus Torvalds
685f1c9e30bSPete Zaitcev static const struct file_operations mon_fops_text_t = {
6861da177e4SLinus Torvalds .owner = THIS_MODULE,
6871da177e4SLinus Torvalds .open = mon_text_open,
6881da177e4SLinus Torvalds .llseek = no_llseek,
689f1c9e30bSPete Zaitcev .read = mon_text_read_t,
690f1c9e30bSPete Zaitcev .release = mon_text_release,
691f1c9e30bSPete Zaitcev };
692f1c9e30bSPete Zaitcev
693f1c9e30bSPete Zaitcev static const struct file_operations mon_fops_text_u = {
694f1c9e30bSPete Zaitcev .owner = THIS_MODULE,
695f1c9e30bSPete Zaitcev .open = mon_text_open,
696f1c9e30bSPete Zaitcev .llseek = no_llseek,
697f1c9e30bSPete Zaitcev .read = mon_text_read_u,
6981da177e4SLinus Torvalds .release = mon_text_release,
6991da177e4SLinus Torvalds };
7001da177e4SLinus Torvalds
mon_text_add(struct mon_bus * mbus,const struct usb_bus * ubus)701ce7cd137SPete Zaitcev int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
7026f23ee1fSPete Zaitcev {
7036f23ee1fSPete Zaitcev enum { NAMESZ = 10 };
7046f23ee1fSPete Zaitcev char name[NAMESZ];
705ce7cd137SPete Zaitcev int busnum = ubus? ubus->busnum: 0;
7066f23ee1fSPete Zaitcev int rc;
7076f23ee1fSPete Zaitcev
7088dec92b2STobias Klauser if (mon_dir == NULL)
7098dec92b2STobias Klauser return 0;
7108dec92b2STobias Klauser
711ce7cd137SPete Zaitcev if (ubus != NULL) {
712ecb658d3SPete Zaitcev rc = snprintf(name, NAMESZ, "%dt", busnum);
7136f23ee1fSPete Zaitcev if (rc <= 0 || rc >= NAMESZ)
7146f23ee1fSPete Zaitcev goto err_print_t;
71526d0b228SGreg Kroah-Hartman mbus->dent_t = debugfs_create_file(name, 0600, mon_dir, mbus,
716ce7cd137SPete Zaitcev &mon_fops_text_t);
717ce7cd137SPete Zaitcev }
7186f23ee1fSPete Zaitcev
719ecb658d3SPete Zaitcev rc = snprintf(name, NAMESZ, "%du", busnum);
720f1c9e30bSPete Zaitcev if (rc <= 0 || rc >= NAMESZ)
721f1c9e30bSPete Zaitcev goto err_print_u;
72226d0b228SGreg Kroah-Hartman mbus->dent_u = debugfs_create_file(name, 0600, mon_dir, mbus,
72326d0b228SGreg Kroah-Hartman &mon_fops_text_u);
724f1c9e30bSPete Zaitcev
725ecb658d3SPete Zaitcev rc = snprintf(name, NAMESZ, "%ds", busnum);
7266f23ee1fSPete Zaitcev if (rc <= 0 || rc >= NAMESZ)
7276f23ee1fSPete Zaitcev goto err_print_s;
72826d0b228SGreg Kroah-Hartman mbus->dent_s = debugfs_create_file(name, 0600, mon_dir, mbus,
72926d0b228SGreg Kroah-Hartman &mon_fops_stat);
7306f23ee1fSPete Zaitcev
7316f23ee1fSPete Zaitcev return 1;
7326f23ee1fSPete Zaitcev
7336f23ee1fSPete Zaitcev err_print_s:
734f1c9e30bSPete Zaitcev debugfs_remove(mbus->dent_u);
735f1c9e30bSPete Zaitcev mbus->dent_u = NULL;
736f1c9e30bSPete Zaitcev err_print_u:
737ce7cd137SPete Zaitcev if (ubus != NULL) {
7386f23ee1fSPete Zaitcev debugfs_remove(mbus->dent_t);
7396f23ee1fSPete Zaitcev mbus->dent_t = NULL;
740ce7cd137SPete Zaitcev }
7416f23ee1fSPete Zaitcev err_print_t:
7426f23ee1fSPete Zaitcev return 0;
7436f23ee1fSPete Zaitcev }
7446f23ee1fSPete Zaitcev
mon_text_del(struct mon_bus * mbus)7456f23ee1fSPete Zaitcev void mon_text_del(struct mon_bus *mbus)
7466f23ee1fSPete Zaitcev {
747f1c9e30bSPete Zaitcev debugfs_remove(mbus->dent_u);
7486f23ee1fSPete Zaitcev debugfs_remove(mbus->dent_t);
7496f23ee1fSPete Zaitcev debugfs_remove(mbus->dent_s);
7506f23ee1fSPete Zaitcev }
7516f23ee1fSPete Zaitcev
7521da177e4SLinus Torvalds /*
7531da177e4SLinus Torvalds * Slab interface: constructor.
7541da177e4SLinus Torvalds */
mon_text_ctor(void * mem)75551cc5068SAlexey Dobriyan static void mon_text_ctor(void *mem)
7561da177e4SLinus Torvalds {
7571da177e4SLinus Torvalds /*
7581da177e4SLinus Torvalds * Nothing to initialize. No, really!
7591da177e4SLinus Torvalds * So, we fill it with garbage to emulate a reused object.
7601da177e4SLinus Torvalds */
7611da177e4SLinus Torvalds memset(mem, 0xe5, sizeof(struct mon_event_text));
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds
mon_text_init(void)7646f23ee1fSPete Zaitcev int __init mon_text_init(void)
7656f23ee1fSPete Zaitcev {
76626d0b228SGreg Kroah-Hartman mon_dir = debugfs_create_dir("usbmon", usb_debug_root);
7676f23ee1fSPete Zaitcev return 0;
7686f23ee1fSPete Zaitcev }
7696f23ee1fSPete Zaitcev
mon_text_exit(void)77021641e3fSPete Zaitcev void mon_text_exit(void)
7716f23ee1fSPete Zaitcev {
7726f23ee1fSPete Zaitcev debugfs_remove(mon_dir);
7736f23ee1fSPete Zaitcev }
774