| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | /* | 
|---|
| 3 | * The USB Monitor, inspired by Dave Harding's USBMon. | 
|---|
| 4 | * | 
|---|
| 5 | * This is a text format reader. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #include <linux/kernel.h> | 
|---|
| 9 | #include <linux/list.h> | 
|---|
| 10 | #include <linux/usb.h> | 
|---|
| 11 | #include <linux/slab.h> | 
|---|
| 12 | #include <linux/sched/signal.h> | 
|---|
| 13 | #include <linux/time.h> | 
|---|
| 14 | #include <linux/ktime.h> | 
|---|
| 15 | #include <linux/export.h> | 
|---|
| 16 | #include <linux/mutex.h> | 
|---|
| 17 | #include <linux/debugfs.h> | 
|---|
| 18 | #include <linux/scatterlist.h> | 
|---|
| 19 | #include <linux/uaccess.h> | 
|---|
| 20 |  | 
|---|
| 21 | #include "usb_mon.h" | 
|---|
| 22 |  | 
|---|
| 23 | /* | 
|---|
| 24 | * No, we do not want arbitrarily long data strings. | 
|---|
| 25 | * Use the binary interface if you want to capture bulk data! | 
|---|
| 26 | */ | 
|---|
| 27 | #define DATA_MAX  32 | 
|---|
| 28 |  | 
|---|
| 29 | /* | 
|---|
| 30 | * Defined by USB 2.0 clause 9.3, table 9.2. | 
|---|
| 31 | */ | 
|---|
| 32 | #define SETUP_MAX  8 | 
|---|
| 33 |  | 
|---|
| 34 | /* | 
|---|
| 35 | * This limit exists to prevent OOMs when the user process stops reading. | 
|---|
| 36 | * If usbmon were available to unprivileged processes, it might be open | 
|---|
| 37 | * to a local DoS. But we have to keep to root in order to prevent | 
|---|
| 38 | * password sniffing from HID devices. | 
|---|
| 39 | */ | 
|---|
| 40 | #define EVENT_MAX  (4*PAGE_SIZE / sizeof(struct mon_event_text)) | 
|---|
| 41 |  | 
|---|
| 42 | /* | 
|---|
| 43 | * Potentially unlimited number; we limit it for similar allocations. | 
|---|
| 44 | * The usbfs limits this to 128, but we're not quite as generous. | 
|---|
| 45 | */ | 
|---|
| 46 | #define ISODESC_MAX   5 | 
|---|
| 47 |  | 
|---|
| 48 | #define PRINTF_DFL  250   /* with 5 ISOs segs */ | 
|---|
| 49 |  | 
|---|
| 50 | struct mon_iso_desc { | 
|---|
| 51 | int status; | 
|---|
| 52 | unsigned int offset; | 
|---|
| 53 | unsigned int length;	/* Unsigned here, signed in URB. Historic. */ | 
|---|
| 54 | }; | 
|---|
| 55 |  | 
|---|
| 56 | struct mon_event_text { | 
|---|
| 57 | struct list_head e_link; | 
|---|
| 58 | int type;		/* submit, complete, etc. */ | 
|---|
| 59 | unsigned long id;	/* From pointer, most of the time */ | 
|---|
| 60 | unsigned int tstamp; | 
|---|
| 61 | int busnum; | 
|---|
| 62 | char devnum; | 
|---|
| 63 | char epnum; | 
|---|
| 64 | char is_in; | 
|---|
| 65 | char xfertype; | 
|---|
| 66 | int length;		/* Depends on type: xfer length or act length */ | 
|---|
| 67 | int status; | 
|---|
| 68 | int interval; | 
|---|
| 69 | int start_frame; | 
|---|
| 70 | int error_count; | 
|---|
| 71 | char setup_flag; | 
|---|
| 72 | char data_flag; | 
|---|
| 73 | int numdesc;		/* Full number */ | 
|---|
| 74 | struct mon_iso_desc isodesc[ISODESC_MAX]; | 
|---|
| 75 | unsigned char setup[SETUP_MAX]; | 
|---|
| 76 | unsigned char data[DATA_MAX]; | 
|---|
| 77 | }; | 
|---|
| 78 |  | 
|---|
| 79 | #define SLAB_NAME_SZ  30 | 
|---|
| 80 | struct mon_reader_text { | 
|---|
| 81 | struct kmem_cache *e_slab; | 
|---|
| 82 | int nevents; | 
|---|
| 83 | struct list_head e_list; | 
|---|
| 84 | struct mon_reader r;	/* In C, parent class can be placed anywhere */ | 
|---|
| 85 |  | 
|---|
| 86 | wait_queue_head_t wait; | 
|---|
| 87 | int printf_size; | 
|---|
| 88 | size_t printf_offset; | 
|---|
| 89 | size_t printf_togo; | 
|---|
| 90 | char *printf_buf; | 
|---|
| 91 | struct mutex printf_lock; | 
|---|
| 92 |  | 
|---|
| 93 | char slab_name[SLAB_NAME_SZ]; | 
|---|
| 94 | }; | 
|---|
| 95 |  | 
|---|
| 96 | static struct dentry *mon_dir;		/* Usually /sys/kernel/debug/usbmon */ | 
|---|
| 97 |  | 
|---|
| 98 | static void mon_text_ctor(void *); | 
|---|
| 99 |  | 
|---|
| 100 | struct mon_text_ptr { | 
|---|
| 101 | int cnt, limit; | 
|---|
| 102 | char *pbuf; | 
|---|
| 103 | }; | 
|---|
| 104 |  | 
|---|
| 105 | static struct mon_event_text * | 
|---|
| 106 | mon_text_read_wait(struct mon_reader_text *rp, struct file *file); | 
|---|
| 107 | static void mon_text_read_head_t(struct mon_reader_text *rp, | 
|---|
| 108 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 109 | static void mon_text_read_head_u(struct mon_reader_text *rp, | 
|---|
| 110 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 111 | static void mon_text_read_statset(struct mon_reader_text *rp, | 
|---|
| 112 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 113 | static void mon_text_read_intstat(struct mon_reader_text *rp, | 
|---|
| 114 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 115 | static void mon_text_read_isostat(struct mon_reader_text *rp, | 
|---|
| 116 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 117 | static void mon_text_read_isodesc(struct mon_reader_text *rp, | 
|---|
| 118 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 119 | static void mon_text_read_data(struct mon_reader_text *rp, | 
|---|
| 120 | struct mon_text_ptr *p, const struct mon_event_text *ep); | 
|---|
| 121 |  | 
|---|
| 122 | /* | 
|---|
| 123 | * mon_text_submit | 
|---|
| 124 | * mon_text_complete | 
|---|
| 125 | * | 
|---|
| 126 | * May be called from an interrupt. | 
|---|
| 127 | * | 
|---|
| 128 | * This is called with the whole mon_bus locked, so no additional lock. | 
|---|
| 129 | */ | 
|---|
| 130 |  | 
|---|
| 131 | static inline char mon_text_get_setup(struct mon_event_text *ep, | 
|---|
| 132 | struct urb *urb, char ev_type, struct mon_bus *mbus) | 
|---|
| 133 | { | 
|---|
| 134 |  | 
|---|
| 135 | if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') | 
|---|
| 136 | return '-'; | 
|---|
| 137 |  | 
|---|
| 138 | if (urb->setup_packet == NULL) | 
|---|
| 139 | return 'Z';	/* '0' would be not as pretty. */ | 
|---|
| 140 |  | 
|---|
| 141 | memcpy(to: ep->setup, from: urb->setup_packet, SETUP_MAX); | 
|---|
| 142 | return 0; | 
|---|
| 143 | } | 
|---|
| 144 |  | 
|---|
| 145 | static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, | 
|---|
| 146 | int len, char ev_type, struct mon_bus *mbus) | 
|---|
| 147 | { | 
|---|
| 148 | void *src; | 
|---|
| 149 |  | 
|---|
| 150 | if (len <= 0) | 
|---|
| 151 | return 'L'; | 
|---|
| 152 | if (len >= DATA_MAX) | 
|---|
| 153 | len = DATA_MAX; | 
|---|
| 154 |  | 
|---|
| 155 | if (ep->is_in) { | 
|---|
| 156 | if (ev_type != 'C') | 
|---|
| 157 | return '<'; | 
|---|
| 158 | } else { | 
|---|
| 159 | if (ev_type != 'S') | 
|---|
| 160 | return '>'; | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | if (urb->num_sgs == 0) { | 
|---|
| 164 | src = urb->transfer_buffer; | 
|---|
| 165 | if (src == NULL) | 
|---|
| 166 | return 'Z';	/* '0' would be not as pretty. */ | 
|---|
| 167 | } else { | 
|---|
| 168 | struct scatterlist *sg = urb->sg; | 
|---|
| 169 |  | 
|---|
| 170 | if (PageHighMem(page: sg_page(sg))) | 
|---|
| 171 | return 'D'; | 
|---|
| 172 |  | 
|---|
| 173 | /* For the text interface we copy only the first sg buffer */ | 
|---|
| 174 | len = min_t(int, sg->length, len); | 
|---|
| 175 | src = sg_virt(sg); | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | memcpy(to: ep->data, from: src, len); | 
|---|
| 179 | return 0; | 
|---|
| 180 | } | 
|---|
| 181 |  | 
|---|
| 182 | static inline unsigned int mon_get_timestamp(void) | 
|---|
| 183 | { | 
|---|
| 184 | struct timespec64 now; | 
|---|
| 185 | unsigned int stamp; | 
|---|
| 186 |  | 
|---|
| 187 | ktime_get_ts64(ts: &now); | 
|---|
| 188 | stamp = now.tv_sec & 0xFFF;  /* 2^32 = 4294967296. Limit to 4096s. */ | 
|---|
| 189 | stamp = stamp * USEC_PER_SEC + now.tv_nsec / NSEC_PER_USEC; | 
|---|
| 190 | return stamp; | 
|---|
| 191 | } | 
|---|
| 192 |  | 
|---|
| 193 | static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, | 
|---|
| 194 | char ev_type, int status) | 
|---|
| 195 | { | 
|---|
| 196 | struct mon_event_text *ep; | 
|---|
| 197 | unsigned int stamp; | 
|---|
| 198 | struct usb_iso_packet_descriptor *fp; | 
|---|
| 199 | struct mon_iso_desc *dp; | 
|---|
| 200 | int i, ndesc; | 
|---|
| 201 |  | 
|---|
| 202 | stamp = mon_get_timestamp(); | 
|---|
| 203 |  | 
|---|
| 204 | if (rp->nevents >= EVENT_MAX || | 
|---|
| 205 | (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { | 
|---|
| 206 | rp->r.m_bus->cnt_text_lost++; | 
|---|
| 207 | return; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | ep->type = ev_type; | 
|---|
| 211 | ep->id = (unsigned long) urb; | 
|---|
| 212 | ep->busnum = urb->dev->bus->busnum; | 
|---|
| 213 | ep->devnum = urb->dev->devnum; | 
|---|
| 214 | ep->epnum = usb_endpoint_num(epd: &urb->ep->desc); | 
|---|
| 215 | ep->xfertype = usb_endpoint_type(epd: &urb->ep->desc); | 
|---|
| 216 | ep->is_in = usb_urb_dir_in(urb); | 
|---|
| 217 | ep->tstamp = stamp; | 
|---|
| 218 | ep->length = (ev_type == 'S') ? | 
|---|
| 219 | urb->transfer_buffer_length : urb->actual_length; | 
|---|
| 220 | /* Collecting status makes debugging sense for submits, too */ | 
|---|
| 221 | ep->status = status; | 
|---|
| 222 |  | 
|---|
| 223 | if (ep->xfertype == USB_ENDPOINT_XFER_INT) { | 
|---|
| 224 | ep->interval = urb->interval; | 
|---|
| 225 | } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { | 
|---|
| 226 | ep->interval = urb->interval; | 
|---|
| 227 | ep->start_frame = urb->start_frame; | 
|---|
| 228 | ep->error_count = urb->error_count; | 
|---|
| 229 | } | 
|---|
| 230 | ep->numdesc = urb->number_of_packets; | 
|---|
| 231 | if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && | 
|---|
| 232 | urb->number_of_packets > 0) { | 
|---|
| 233 | if ((ndesc = urb->number_of_packets) > ISODESC_MAX) | 
|---|
| 234 | ndesc = ISODESC_MAX; | 
|---|
| 235 | fp = urb->iso_frame_desc; | 
|---|
| 236 | dp = ep->isodesc; | 
|---|
| 237 | for (i = 0; i < ndesc; i++) { | 
|---|
| 238 | dp->status = fp->status; | 
|---|
| 239 | dp->offset = fp->offset; | 
|---|
| 240 | dp->length = (ev_type == 'S') ? | 
|---|
| 241 | fp->length : fp->actual_length; | 
|---|
| 242 | fp++; | 
|---|
| 243 | dp++; | 
|---|
| 244 | } | 
|---|
| 245 | /* Wasteful, but simple to understand: ISO 'C' is sparse. */ | 
|---|
| 246 | if (ev_type == 'C') | 
|---|
| 247 | ep->length = urb->transfer_buffer_length; | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 | ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, mbus: rp->r.m_bus); | 
|---|
| 251 | ep->data_flag = mon_text_get_data(ep, urb, len: ep->length, ev_type, | 
|---|
| 252 | mbus: rp->r.m_bus); | 
|---|
| 253 |  | 
|---|
| 254 | rp->nevents++; | 
|---|
| 255 | list_add_tail(new: &ep->e_link, head: &rp->e_list); | 
|---|
| 256 | wake_up(&rp->wait); | 
|---|
| 257 | } | 
|---|
| 258 |  | 
|---|
| 259 | static void mon_text_submit(void *data, struct urb *urb) | 
|---|
| 260 | { | 
|---|
| 261 | struct mon_reader_text *rp = data; | 
|---|
| 262 | mon_text_event(rp, urb, ev_type: 'S', status: -EINPROGRESS); | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 | static void mon_text_complete(void *data, struct urb *urb, int status) | 
|---|
| 266 | { | 
|---|
| 267 | struct mon_reader_text *rp = data; | 
|---|
| 268 | mon_text_event(rp, urb, ev_type: 'C', status); | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | static void mon_text_error(void *data, struct urb *urb, int error) | 
|---|
| 272 | { | 
|---|
| 273 | struct mon_reader_text *rp = data; | 
|---|
| 274 | struct mon_event_text *ep; | 
|---|
| 275 |  | 
|---|
| 276 | if (rp->nevents >= EVENT_MAX || | 
|---|
| 277 | (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { | 
|---|
| 278 | rp->r.m_bus->cnt_text_lost++; | 
|---|
| 279 | return; | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 | ep->type = 'E'; | 
|---|
| 283 | ep->id = (unsigned long) urb; | 
|---|
| 284 | ep->busnum = urb->dev->bus->busnum; | 
|---|
| 285 | ep->devnum = urb->dev->devnum; | 
|---|
| 286 | ep->epnum = usb_endpoint_num(epd: &urb->ep->desc); | 
|---|
| 287 | ep->xfertype = usb_endpoint_type(epd: &urb->ep->desc); | 
|---|
| 288 | ep->is_in = usb_urb_dir_in(urb); | 
|---|
| 289 | ep->tstamp = mon_get_timestamp(); | 
|---|
| 290 | ep->length = 0; | 
|---|
| 291 | ep->status = error; | 
|---|
| 292 |  | 
|---|
| 293 | ep->setup_flag = '-'; | 
|---|
| 294 | ep->data_flag = 'E'; | 
|---|
| 295 |  | 
|---|
| 296 | rp->nevents++; | 
|---|
| 297 | list_add_tail(new: &ep->e_link, head: &rp->e_list); | 
|---|
| 298 | wake_up(&rp->wait); | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | /* | 
|---|
| 302 | * Fetch next event from the circular buffer. | 
|---|
| 303 | */ | 
|---|
| 304 | static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp, | 
|---|
| 305 | struct mon_bus *mbus) | 
|---|
| 306 | { | 
|---|
| 307 | struct list_head *p; | 
|---|
| 308 | unsigned long flags; | 
|---|
| 309 |  | 
|---|
| 310 | spin_lock_irqsave(&mbus->lock, flags); | 
|---|
| 311 | if (list_empty(head: &rp->e_list)) { | 
|---|
| 312 | spin_unlock_irqrestore(lock: &mbus->lock, flags); | 
|---|
| 313 | return NULL; | 
|---|
| 314 | } | 
|---|
| 315 | p = rp->e_list.next; | 
|---|
| 316 | list_del(entry: p); | 
|---|
| 317 | --rp->nevents; | 
|---|
| 318 | spin_unlock_irqrestore(lock: &mbus->lock, flags); | 
|---|
| 319 | return list_entry(p, struct mon_event_text, e_link); | 
|---|
| 320 | } | 
|---|
| 321 |  | 
|---|
| 322 | /* | 
|---|
| 323 | */ | 
|---|
| 324 | static int mon_text_open(struct inode *inode, struct file *file) | 
|---|
| 325 | { | 
|---|
| 326 | struct mon_bus *mbus; | 
|---|
| 327 | struct mon_reader_text *rp; | 
|---|
| 328 | int rc; | 
|---|
| 329 |  | 
|---|
| 330 | mutex_lock(lock: &mon_lock); | 
|---|
| 331 | mbus = inode->i_private; | 
|---|
| 332 |  | 
|---|
| 333 | rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL); | 
|---|
| 334 | if (rp == NULL) { | 
|---|
| 335 | rc = -ENOMEM; | 
|---|
| 336 | goto err_alloc; | 
|---|
| 337 | } | 
|---|
| 338 | INIT_LIST_HEAD(list: &rp->e_list); | 
|---|
| 339 | init_waitqueue_head(&rp->wait); | 
|---|
| 340 | mutex_init(&rp->printf_lock); | 
|---|
| 341 |  | 
|---|
| 342 | rp->printf_size = PRINTF_DFL; | 
|---|
| 343 | rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL); | 
|---|
| 344 | if (rp->printf_buf == NULL) { | 
|---|
| 345 | rc = -ENOMEM; | 
|---|
| 346 | goto err_alloc_pr; | 
|---|
| 347 | } | 
|---|
| 348 |  | 
|---|
| 349 | rp->r.m_bus = mbus; | 
|---|
| 350 | rp->r.r_data = rp; | 
|---|
| 351 | rp->r.rnf_submit = mon_text_submit; | 
|---|
| 352 | rp->r.rnf_error = mon_text_error; | 
|---|
| 353 | rp->r.rnf_complete = mon_text_complete; | 
|---|
| 354 |  | 
|---|
| 355 | scnprintf(buf: rp->slab_name, SLAB_NAME_SZ, fmt: "mon_text_%p", rp); | 
|---|
| 356 | rp->e_slab = kmem_cache_create(rp->slab_name, | 
|---|
| 357 | sizeof(struct mon_event_text), sizeof(long), 0, | 
|---|
| 358 | mon_text_ctor); | 
|---|
| 359 | if (rp->e_slab == NULL) { | 
|---|
| 360 | rc = -ENOMEM; | 
|---|
| 361 | goto err_slab; | 
|---|
| 362 | } | 
|---|
| 363 |  | 
|---|
| 364 | mon_reader_add(mbus, r: &rp->r); | 
|---|
| 365 |  | 
|---|
| 366 | file->private_data = rp; | 
|---|
| 367 | mutex_unlock(lock: &mon_lock); | 
|---|
| 368 | return 0; | 
|---|
| 369 |  | 
|---|
| 370 | // err_busy: | 
|---|
| 371 | //	kmem_cache_destroy(rp->e_slab); | 
|---|
| 372 | err_slab: | 
|---|
| 373 | kfree(objp: rp->printf_buf); | 
|---|
| 374 | err_alloc_pr: | 
|---|
| 375 | kfree(objp: rp); | 
|---|
| 376 | err_alloc: | 
|---|
| 377 | mutex_unlock(lock: &mon_lock); | 
|---|
| 378 | return rc; | 
|---|
| 379 | } | 
|---|
| 380 |  | 
|---|
| 381 | static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp, | 
|---|
| 382 | char __user * const buf, const size_t nbytes) | 
|---|
| 383 | { | 
|---|
| 384 | const size_t togo = min(nbytes, rp->printf_togo); | 
|---|
| 385 |  | 
|---|
| 386 | if (copy_to_user(to: buf, from: &rp->printf_buf[rp->printf_offset], n: togo)) | 
|---|
| 387 | return -EFAULT; | 
|---|
| 388 | rp->printf_togo -= togo; | 
|---|
| 389 | rp->printf_offset += togo; | 
|---|
| 390 | return togo; | 
|---|
| 391 | } | 
|---|
| 392 |  | 
|---|
| 393 | /* ppos is not advanced since the llseek operation is not permitted. */ | 
|---|
| 394 | static ssize_t mon_text_read_t(struct file *file, char __user *buf, | 
|---|
| 395 | size_t nbytes, loff_t *ppos) | 
|---|
| 396 | { | 
|---|
| 397 | struct mon_reader_text *rp = file->private_data; | 
|---|
| 398 | struct mon_event_text *ep; | 
|---|
| 399 | struct mon_text_ptr ptr; | 
|---|
| 400 | ssize_t ret; | 
|---|
| 401 |  | 
|---|
| 402 | mutex_lock(lock: &rp->printf_lock); | 
|---|
| 403 |  | 
|---|
| 404 | if (rp->printf_togo == 0) { | 
|---|
| 405 |  | 
|---|
| 406 | ep = mon_text_read_wait(rp, file); | 
|---|
| 407 | if (IS_ERR(ptr: ep)) { | 
|---|
| 408 | mutex_unlock(lock: &rp->printf_lock); | 
|---|
| 409 | return PTR_ERR(ptr: ep); | 
|---|
| 410 | } | 
|---|
| 411 | ptr.cnt = 0; | 
|---|
| 412 | ptr.pbuf = rp->printf_buf; | 
|---|
| 413 | ptr.limit = rp->printf_size; | 
|---|
| 414 |  | 
|---|
| 415 | mon_text_read_head_t(rp, p: &ptr, ep); | 
|---|
| 416 | mon_text_read_statset(rp, p: &ptr, ep); | 
|---|
| 417 | ptr.cnt += scnprintf(buf: ptr.pbuf + ptr.cnt, size: ptr.limit - ptr.cnt, | 
|---|
| 418 | fmt: " %d", ep->length); | 
|---|
| 419 | mon_text_read_data(rp, p: &ptr, ep); | 
|---|
| 420 |  | 
|---|
| 421 | rp->printf_togo = ptr.cnt; | 
|---|
| 422 | rp->printf_offset = 0; | 
|---|
| 423 |  | 
|---|
| 424 | kmem_cache_free(s: rp->e_slab, objp: ep); | 
|---|
| 425 | } | 
|---|
| 426 |  | 
|---|
| 427 | ret = mon_text_copy_to_user(rp, buf, nbytes); | 
|---|
| 428 | mutex_unlock(lock: &rp->printf_lock); | 
|---|
| 429 | return ret; | 
|---|
| 430 | } | 
|---|
| 431 |  | 
|---|
| 432 | /* ppos is not advanced since the llseek operation is not permitted. */ | 
|---|
| 433 | static ssize_t mon_text_read_u(struct file *file, char __user *buf, | 
|---|
| 434 | size_t nbytes, loff_t *ppos) | 
|---|
| 435 | { | 
|---|
| 436 | struct mon_reader_text *rp = file->private_data; | 
|---|
| 437 | struct mon_event_text *ep; | 
|---|
| 438 | struct mon_text_ptr ptr; | 
|---|
| 439 | ssize_t ret; | 
|---|
| 440 |  | 
|---|
| 441 | mutex_lock(lock: &rp->printf_lock); | 
|---|
| 442 |  | 
|---|
| 443 | if (rp->printf_togo == 0) { | 
|---|
| 444 |  | 
|---|
| 445 | ep = mon_text_read_wait(rp, file); | 
|---|
| 446 | if (IS_ERR(ptr: ep)) { | 
|---|
| 447 | mutex_unlock(lock: &rp->printf_lock); | 
|---|
| 448 | return PTR_ERR(ptr: ep); | 
|---|
| 449 | } | 
|---|
| 450 | ptr.cnt = 0; | 
|---|
| 451 | ptr.pbuf = rp->printf_buf; | 
|---|
| 452 | ptr.limit = rp->printf_size; | 
|---|
| 453 |  | 
|---|
| 454 | mon_text_read_head_u(rp, p: &ptr, ep); | 
|---|
| 455 | if (ep->type == 'E') { | 
|---|
| 456 | mon_text_read_statset(rp, p: &ptr, ep); | 
|---|
| 457 | } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { | 
|---|
| 458 | mon_text_read_isostat(rp, p: &ptr, ep); | 
|---|
| 459 | mon_text_read_isodesc(rp, p: &ptr, ep); | 
|---|
| 460 | } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { | 
|---|
| 461 | mon_text_read_intstat(rp, p: &ptr, ep); | 
|---|
| 462 | } else { | 
|---|
| 463 | mon_text_read_statset(rp, p: &ptr, ep); | 
|---|
| 464 | } | 
|---|
| 465 | ptr.cnt += scnprintf(buf: ptr.pbuf + ptr.cnt, size: ptr.limit - ptr.cnt, | 
|---|
| 466 | fmt: " %d", ep->length); | 
|---|
| 467 | mon_text_read_data(rp, p: &ptr, ep); | 
|---|
| 468 |  | 
|---|
| 469 | rp->printf_togo = ptr.cnt; | 
|---|
| 470 | rp->printf_offset = 0; | 
|---|
| 471 |  | 
|---|
| 472 | kmem_cache_free(s: rp->e_slab, objp: ep); | 
|---|
| 473 | } | 
|---|
| 474 |  | 
|---|
| 475 | ret = mon_text_copy_to_user(rp, buf, nbytes); | 
|---|
| 476 | mutex_unlock(lock: &rp->printf_lock); | 
|---|
| 477 | return ret; | 
|---|
| 478 | } | 
|---|
| 479 |  | 
|---|
| 480 | static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp, | 
|---|
| 481 | struct file *file) | 
|---|
| 482 | { | 
|---|
| 483 | struct mon_bus *mbus = rp->r.m_bus; | 
|---|
| 484 | DECLARE_WAITQUEUE(waita, current); | 
|---|
| 485 | struct mon_event_text *ep; | 
|---|
| 486 |  | 
|---|
| 487 | add_wait_queue(wq_head: &rp->wait, wq_entry: &waita); | 
|---|
| 488 | set_current_state(TASK_INTERRUPTIBLE); | 
|---|
| 489 | while ((ep = mon_text_fetch(rp, mbus)) == NULL) { | 
|---|
| 490 | if (file->f_flags & O_NONBLOCK) { | 
|---|
| 491 | set_current_state(TASK_RUNNING); | 
|---|
| 492 | remove_wait_queue(wq_head: &rp->wait, wq_entry: &waita); | 
|---|
| 493 | return ERR_PTR(error: -EWOULDBLOCK); | 
|---|
| 494 | } | 
|---|
| 495 | /* | 
|---|
| 496 | * We do not count nwaiters, because ->release is supposed | 
|---|
| 497 | * to be called when all openers are gone only. | 
|---|
| 498 | */ | 
|---|
| 499 | schedule(); | 
|---|
| 500 | if (signal_pending(current)) { | 
|---|
| 501 | remove_wait_queue(wq_head: &rp->wait, wq_entry: &waita); | 
|---|
| 502 | return ERR_PTR(error: -EINTR); | 
|---|
| 503 | } | 
|---|
| 504 | set_current_state(TASK_INTERRUPTIBLE); | 
|---|
| 505 | } | 
|---|
| 506 | set_current_state(TASK_RUNNING); | 
|---|
| 507 | remove_wait_queue(wq_head: &rp->wait, wq_entry: &waita); | 
|---|
| 508 | return ep; | 
|---|
| 509 | } | 
|---|
| 510 |  | 
|---|
| 511 | static void mon_text_read_head_t(struct mon_reader_text *rp, | 
|---|
| 512 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 513 | { | 
|---|
| 514 | char udir, utype; | 
|---|
| 515 |  | 
|---|
| 516 | udir = (ep->is_in ? 'i' : 'o'); | 
|---|
| 517 | switch (ep->xfertype) { | 
|---|
| 518 | case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break; | 
|---|
| 519 | case USB_ENDPOINT_XFER_INT:	utype = 'I'; break; | 
|---|
| 520 | case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break; | 
|---|
| 521 | default: /* PIPE_BULK */  utype = 'B'; | 
|---|
| 522 | } | 
|---|
| 523 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 524 | fmt: "%lx %u %c %c%c:%03u:%02u", | 
|---|
| 525 | ep->id, ep->tstamp, ep->type, | 
|---|
| 526 | utype, udir, ep->devnum, ep->epnum); | 
|---|
| 527 | } | 
|---|
| 528 |  | 
|---|
| 529 | static void mon_text_read_head_u(struct mon_reader_text *rp, | 
|---|
| 530 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 531 | { | 
|---|
| 532 | char udir, utype; | 
|---|
| 533 |  | 
|---|
| 534 | udir = (ep->is_in ? 'i' : 'o'); | 
|---|
| 535 | switch (ep->xfertype) { | 
|---|
| 536 | case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break; | 
|---|
| 537 | case USB_ENDPOINT_XFER_INT:	utype = 'I'; break; | 
|---|
| 538 | case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break; | 
|---|
| 539 | default: /* PIPE_BULK */  utype = 'B'; | 
|---|
| 540 | } | 
|---|
| 541 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 542 | fmt: "%lx %u %c %c%c:%d:%03u:%u", | 
|---|
| 543 | ep->id, ep->tstamp, ep->type, | 
|---|
| 544 | utype, udir, ep->busnum, ep->devnum, ep->epnum); | 
|---|
| 545 | } | 
|---|
| 546 |  | 
|---|
| 547 | static void mon_text_read_statset(struct mon_reader_text *rp, | 
|---|
| 548 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 549 | { | 
|---|
| 550 |  | 
|---|
| 551 | if (ep->setup_flag == 0) {   /* Setup packet is present and captured */ | 
|---|
| 552 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 553 | fmt: " s %02x %02x %04x %04x %04x", | 
|---|
| 554 | ep->setup[0], | 
|---|
| 555 | ep->setup[1], | 
|---|
| 556 | (ep->setup[3] << 8) | ep->setup[2], | 
|---|
| 557 | (ep->setup[5] << 8) | ep->setup[4], | 
|---|
| 558 | (ep->setup[7] << 8) | ep->setup[6]); | 
|---|
| 559 | } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ | 
|---|
| 560 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 561 | fmt: " %c __ __ ____ ____ ____", ep->setup_flag); | 
|---|
| 562 | } else {                     /* No setup for this kind of URB */ | 
|---|
| 563 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 564 | fmt: " %d", ep->status); | 
|---|
| 565 | } | 
|---|
| 566 | } | 
|---|
| 567 |  | 
|---|
| 568 | static void mon_text_read_intstat(struct mon_reader_text *rp, | 
|---|
| 569 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 570 | { | 
|---|
| 571 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 572 | fmt: " %d:%d", ep->status, ep->interval); | 
|---|
| 573 | } | 
|---|
| 574 |  | 
|---|
| 575 | static void mon_text_read_isostat(struct mon_reader_text *rp, | 
|---|
| 576 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 577 | { | 
|---|
| 578 | if (ep->type == 'S') { | 
|---|
| 579 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 580 | fmt: " %d:%d:%d", ep->status, ep->interval, ep->start_frame); | 
|---|
| 581 | } else { | 
|---|
| 582 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 583 | fmt: " %d:%d:%d:%d", | 
|---|
| 584 | ep->status, ep->interval, ep->start_frame, ep->error_count); | 
|---|
| 585 | } | 
|---|
| 586 | } | 
|---|
| 587 |  | 
|---|
| 588 | static void mon_text_read_isodesc(struct mon_reader_text *rp, | 
|---|
| 589 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 590 | { | 
|---|
| 591 | int ndesc;	/* Display this many */ | 
|---|
| 592 | int i; | 
|---|
| 593 | const struct mon_iso_desc *dp; | 
|---|
| 594 |  | 
|---|
| 595 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 596 | fmt: " %d", ep->numdesc); | 
|---|
| 597 | ndesc = ep->numdesc; | 
|---|
| 598 | if (ndesc > ISODESC_MAX) | 
|---|
| 599 | ndesc = ISODESC_MAX; | 
|---|
| 600 | if (ndesc < 0) | 
|---|
| 601 | ndesc = 0; | 
|---|
| 602 | dp = ep->isodesc; | 
|---|
| 603 | for (i = 0; i < ndesc; i++) { | 
|---|
| 604 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 605 | fmt: " %d:%u:%u", dp->status, dp->offset, dp->length); | 
|---|
| 606 | dp++; | 
|---|
| 607 | } | 
|---|
| 608 | } | 
|---|
| 609 |  | 
|---|
| 610 | static void mon_text_read_data(struct mon_reader_text *rp, | 
|---|
| 611 | struct mon_text_ptr *p, const struct mon_event_text *ep) | 
|---|
| 612 | { | 
|---|
| 613 | int data_len, i; | 
|---|
| 614 |  | 
|---|
| 615 | if ((data_len = ep->length) > 0) { | 
|---|
| 616 | if (ep->data_flag == 0) { | 
|---|
| 617 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 618 | fmt: " ="); | 
|---|
| 619 | if (data_len >= DATA_MAX) | 
|---|
| 620 | data_len = DATA_MAX; | 
|---|
| 621 | for (i = 0; i < data_len; i++) { | 
|---|
| 622 | if (i % 4 == 0) { | 
|---|
| 623 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, | 
|---|
| 624 | size: p->limit - p->cnt, | 
|---|
| 625 | fmt: " "); | 
|---|
| 626 | } | 
|---|
| 627 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, | 
|---|
| 628 | size: p->limit - p->cnt, | 
|---|
| 629 | fmt: "%02x", ep->data[i]); | 
|---|
| 630 | } | 
|---|
| 631 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 632 | fmt: "\n"); | 
|---|
| 633 | } else { | 
|---|
| 634 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, | 
|---|
| 635 | fmt: " %c\n", ep->data_flag); | 
|---|
| 636 | } | 
|---|
| 637 | } else { | 
|---|
| 638 | p->cnt += scnprintf(buf: p->pbuf + p->cnt, size: p->limit - p->cnt, fmt: "\n"); | 
|---|
| 639 | } | 
|---|
| 640 | } | 
|---|
| 641 |  | 
|---|
| 642 | static int mon_text_release(struct inode *inode, struct file *file) | 
|---|
| 643 | { | 
|---|
| 644 | struct mon_reader_text *rp = file->private_data; | 
|---|
| 645 | struct mon_bus *mbus; | 
|---|
| 646 | /* unsigned long flags; */ | 
|---|
| 647 | struct list_head *p; | 
|---|
| 648 | struct mon_event_text *ep; | 
|---|
| 649 |  | 
|---|
| 650 | mutex_lock(lock: &mon_lock); | 
|---|
| 651 | mbus = inode->i_private; | 
|---|
| 652 |  | 
|---|
| 653 | if (mbus->nreaders <= 0) { | 
|---|
| 654 | printk(KERN_ERR TAG ": consistency error on close\n"); | 
|---|
| 655 | mutex_unlock(lock: &mon_lock); | 
|---|
| 656 | return 0; | 
|---|
| 657 | } | 
|---|
| 658 | mon_reader_del(mbus, r: &rp->r); | 
|---|
| 659 |  | 
|---|
| 660 | /* | 
|---|
| 661 | * In theory, e_list is protected by mbus->lock. However, | 
|---|
| 662 | * after mon_reader_del has finished, the following is the case: | 
|---|
| 663 | *  - we are not on reader list anymore, so new events won't be added; | 
|---|
| 664 | *  - whole mbus may be dropped if it was orphaned. | 
|---|
| 665 | * So, we better not touch mbus. | 
|---|
| 666 | */ | 
|---|
| 667 | /* spin_lock_irqsave(&mbus->lock, flags); */ | 
|---|
| 668 | while (!list_empty(head: &rp->e_list)) { | 
|---|
| 669 | p = rp->e_list.next; | 
|---|
| 670 | ep = list_entry(p, struct mon_event_text, e_link); | 
|---|
| 671 | list_del(entry: p); | 
|---|
| 672 | --rp->nevents; | 
|---|
| 673 | kmem_cache_free(s: rp->e_slab, objp: ep); | 
|---|
| 674 | } | 
|---|
| 675 | /* spin_unlock_irqrestore(&mbus->lock, flags); */ | 
|---|
| 676 |  | 
|---|
| 677 | kmem_cache_destroy(s: rp->e_slab); | 
|---|
| 678 | kfree(objp: rp->printf_buf); | 
|---|
| 679 | kfree(objp: rp); | 
|---|
| 680 |  | 
|---|
| 681 | mutex_unlock(lock: &mon_lock); | 
|---|
| 682 | return 0; | 
|---|
| 683 | } | 
|---|
| 684 |  | 
|---|
| 685 | static const struct file_operations mon_fops_text_t = { | 
|---|
| 686 | .owner =	THIS_MODULE, | 
|---|
| 687 | .open =		mon_text_open, | 
|---|
| 688 | .read =		mon_text_read_t, | 
|---|
| 689 | .release =	mon_text_release, | 
|---|
| 690 | }; | 
|---|
| 691 |  | 
|---|
| 692 | static const struct file_operations mon_fops_text_u = { | 
|---|
| 693 | .owner =	THIS_MODULE, | 
|---|
| 694 | .open =		mon_text_open, | 
|---|
| 695 | .read =		mon_text_read_u, | 
|---|
| 696 | .release =	mon_text_release, | 
|---|
| 697 | }; | 
|---|
| 698 |  | 
|---|
| 699 | int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) | 
|---|
| 700 | { | 
|---|
| 701 | enum { NAMESZ = 12 }; | 
|---|
| 702 | char name[NAMESZ]; | 
|---|
| 703 | int busnum = ubus? ubus->busnum: 0; | 
|---|
| 704 |  | 
|---|
| 705 | if (mon_dir == NULL) | 
|---|
| 706 | return 0; | 
|---|
| 707 |  | 
|---|
| 708 | if (ubus != NULL) { | 
|---|
| 709 | scnprintf(buf: name, size: NAMESZ, fmt: "%dt", busnum); | 
|---|
| 710 | mbus->dent_t = debugfs_create_file(name, 0600, mon_dir, mbus, | 
|---|
| 711 | &mon_fops_text_t); | 
|---|
| 712 | } | 
|---|
| 713 |  | 
|---|
| 714 | scnprintf(buf: name, size: NAMESZ, fmt: "%du", busnum); | 
|---|
| 715 | mbus->dent_u = debugfs_create_file(name, 0600, mon_dir, mbus, | 
|---|
| 716 | &mon_fops_text_u); | 
|---|
| 717 |  | 
|---|
| 718 | scnprintf(buf: name, size: NAMESZ, fmt: "%ds", busnum); | 
|---|
| 719 | mbus->dent_s = debugfs_create_file(name, 0600, mon_dir, mbus, | 
|---|
| 720 | &mon_fops_stat); | 
|---|
| 721 |  | 
|---|
| 722 | return 1; | 
|---|
| 723 | } | 
|---|
| 724 |  | 
|---|
| 725 | void mon_text_del(struct mon_bus *mbus) | 
|---|
| 726 | { | 
|---|
| 727 | debugfs_remove(dentry: mbus->dent_u); | 
|---|
| 728 | debugfs_remove(dentry: mbus->dent_t); | 
|---|
| 729 | debugfs_remove(dentry: mbus->dent_s); | 
|---|
| 730 | } | 
|---|
| 731 |  | 
|---|
| 732 | /* | 
|---|
| 733 | * Slab interface: constructor. | 
|---|
| 734 | */ | 
|---|
| 735 | static void mon_text_ctor(void *mem) | 
|---|
| 736 | { | 
|---|
| 737 | /* | 
|---|
| 738 | * Nothing to initialize. No, really! | 
|---|
| 739 | * So, we fill it with garbage to emulate a reused object. | 
|---|
| 740 | */ | 
|---|
| 741 | memset(s: mem, c: 0xe5, n: sizeof(struct mon_event_text)); | 
|---|
| 742 | } | 
|---|
| 743 |  | 
|---|
| 744 | int __init mon_text_init(void) | 
|---|
| 745 | { | 
|---|
| 746 | mon_dir = debugfs_create_dir(name: "usbmon", parent: usb_debug_root); | 
|---|
| 747 | return 0; | 
|---|
| 748 | } | 
|---|
| 749 |  | 
|---|
| 750 | void mon_text_exit(void) | 
|---|
| 751 | { | 
|---|
| 752 | debugfs_remove(dentry: mon_dir); | 
|---|
| 753 | } | 
|---|
| 754 |  | 
|---|