xref: /openbmc/linux/drivers/usb/mon/mon_text.c (revision 0de005d0)
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);
4170de005d0STakashi 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 		}
4650de005d0STakashi 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 	}
5230de005d0STakashi 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 	}
5410de005d0STakashi 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 */
5520de005d0STakashi 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 */
5600de005d0STakashi 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 */
5630de005d0STakashi 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 {
5710de005d0STakashi 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') {
5790de005d0STakashi 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 {
5820de005d0STakashi 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 
5950de005d0STakashi 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++) {
6040de005d0STakashi 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) {
6170de005d0STakashi 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) {
6230de005d0STakashi Iwai 					p->cnt += scnprintf(p->pbuf + p->cnt,
624f1c9e30bSPete Zaitcev 					    p->limit - p->cnt,
6251da177e4SLinus Torvalds 					    " ");
6261da177e4SLinus Torvalds 				}
6270de005d0STakashi Iwai 				p->cnt += scnprintf(p->pbuf + p->cnt,
628f1c9e30bSPete Zaitcev 				    p->limit - p->cnt,
6291da177e4SLinus Torvalds 				    "%02x", ep->data[i]);
6301da177e4SLinus Torvalds 			}
6310de005d0STakashi Iwai 			p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
632f1c9e30bSPete Zaitcev 			    "\n");
6331da177e4SLinus Torvalds 		} else {
6340de005d0STakashi Iwai 			p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
6351da177e4SLinus Torvalds 			    " %c\n", ep->data_flag);
6361da177e4SLinus Torvalds 		}
6371da177e4SLinus Torvalds 	} else {
6380de005d0STakashi 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