Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | // SPDX-License-Identifier: GPL-2.0 /* * Common code for usb urb handling, based on the musb-new code * * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> * */ #include <dm/device.h> #include <dm/device_compat.h> #include <linux/usb/usb_urb_compat.h> #include <time.h> #include <usb.h> #if CONFIG_IS_ENABLED(DM_USB) struct usb_device *usb_dev_get_parent(struct usb_device *udev) { struct udevice *parent = udev->dev->parent; /* * When called from usb-uclass.c: usb_scan_device() udev->dev points * to the parent udevice, not the actual udevice belonging to the * udev as the device is not instantiated yet. * * If dev is an usb-bus, then we are called from usb_scan_device() for * an usb-device plugged directly into the root port, return NULL. */ if (device_get_uclass_id(udev->dev) == UCLASS_USB) return NULL; /* * If these 2 are not the same we are being called from * usb_scan_device() and udev itself is the parent. */ if (dev_get_parent_priv(udev->dev) != udev) return udev; /* We are being called normally, use the parent pointer */ if (device_get_uclass_id(parent) == UCLASS_USB_HUB) return dev_get_parent_priv(parent); return NULL; } #else struct usb_device *usb_dev_get_parent(struct usb_device *udev) { return udev->parent; } #endif static void usb_urb_complete(struct urb *urb) { urb->dev->status &= ~USB_ST_NOT_PROC; urb->dev->act_len = urb->actual_length; if (urb->status == -EINPROGRESS) urb->status = 0; } void usb_urb_fill(struct urb *urb, struct usb_host_endpoint *hep, struct usb_device *dev, int endpoint_type, unsigned long pipe, void *buffer, int len, struct devrequest *setup, int interval) { int epnum = usb_pipeendpoint(pipe); int is_in = usb_pipein(pipe); u16 maxpacketsize = is_in ? dev->epmaxpacketin[epnum] : dev->epmaxpacketout[epnum]; memset(urb, 0, sizeof(struct urb)); memset(hep, 0, sizeof(struct usb_host_endpoint)); INIT_LIST_HEAD(&hep->urb_list); INIT_LIST_HEAD(&urb->urb_list); urb->ep = hep; urb->complete = usb_urb_complete; urb->status = -EINPROGRESS; urb->dev = dev; urb->pipe = pipe; urb->transfer_buffer = buffer; urb->transfer_dma = (unsigned long)buffer; urb->transfer_buffer_length = len; urb->setup_packet = (unsigned char *)setup; urb->ep->desc.wMaxPacketSize = __cpu_to_le16(maxpacketsize); urb->ep->desc.bmAttributes = endpoint_type; urb->ep->desc.bEndpointAddress = ((is_in ? USB_DIR_IN : USB_DIR_OUT) | epnum); urb->ep->desc.bInterval = interval; } int usb_urb_submit(struct usb_hcd *hcd, struct urb *urb) { const struct usb_urb_ops *ops = hcd->urb_ops; unsigned long timeout; int ret; if (!ops) return -EINVAL; ret = ops->urb_enqueue(hcd, urb, 0); if (ret < 0) { printf("Failed to enqueue URB to controller\n"); return ret; } timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe); do { if (ctrlc()) return -EIO; ops->isr(0, hcd); } while (urb->status == -EINPROGRESS && get_timer(0) < timeout); if (urb->status == -EINPROGRESS) ops->urb_dequeue(hcd, urb, -ETIME); return urb->status; } int usb_urb_submit_control(struct usb_hcd *hcd, struct urb *urb, struct usb_host_endpoint *hep, struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup, int interval, enum usb_device_speed speed) { const struct usb_urb_ops *ops = hcd->urb_ops; usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe, buffer, len, setup, 0); /* Fix speed for non hub-attached devices */ if (!usb_dev_get_parent(dev)) { dev->speed = speed; if (ops->hub_control) return ops->hub_control(hcd, dev, pipe, buffer, len, setup); } return usb_urb_submit(hcd, urb); } int usb_urb_submit_bulk(struct usb_hcd *hcd, struct urb *urb, struct usb_host_endpoint *hep, struct usb_device *dev, unsigned long pipe, void *buffer, int len) { usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_BULK, pipe, buffer, len, NULL, 0); return usb_urb_submit(hcd, urb); } int usb_urb_submit_irq(struct usb_hcd *hcd, struct urb *urb, struct usb_host_endpoint *hep, struct usb_device *dev, unsigned long pipe, void *buffer, int len, int interval) { usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_INT, pipe, buffer, len, NULL, interval); return usb_urb_submit(hcd, urb); } |