diff options
Diffstat (limited to 'drivers/usb/mon/mon_bin.c')
-rw-r--r-- | drivers/usb/mon/mon_bin.c | 142 |
1 files changed, 116 insertions, 26 deletions
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 4cf27c72423e..f8d9045d668a 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c | |||
@@ -37,10 +37,13 @@ | |||
37 | #define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) | 37 | #define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) |
38 | #define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) | 38 | #define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) |
39 | #define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) | 39 | #define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) |
40 | /* #9 was MON_IOCT_SETAPI */ | ||
41 | #define MON_IOCX_GETX _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get) | ||
40 | 42 | ||
41 | #ifdef CONFIG_COMPAT | 43 | #ifdef CONFIG_COMPAT |
42 | #define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32) | 44 | #define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32) |
43 | #define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32) | 45 | #define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32) |
46 | #define MON_IOCX_GETX32 _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get32) | ||
44 | #endif | 47 | #endif |
45 | 48 | ||
46 | /* | 49 | /* |
@@ -92,7 +95,29 @@ struct mon_bin_hdr { | |||
92 | int status; | 95 | int status; |
93 | unsigned int len_urb; /* Length of data (submitted or actual) */ | 96 | unsigned int len_urb; /* Length of data (submitted or actual) */ |
94 | unsigned int len_cap; /* Delivered length */ | 97 | unsigned int len_cap; /* Delivered length */ |
95 | unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ | 98 | union { |
99 | unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ | ||
100 | struct iso_rec { | ||
101 | int error_count; | ||
102 | int numdesc; | ||
103 | } iso; | ||
104 | } s; | ||
105 | int interval; | ||
106 | int start_frame; | ||
107 | unsigned int xfer_flags; | ||
108 | unsigned int ndesc; /* Actual number of ISO descriptors */ | ||
109 | }; | ||
110 | |||
111 | /* | ||
112 | * ISO vector, packed into the head of data stream. | ||
113 | * This has to take 16 bytes to make sure that the end of buffer | ||
114 | * wrap is not happening in the middle of a descriptor. | ||
115 | */ | ||
116 | struct mon_bin_isodesc { | ||
117 | int iso_status; | ||
118 | unsigned int iso_off; | ||
119 | unsigned int iso_len; | ||
120 | u32 _pad; | ||
96 | }; | 121 | }; |
97 | 122 | ||
98 | /* per file statistic */ | 123 | /* per file statistic */ |
@@ -102,7 +127,7 @@ struct mon_bin_stats { | |||
102 | }; | 127 | }; |
103 | 128 | ||
104 | struct mon_bin_get { | 129 | struct mon_bin_get { |
105 | struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */ | 130 | struct mon_bin_hdr __user *hdr; /* Can be 48 bytes or 64. */ |
106 | void __user *data; | 131 | void __user *data; |
107 | size_t alloc; /* Length of data (can be zero) */ | 132 | size_t alloc; /* Length of data (can be zero) */ |
108 | }; | 133 | }; |
@@ -131,6 +156,11 @@ struct mon_bin_mfetch32 { | |||
131 | #define PKT_ALIGN 64 | 156 | #define PKT_ALIGN 64 |
132 | #define PKT_SIZE 64 | 157 | #define PKT_SIZE 64 |
133 | 158 | ||
159 | #define PKT_SZ_API0 48 /* API 0 (2.6.20) size */ | ||
160 | #define PKT_SZ_API1 64 /* API 1 size: extra fields */ | ||
161 | |||
162 | #define ISODESC_MAX 128 /* Same number as usbfs allows, 2048 bytes. */ | ||
163 | |||
134 | /* max number of USB bus supported */ | 164 | /* max number of USB bus supported */ |
135 | #define MON_BIN_MAX_MINOR 128 | 165 | #define MON_BIN_MAX_MINOR 128 |
136 | 166 | ||
@@ -360,12 +390,8 @@ static inline char mon_bin_get_setup(unsigned char *setupb, | |||
360 | const struct urb *urb, char ev_type) | 390 | const struct urb *urb, char ev_type) |
361 | { | 391 | { |
362 | 392 | ||
363 | if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S') | ||
364 | return '-'; | ||
365 | |||
366 | if (urb->setup_packet == NULL) | 393 | if (urb->setup_packet == NULL) |
367 | return 'Z'; | 394 | return 'Z'; |
368 | |||
369 | memcpy(setupb, urb->setup_packet, SETUP_LEN); | 395 | memcpy(setupb, urb->setup_packet, SETUP_LEN); |
370 | return 0; | 396 | return 0; |
371 | } | 397 | } |
@@ -387,6 +413,26 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp, | |||
387 | return 0; | 413 | return 0; |
388 | } | 414 | } |
389 | 415 | ||
416 | static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, | ||
417 | unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc) | ||
418 | { | ||
419 | struct mon_bin_isodesc *dp; | ||
420 | struct usb_iso_packet_descriptor *fp; | ||
421 | |||
422 | fp = urb->iso_frame_desc; | ||
423 | while (ndesc-- != 0) { | ||
424 | dp = (struct mon_bin_isodesc *) | ||
425 | (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE); | ||
426 | dp->iso_status = fp->status; | ||
427 | dp->iso_off = fp->offset; | ||
428 | dp->iso_len = (ev_type == 'S') ? fp->length : fp->actual_length; | ||
429 | dp->_pad = 0; | ||
430 | if ((offset += sizeof(struct mon_bin_isodesc)) >= rp->b_size) | ||
431 | offset = 0; | ||
432 | fp++; | ||
433 | } | ||
434 | } | ||
435 | |||
390 | static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | 436 | static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, |
391 | char ev_type, int status) | 437 | char ev_type, int status) |
392 | { | 438 | { |
@@ -396,6 +442,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
396 | unsigned int urb_length; | 442 | unsigned int urb_length; |
397 | unsigned int offset; | 443 | unsigned int offset; |
398 | unsigned int length; | 444 | unsigned int length; |
445 | unsigned int ndesc, lendesc; | ||
399 | unsigned char dir; | 446 | unsigned char dir; |
400 | struct mon_bin_hdr *ep; | 447 | struct mon_bin_hdr *ep; |
401 | char data_tag = 0; | 448 | char data_tag = 0; |
@@ -407,6 +454,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
407 | /* | 454 | /* |
408 | * Find the maximum allowable length, then allocate space. | 455 | * Find the maximum allowable length, then allocate space. |
409 | */ | 456 | */ |
457 | if (usb_endpoint_xfer_isoc(epd)) { | ||
458 | if (urb->number_of_packets < 0) { | ||
459 | ndesc = 0; | ||
460 | } else if (urb->number_of_packets >= ISODESC_MAX) { | ||
461 | ndesc = ISODESC_MAX; | ||
462 | } else { | ||
463 | ndesc = urb->number_of_packets; | ||
464 | } | ||
465 | } else { | ||
466 | ndesc = 0; | ||
467 | } | ||
468 | lendesc = ndesc*sizeof(struct mon_bin_isodesc); | ||
469 | |||
410 | urb_length = (ev_type == 'S') ? | 470 | urb_length = (ev_type == 'S') ? |
411 | urb->transfer_buffer_length : urb->actual_length; | 471 | urb->transfer_buffer_length : urb->actual_length; |
412 | length = urb_length; | 472 | length = urb_length; |
@@ -429,10 +489,12 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
429 | dir = 0; | 489 | dir = 0; |
430 | } | 490 | } |
431 | 491 | ||
432 | if (rp->mmap_active) | 492 | if (rp->mmap_active) { |
433 | offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE); | 493 | offset = mon_buff_area_alloc_contiguous(rp, |
434 | else | 494 | length + PKT_SIZE + lendesc); |
435 | offset = mon_buff_area_alloc(rp, length + PKT_SIZE); | 495 | } else { |
496 | offset = mon_buff_area_alloc(rp, length + PKT_SIZE + lendesc); | ||
497 | } | ||
436 | if (offset == ~0) { | 498 | if (offset == ~0) { |
437 | rp->cnt_lost++; | 499 | rp->cnt_lost++; |
438 | spin_unlock_irqrestore(&rp->b_lock, flags); | 500 | spin_unlock_irqrestore(&rp->b_lock, flags); |
@@ -456,9 +518,31 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
456 | ep->ts_usec = ts.tv_usec; | 518 | ep->ts_usec = ts.tv_usec; |
457 | ep->status = status; | 519 | ep->status = status; |
458 | ep->len_urb = urb_length; | 520 | ep->len_urb = urb_length; |
459 | ep->len_cap = length; | 521 | ep->len_cap = length + lendesc; |
522 | ep->xfer_flags = urb->transfer_flags; | ||
523 | |||
524 | if (usb_endpoint_xfer_int(epd)) { | ||
525 | ep->interval = urb->interval; | ||
526 | } else if (usb_endpoint_xfer_isoc(epd)) { | ||
527 | ep->interval = urb->interval; | ||
528 | ep->start_frame = urb->start_frame; | ||
529 | ep->s.iso.error_count = urb->error_count; | ||
530 | ep->s.iso.numdesc = urb->number_of_packets; | ||
531 | } | ||
532 | |||
533 | if (usb_endpoint_xfer_control(epd) && ev_type == 'S') { | ||
534 | ep->flag_setup = mon_bin_get_setup(ep->s.setup, urb, ev_type); | ||
535 | } else { | ||
536 | ep->flag_setup = '-'; | ||
537 | } | ||
538 | |||
539 | if (ndesc != 0) { | ||
540 | ep->ndesc = ndesc; | ||
541 | mon_bin_get_isodesc(rp, offset, urb, ev_type, ndesc); | ||
542 | if ((offset += lendesc) >= rp->b_size) | ||
543 | offset -= rp->b_size; | ||
544 | } | ||
460 | 545 | ||
461 | ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type); | ||
462 | if (length != 0) { | 546 | if (length != 0) { |
463 | ep->flag_data = mon_bin_get_data(rp, offset, urb, length); | 547 | ep->flag_data = mon_bin_get_data(rp, offset, urb, length); |
464 | if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ | 548 | if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ |
@@ -592,7 +676,8 @@ err_alloc: | |||
592 | * Returns zero or error. | 676 | * Returns zero or error. |
593 | */ | 677 | */ |
594 | static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, | 678 | static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, |
595 | struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes) | 679 | struct mon_bin_hdr __user *hdr, unsigned int hdrbytes, |
680 | void __user *data, unsigned int nbytes) | ||
596 | { | 681 | { |
597 | unsigned long flags; | 682 | unsigned long flags; |
598 | struct mon_bin_hdr *ep; | 683 | struct mon_bin_hdr *ep; |
@@ -609,7 +694,7 @@ static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, | |||
609 | 694 | ||
610 | ep = MON_OFF2HDR(rp, rp->b_out); | 695 | ep = MON_OFF2HDR(rp, rp->b_out); |
611 | 696 | ||
612 | if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) { | 697 | if (copy_to_user(hdr, ep, hdrbytes)) { |
613 | mutex_unlock(&rp->fetch_lock); | 698 | mutex_unlock(&rp->fetch_lock); |
614 | return -EFAULT; | 699 | return -EFAULT; |
615 | } | 700 | } |
@@ -657,6 +742,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, | |||
657 | size_t nbytes, loff_t *ppos) | 742 | size_t nbytes, loff_t *ppos) |
658 | { | 743 | { |
659 | struct mon_reader_bin *rp = file->private_data; | 744 | struct mon_reader_bin *rp = file->private_data; |
745 | unsigned int hdrbytes = PKT_SZ_API0; | ||
660 | unsigned long flags; | 746 | unsigned long flags; |
661 | struct mon_bin_hdr *ep; | 747 | struct mon_bin_hdr *ep; |
662 | unsigned int offset; | 748 | unsigned int offset; |
@@ -674,8 +760,8 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, | |||
674 | 760 | ||
675 | ep = MON_OFF2HDR(rp, rp->b_out); | 761 | ep = MON_OFF2HDR(rp, rp->b_out); |
676 | 762 | ||
677 | if (rp->b_read < sizeof(struct mon_bin_hdr)) { | 763 | if (rp->b_read < hdrbytes) { |
678 | step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read); | 764 | step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read)); |
679 | ptr = ((char *)ep) + rp->b_read; | 765 | ptr = ((char *)ep) + rp->b_read; |
680 | if (step_len && copy_to_user(buf, ptr, step_len)) { | 766 | if (step_len && copy_to_user(buf, ptr, step_len)) { |
681 | mutex_unlock(&rp->fetch_lock); | 767 | mutex_unlock(&rp->fetch_lock); |
@@ -687,13 +773,13 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, | |||
687 | done += step_len; | 773 | done += step_len; |
688 | } | 774 | } |
689 | 775 | ||
690 | if (rp->b_read >= sizeof(struct mon_bin_hdr)) { | 776 | if (rp->b_read >= hdrbytes) { |
691 | step_len = ep->len_cap; | 777 | step_len = ep->len_cap; |
692 | step_len -= rp->b_read - sizeof(struct mon_bin_hdr); | 778 | step_len -= rp->b_read - hdrbytes; |
693 | if (step_len > nbytes) | 779 | if (step_len > nbytes) |
694 | step_len = nbytes; | 780 | step_len = nbytes; |
695 | offset = rp->b_out + PKT_SIZE; | 781 | offset = rp->b_out + PKT_SIZE; |
696 | offset += rp->b_read - sizeof(struct mon_bin_hdr); | 782 | offset += rp->b_read - hdrbytes; |
697 | if (offset >= rp->b_size) | 783 | if (offset >= rp->b_size) |
698 | offset -= rp->b_size; | 784 | offset -= rp->b_size; |
699 | if (copy_from_buf(rp, offset, buf, step_len)) { | 785 | if (copy_from_buf(rp, offset, buf, step_len)) { |
@@ -709,7 +795,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, | |||
709 | /* | 795 | /* |
710 | * Check if whole packet was read, and if so, jump to the next one. | 796 | * Check if whole packet was read, and if so, jump to the next one. |
711 | */ | 797 | */ |
712 | if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) { | 798 | if (rp->b_read >= hdrbytes + ep->len_cap) { |
713 | spin_lock_irqsave(&rp->b_lock, flags); | 799 | spin_lock_irqsave(&rp->b_lock, flags); |
714 | mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); | 800 | mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); |
715 | spin_unlock_irqrestore(&rp->b_lock, flags); | 801 | spin_unlock_irqrestore(&rp->b_lock, flags); |
@@ -908,6 +994,7 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, | |||
908 | break; | 994 | break; |
909 | 995 | ||
910 | case MON_IOCX_GET: | 996 | case MON_IOCX_GET: |
997 | case MON_IOCX_GETX: | ||
911 | { | 998 | { |
912 | struct mon_bin_get getb; | 999 | struct mon_bin_get getb; |
913 | 1000 | ||
@@ -917,8 +1004,9 @@ static int mon_bin_ioctl(struct inode *inode, struct file *file, | |||
917 | 1004 | ||
918 | if (getb.alloc > 0x10000000) /* Want to cast to u32 */ | 1005 | if (getb.alloc > 0x10000000) /* Want to cast to u32 */ |
919 | return -EINVAL; | 1006 | return -EINVAL; |
920 | ret = mon_bin_get_event(file, rp, | 1007 | ret = mon_bin_get_event(file, rp, getb.hdr, |
921 | getb.hdr, getb.data, (unsigned int)getb.alloc); | 1008 | (cmd == MON_IOCX_GET)? PKT_SZ_API0: PKT_SZ_API1, |
1009 | getb.data, (unsigned int)getb.alloc); | ||
922 | } | 1010 | } |
923 | break; | 1011 | break; |
924 | 1012 | ||
@@ -984,16 +1072,18 @@ static long mon_bin_compat_ioctl(struct file *file, | |||
984 | 1072 | ||
985 | switch (cmd) { | 1073 | switch (cmd) { |
986 | 1074 | ||
987 | case MON_IOCX_GET32: { | 1075 | case MON_IOCX_GET32: |
1076 | case MON_IOCX_GETX32: | ||
1077 | { | ||
988 | struct mon_bin_get32 getb; | 1078 | struct mon_bin_get32 getb; |
989 | 1079 | ||
990 | if (copy_from_user(&getb, (void __user *)arg, | 1080 | if (copy_from_user(&getb, (void __user *)arg, |
991 | sizeof(struct mon_bin_get32))) | 1081 | sizeof(struct mon_bin_get32))) |
992 | return -EFAULT; | 1082 | return -EFAULT; |
993 | 1083 | ||
994 | ret = mon_bin_get_event(file, rp, | 1084 | ret = mon_bin_get_event(file, rp, compat_ptr(getb.hdr32), |
995 | compat_ptr(getb.hdr32), compat_ptr(getb.data32), | 1085 | (cmd == MON_IOCX_GET32)? PKT_SZ_API0: PKT_SZ_API1, |
996 | getb.alloc32); | 1086 | compat_ptr(getb.data32), getb.alloc32); |
997 | if (ret < 0) | 1087 | if (ret < 0) |
998 | return ret; | 1088 | return ret; |
999 | } | 1089 | } |