aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ehci-hub.c144
-rw-r--r--drivers/usb/host/ehci-q.c101
-rw-r--r--drivers/usb/misc/ehset.c20
3 files changed, 263 insertions, 2 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 269a2e8ad0ab..d0d4cc151e71 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -712,6 +712,142 @@ ehci_hub_descriptor (
712} 712}
713 713
714/*-------------------------------------------------------------------------*/ 714/*-------------------------------------------------------------------------*/
715#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
716
717static void usb_ehset_completion(struct urb *urb)
718{
719 struct completion *done = urb->context;
720
721 complete(done);
722}
723static int submit_single_step_set_feature(
724 struct usb_hcd *hcd,
725 struct urb *urb,
726 int is_setup
727);
728
729/*
730 * Allocate and initialize a control URB. This request will be used by the
731 * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
732 * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
733 * Return NULL if failed.
734 */
735static struct urb *request_single_step_set_feature_urb(
736 struct usb_device *udev,
737 void *dr,
738 void *buf,
739 struct completion *done
740) {
741 struct urb *urb;
742 struct usb_hcd *hcd = bus_to_hcd(udev->bus);
743 struct usb_host_endpoint *ep;
744
745 urb = usb_alloc_urb(0, GFP_KERNEL);
746 if (!urb)
747 return NULL;
748
749 urb->pipe = usb_rcvctrlpipe(udev, 0);
750 ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
751 [usb_pipeendpoint(urb->pipe)];
752 if (!ep) {
753 usb_free_urb(urb);
754 return NULL;
755 }
756
757 urb->ep = ep;
758 urb->dev = udev;
759 urb->setup_packet = (void *)dr;
760 urb->transfer_buffer = buf;
761 urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
762 urb->complete = usb_ehset_completion;
763 urb->status = -EINPROGRESS;
764 urb->actual_length = 0;
765 urb->transfer_flags = URB_DIR_IN;
766 usb_get_urb(urb);
767 atomic_inc(&urb->use_count);
768 atomic_inc(&urb->dev->urbnum);
769 urb->setup_dma = dma_map_single(
770 hcd->self.controller,
771 urb->setup_packet,
772 sizeof(struct usb_ctrlrequest),
773 DMA_TO_DEVICE);
774 urb->transfer_dma = dma_map_single(
775 hcd->self.controller,
776 urb->transfer_buffer,
777 urb->transfer_buffer_length,
778 DMA_FROM_DEVICE);
779 urb->context = done;
780 return urb;
781}
782
783static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
784{
785 int retval = -ENOMEM;
786 struct usb_ctrlrequest *dr;
787 struct urb *urb;
788 struct usb_device *udev;
789 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
790 struct usb_device_descriptor *buf;
791 DECLARE_COMPLETION_ONSTACK(done);
792
793 /* Obtain udev of the rhub's child port */
794 udev = usb_hub_find_child(hcd->self.root_hub, port);
795 if (!udev) {
796 ehci_err(ehci, "No device attached to the RootHub\n");
797 return -ENODEV;
798 }
799 buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
800 if (!buf)
801 return -ENOMEM;
802
803 dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
804 if (!dr) {
805 kfree(buf);
806 return -ENOMEM;
807 }
808
809 /* Fill Setup packet for GetDescriptor */
810 dr->bRequestType = USB_DIR_IN;
811 dr->bRequest = USB_REQ_GET_DESCRIPTOR;
812 dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
813 dr->wIndex = 0;
814 dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
815 urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
816 if (!urb)
817 goto cleanup;
818
819 /* Submit just the SETUP stage */
820 retval = submit_single_step_set_feature(hcd, urb, 1);
821 if (retval)
822 goto out1;
823 if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
824 usb_kill_urb(urb);
825 retval = -ETIMEDOUT;
826 ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
827 goto out1;
828 }
829 msleep(15 * 1000);
830
831 /* Complete remaining DATA and STATUS stages using the same URB */
832 urb->status = -EINPROGRESS;
833 usb_get_urb(urb);
834 atomic_inc(&urb->use_count);
835 atomic_inc(&urb->dev->urbnum);
836 retval = submit_single_step_set_feature(hcd, urb, 0);
837 if (!retval && !wait_for_completion_timeout(&done,
838 msecs_to_jiffies(2000))) {
839 usb_kill_urb(urb);
840 retval = -ETIMEDOUT;
841 ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
842 }
843out1:
844 usb_free_urb(urb);
845cleanup:
846 kfree(dr);
847 kfree(buf);
848 return retval;
849}
850/*-------------------------------------------------------------------------*/
715 851
716static int ehci_hub_control ( 852static int ehci_hub_control (
717 struct usb_hcd *hcd, 853 struct usb_hcd *hcd,
@@ -1086,7 +1222,13 @@ static int ehci_hub_control (
1086 * about the EHCI-specific stuff. 1222 * about the EHCI-specific stuff.
1087 */ 1223 */
1088 case USB_PORT_FEAT_TEST: 1224 case USB_PORT_FEAT_TEST:
1089 if (!selector || selector > 5) 1225 if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
1226 spin_unlock_irqrestore(&ehci->lock, flags);
1227 retval = ehset_single_step_set_feature(hcd,
1228 wIndex);
1229 spin_lock_irqsave(&ehci->lock, flags);
1230 break;
1231 } else if (!selector || selector > 5)
1090 goto error; 1232 goto error;
1091 spin_unlock_irqrestore(&ehci->lock, flags); 1233 spin_unlock_irqrestore(&ehci->lock, flags);
1092 ehci_quiesce(ehci); 1234 ehci_quiesce(ehci);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index b637a65e1e52..903d00dd6683 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1139,6 +1139,107 @@ submit_async (
1139} 1139}
1140 1140
1141/*-------------------------------------------------------------------------*/ 1141/*-------------------------------------------------------------------------*/
1142/*
1143 * This function creates the qtds and submits them for the
1144 * SINGLE_STEP_SET_FEATURE Test.
1145 * This is done in two parts: first SETUP req for GetDesc is sent then
1146 * 15 seconds later, the IN stage for GetDesc starts to req data from dev
1147 *
1148 * is_setup : i/p arguement decides which of the two stage needs to be
1149 * performed; TRUE - SETUP and FALSE - IN+STATUS
1150 * Returns 0 if success
1151 */
1152static int submit_single_step_set_feature(
1153 struct usb_hcd *hcd,
1154 struct urb *urb,
1155 int is_setup
1156) {
1157 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
1158 struct list_head qtd_list;
1159 struct list_head *head;
1160
1161 struct ehci_qtd *qtd, *qtd_prev;
1162 dma_addr_t buf;
1163 int len, maxpacket;
1164 u32 token;
1165
1166 INIT_LIST_HEAD(&qtd_list);
1167 head = &qtd_list;
1168
1169 /* URBs map to sequences of QTDs: one logical transaction */
1170 qtd = ehci_qtd_alloc(ehci, GFP_KERNEL);
1171 if (unlikely(!qtd))
1172 return -1;
1173 list_add_tail(&qtd->qtd_list, head);
1174 qtd->urb = urb;
1175
1176 token = QTD_STS_ACTIVE;
1177 token |= (EHCI_TUNE_CERR << 10);
1178
1179 len = urb->transfer_buffer_length;
1180 /*
1181 * Check if the request is to perform just the SETUP stage (getDesc)
1182 * as in SINGLE_STEP_SET_FEATURE test, DATA stage (IN) happens
1183 * 15 secs after the setup
1184 */
1185 if (is_setup) {
1186 /* SETUP pid */
1187 qtd_fill(ehci, qtd, urb->setup_dma,
1188 sizeof(struct usb_ctrlrequest),
1189 token | (2 /* "setup" */ << 8), 8);
1190
1191 submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
1192 return 0; /*Return now; we shall come back after 15 seconds*/
1193 }
1194
1195 /*
1196 * IN: data transfer stage: buffer setup : start the IN txn phase for
1197 * the get_Desc SETUP which was sent 15seconds back
1198 */
1199 token ^= QTD_TOGGLE; /*We need to start IN with DATA-1 Pid-sequence*/
1200 buf = urb->transfer_dma;
1201
1202 token |= (1 /* "in" */ << 8); /*This is IN stage*/
1203
1204 maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, 0));
1205
1206 qtd_fill(ehci, qtd, buf, len, token, maxpacket);
1207
1208 /*
1209 * Our IN phase shall always be a short read; so keep the queue running
1210 * and let it advance to the next qtd which zero length OUT status
1211 */
1212 qtd->hw_alt_next = EHCI_LIST_END(ehci);
1213
1214 /* STATUS stage for GetDesc control request */
1215 token ^= 0x0100; /* "in" <--> "out" */
1216 token |= QTD_TOGGLE; /* force DATA1 */
1217
1218 qtd_prev = qtd;
1219 qtd = ehci_qtd_alloc(ehci, GFP_ATOMIC);
1220 if (unlikely(!qtd))
1221 goto cleanup;
1222 qtd->urb = urb;
1223 qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
1224 list_add_tail(&qtd->qtd_list, head);
1225
1226 /* dont fill any data in such packets */
1227 qtd_fill(ehci, qtd, 0, 0, token, 0);
1228
1229 /* by default, enable interrupt on urb completion */
1230 if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
1231 qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
1232
1233 submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
1234
1235 return 0;
1236
1237cleanup:
1238 qtd_list_free(ehci, urb, head);
1239 return -1;
1240}
1241
1242/*-------------------------------------------------------------------------*/
1142 1243
1143static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) 1244static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
1144{ 1245{
diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
index d2864b3f41fe..c31b4a33e6bb 100644
--- a/drivers/usb/misc/ehset.c
+++ b/drivers/usb/misc/ehset.c
@@ -96,7 +96,25 @@ static int ehset_probe(struct usb_interface *intf,
96 kfree(buf); 96 kfree(buf);
97 break; 97 break;
98 case TEST_SINGLE_STEP_SET_FEATURE: 98 case TEST_SINGLE_STEP_SET_FEATURE:
99 /* unsupported for now */ 99 /*
100 * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
101 *
102 * Note, this test is only supported on root hubs since the
103 * SetPortFeature handling can only be done inside the HCD's
104 * hub_control callback function.
105 */
106 if (hub_udev != dev->bus->root_hub) {
107 dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
108 break;
109 }
110
111 ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
112 USB_REQ_SET_FEATURE, USB_RT_PORT,
113 USB_PORT_FEAT_TEST,
114 (6 << 8) | portnum,
115 NULL, 0, 60 * 1000);
116
117 break;
100 default: 118 default:
101 dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n", 119 dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
102 __func__, test_pid); 120 __func__, test_pid);