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 | } |
