diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-05-25 16:06:31 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2014-09-07 17:45:10 +0200 |
commit | 12ce7fc2cce5531723ea7d141df80142891989d7 (patch) | |
tree | dc4e3320f8ed0932265b3c917448a83f7dcecafe /utils | |
parent | 1dc1a9310e8a078a633dd90def13103f80e01ce7 (diff) | |
download | rockbox-12ce7fc2cce5531723ea7d141df80142891989d7.tar.gz rockbox-12ce7fc2cce5531723ea7d141df80142891989d7.zip |
hwstub: remove protocol to make it use its own interface
This way, hwstub can be implemented along with other usb features/interfaces.
Change-Id: I7148cab845049cc0a8b8e740fa0d52d3a385eaed
Diffstat (limited to 'utils')
-rw-r--r-- | utils/hwstub/hwstub_protocol.h | 113 | ||||
-rw-r--r-- | utils/hwstub/lib/hwstub.c | 125 | ||||
-rw-r--r-- | utils/hwstub/lib/hwstub.h | 8 | ||||
-rw-r--r-- | utils/hwstub/stub/main.c | 219 | ||||
-rw-r--r-- | utils/hwstub/tools/hwstub_shell.cpp | 17 |
5 files changed, 347 insertions, 135 deletions
diff --git a/utils/hwstub/hwstub_protocol.h b/utils/hwstub/hwstub_protocol.h index 2c11025b1e..02c065cbe0 100644 --- a/utils/hwstub/hwstub_protocol.h +++ b/utils/hwstub/hwstub_protocol.h | |||
@@ -21,46 +21,46 @@ | |||
21 | #ifndef __HWSTUB_PROTOCOL__ | 21 | #ifndef __HWSTUB_PROTOCOL__ |
22 | #define __HWSTUB_PROTOCOL__ | 22 | #define __HWSTUB_PROTOCOL__ |
23 | 23 | ||
24 | #define HWSTUB_CLASS 0xff | 24 | /** |
25 | #define HWSTUB_SUBCLASS 0xac | 25 | * HWStub protocol version |
26 | #define HWSTUB_PROTOCOL 0x1d | 26 | */ |
27 | 27 | ||
28 | #define HWSTUB_VERSION_MAJOR 3 | 28 | #define HWSTUB_VERSION_MAJOR 4 |
29 | #define HWSTUB_VERSION_MINOR 0 | 29 | #define HWSTUB_VERSION_MINOR 0 |
30 | #define HWSTUB_VERSION_REV 1 | 30 | #define HWSTUB_VERSION_REV 0 |
31 | 31 | ||
32 | #define HWSTUB_VERSION__(maj,min,rev) #maj"."#min"."#rev | 32 | #define HWSTUB_VERSION__(maj,min,rev) #maj"."#min"."#rev |
33 | #define HWSTUB_VERSION_(maj,min,rev) HWSTUB_VERSION__(maj,min,rev) | 33 | #define HWSTUB_VERSION_(maj,min,rev) HWSTUB_VERSION__(maj,min,rev) |
34 | #define HWSTUB_VERSION HWSTUB_VERSION_(HWSTUB_VERSION_MAJOR,HWSTUB_VERSION_MINOR,HWSTUB_VERSION_REV) | 34 | #define HWSTUB_VERSION HWSTUB_VERSION_(HWSTUB_VERSION_MAJOR,HWSTUB_VERSION_MINOR,HWSTUB_VERSION_REV) |
35 | 35 | ||
36 | /** | ||
37 | * A device can use any VID:PID but in case hwstub is in full control of the | ||
38 | * device, the preferred VID:PID is the following. | ||
39 | */ | ||
40 | |||
36 | #define HWSTUB_USB_VID 0xfee1 | 41 | #define HWSTUB_USB_VID 0xfee1 |
37 | #define HWSTUB_USB_PID 0xdead | 42 | #define HWSTUB_USB_PID 0xdead |
38 | 43 | ||
39 | /** | 44 | /** |
40 | * Control commands | 45 | * The device class should be per interface and the hwstub interface must use |
41 | * | 46 | * the following class, subclass and protocol. |
42 | * These commands are sent to the device, using the standard bRequest field | ||
43 | * of the SETUP packet. This is to take advantage of both wIndex and wValue | ||
44 | * although it would have been more correct to send them to the interface. | ||
45 | */ | 47 | */ |
46 | 48 | ||
47 | /* list of commands */ | 49 | #define HWSTUB_CLASS 0xff |
48 | #define HWSTUB_GET_LOG 0 /* optional */ | 50 | #define HWSTUB_SUBCLASS 0x57 |
49 | #define HWSTUB_RW_MEM 1 /* optional */ | 51 | #define HWSTUB_PROTOCOL 0x0b |
50 | #define HWSTUB_CALL 2 /* optional */ | ||
51 | #define HWSTUB_JUMP 3 /* optional */ | ||
52 | 52 | ||
53 | /** | 53 | /** |
54 | * Descriptors can be retrieve using configuration descriptor or individually | 54 | * Descriptors can be retrieved using configuration descriptor or individually |
55 | * using the standard GetDescriptor request on the interface. | 55 | * using the standard GetDescriptor request on the interface. |
56 | */ | 56 | */ |
57 | 57 | ||
58 | /* list of possible information */ | 58 | #define HWSTUB_DT_VERSION 0x41 /* mandatory */ |
59 | #define HWSTUB_DT_VERSION 0x41 /* mandatory */ | 59 | #define HWSTUB_DT_LAYOUT 0x42 /* mandatory */ |
60 | #define HWSTUB_DT_LAYOUT 0x42 /* mandatory */ | 60 | #define HWSTUB_DT_TARGET 0x43 /* mandatory */ |
61 | #define HWSTUB_DT_TARGET 0x43 /* mandatory */ | 61 | #define HWSTUB_DT_STMP 0x44 /* optional */ |
62 | #define HWSTUB_DT_STMP 0x44 /* optional */ | 62 | #define HWSTUB_DT_PP 0x45 /* optional */ |
63 | #define HWSTUB_DT_PP 0x45 /* optional */ | 63 | #define HWSTUB_DT_DEVICE 0x46 /* optional */ |
64 | 64 | ||
65 | struct hwstub_version_desc_t | 65 | struct hwstub_version_desc_t |
66 | { | 66 | { |
@@ -120,25 +120,70 @@ struct hwstub_target_desc_t | |||
120 | char bName[58]; | 120 | char bName[58]; |
121 | } __attribute__((packed)); | 121 | } __attribute__((packed)); |
122 | 122 | ||
123 | struct hwstub_device_desc_t | ||
124 | { | ||
125 | uint8_t bLength; | ||
126 | uint8_t bDescriptorType; | ||
127 | /* Give the bRequest value for */ | ||
128 | } __attribute__((packed)); | ||
129 | |||
130 | /** | ||
131 | * Control commands | ||
132 | * | ||
133 | * These commands are sent to the interface, using the standard bRequest field | ||
134 | * of the SETUP packet. The wIndex contains the interface number. The wValue | ||
135 | * contains an ID which is used for requests requiring several transfers. | ||
136 | */ | ||
137 | |||
138 | #define HWSTUB_GET_LOG 0x40 | ||
139 | #define HWSTUB_READ 0x41 | ||
140 | #define HWSTUB_READ2 0x42 | ||
141 | #define HWSTUB_WRITE 0x43 | ||
142 | #define HWSTUB_EXEC 0x44 | ||
143 | |||
123 | /** | 144 | /** |
124 | * HWSTUB_GET_LOG: | 145 | * HWSTUB_GET_LOG: |
125 | * The log is returned as part of the control transfer. | 146 | * The log is returned as part of the control transfer. |
126 | */ | 147 | */ |
127 | 148 | ||
128 | /** | 149 | /** |
129 | * HWSTUB_RW_MEM: | 150 | * HWSTUB_READ and HWSTUB_READ2: |
130 | * The 32-bit address is split into two parts. | 151 | * Read a range of memory. The request works in two steps: first the host |
131 | * The low 16-bit are stored in wValue and the upper | 152 | * sends HWSTUB_READ with the parameters (address, length) and then |
132 | * 16-bit are stored in wIndex. Depending on the transfer direction, | 153 | * a HWSTUB_READ2 to retrieve the buffer. Both requests must use the same |
133 | * the transfer is either a read or a write. | 154 | * ID in wValue, otherwise the second request will be STALLed. |
134 | * The read/write on the device are guaranteed to be 16-bit/32-bit when | 155 | */ |
135 | * possible, making it suitable to read/write registers. */ | 156 | |
157 | struct hwstub_read_req_t | ||
158 | { | ||
159 | uint32_t dAddress; | ||
160 | } __attribute__((packed)); | ||
161 | |||
162 | /** | ||
163 | * HWSTUB_WRITE | ||
164 | * Write a range of memory. The payload starts with the following header, everything | ||
165 | * which follows is data. | ||
166 | */ | ||
167 | struct hwstub_write_req_t | ||
168 | { | ||
169 | uint32_t dAddress; | ||
170 | } __attribute__((packed)); | ||
136 | 171 | ||
137 | /** | 172 | /** |
138 | * HWSTUB_{CALL,JUMP}: | 173 | * HWSTUB_EXEC: |
139 | * The 32-bit address is split into two parts. | 174 | * Execute code at an address. Several options are available regarding ARM vs Thumb, |
140 | * The low 16-bit are stored in wValue and the upper | 175 | * jump vs call. |
141 | * 16-bit are stored in wIndex. Depending on the transfer direction, | 176 | */ |
142 | * the transfer is either a read or a write. */ | 177 | |
178 | #define HWSTUB_EXEC_ARM (0 << 0) /* target code is ARM */ | ||
179 | #define HWSTUB_EXEC_THUMB (1 << 0) /* target code is Thumb */ | ||
180 | #define HWSTUB_EXEC_JUMP (0 << 1) /* branch, code will never turn */ | ||
181 | #define HWSTUB_EXEC_CALL (1 << 1) /* call and expect return */ | ||
182 | |||
183 | struct hwstub_exec_req_t | ||
184 | { | ||
185 | uint32_t dAddress; | ||
186 | uint16_t bmFlags; | ||
187 | }; | ||
143 | 188 | ||
144 | #endif /* __HWSTUB_PROTOCOL__ */ | 189 | #endif /* __HWSTUB_PROTOCOL__ */ |
diff --git a/utils/hwstub/lib/hwstub.c b/utils/hwstub/lib/hwstub.c index 67a797ddfe..9f46159026 100644 --- a/utils/hwstub/lib/hwstub.c +++ b/utils/hwstub/lib/hwstub.c | |||
@@ -30,26 +30,78 @@ struct hwstub_device_t | |||
30 | { | 30 | { |
31 | libusb_device_handle *handle; | 31 | libusb_device_handle *handle; |
32 | int intf; | 32 | int intf; |
33 | int bulk_in; | 33 | unsigned buf_sz; |
34 | int bulk_out; | 34 | uint16_t id; |
35 | int int_in; | ||
36 | }; | 35 | }; |
37 | 36 | ||
37 | int hwstub_probe(libusb_device *dev) | ||
38 | { | ||
39 | struct libusb_config_descriptor *config = NULL; | ||
40 | int ret = -1; | ||
41 | if(libusb_get_config_descriptor(dev, 0, &config) != 0) | ||
42 | goto Lend; | ||
43 | /* search hwstub interface */ | ||
44 | for(unsigned i = 0; i < config->bNumInterfaces; i++) | ||
45 | { | ||
46 | /* hwstub interface has only one setting */ | ||
47 | if(config->interface[i].num_altsetting != 1) | ||
48 | continue; | ||
49 | const struct libusb_interface_descriptor *intf = &config->interface[i].altsetting[0]; | ||
50 | /* check class/subclass/protocol */ | ||
51 | if(intf->bInterfaceClass != HWSTUB_CLASS || | ||
52 | intf->bInterfaceSubClass != HWSTUB_SUBCLASS || | ||
53 | intf->bInterfaceProtocol != HWSTUB_PROTOCOL) | ||
54 | continue; | ||
55 | /* found ! */ | ||
56 | ret = i; | ||
57 | break; | ||
58 | } | ||
59 | Lend: | ||
60 | if(config) | ||
61 | libusb_free_config_descriptor(config); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | ssize_t hwstub_get_device_list(libusb_context *ctx, libusb_device ***list) | ||
66 | { | ||
67 | libusb_device **great_list; | ||
68 | ssize_t great_cnt = libusb_get_device_list(ctx, &great_list); | ||
69 | if(great_cnt < 0) | ||
70 | return great_cnt; | ||
71 | /* allocate a list (size at least one NULL entry at the end) */ | ||
72 | libusb_device **mylist = malloc(sizeof(libusb_device *) * (great_cnt + 1)); | ||
73 | memset(mylist, 0, sizeof(libusb_device *) * (great_cnt + 1)); | ||
74 | /* list hwstub devices */ | ||
75 | ssize_t cnt = 0; | ||
76 | for(int i = 0; i < great_cnt; i++) | ||
77 | if(hwstub_probe(great_list[i]) >= 0) | ||
78 | { | ||
79 | libusb_ref_device(great_list[i]); | ||
80 | mylist[cnt++] = great_list[i]; | ||
81 | } | ||
82 | /* free old list */ | ||
83 | libusb_free_device_list(great_list, 1); | ||
84 | /* return */ | ||
85 | *list = mylist; | ||
86 | return cnt; | ||
87 | } | ||
88 | |||
38 | struct hwstub_device_t *hwstub_open(libusb_device_handle *handle) | 89 | struct hwstub_device_t *hwstub_open(libusb_device_handle *handle) |
39 | { | 90 | { |
40 | struct hwstub_device_t *dev = malloc(sizeof(struct hwstub_device_t)); | 91 | struct hwstub_device_t *dev = malloc(sizeof(struct hwstub_device_t)); |
41 | memset(dev, 0, sizeof(struct hwstub_device_t)); | 92 | memset(dev, 0, sizeof(struct hwstub_device_t)); |
42 | dev->handle = handle; | 93 | dev->handle = handle; |
94 | dev->intf = -1; | ||
95 | dev->buf_sz = 1024; /* default size */ | ||
43 | libusb_device *mydev = libusb_get_device(dev->handle); | 96 | libusb_device *mydev = libusb_get_device(dev->handle); |
44 | 97 | dev->intf = hwstub_probe(mydev); | |
45 | int config_id; | 98 | if(dev->intf == -1) |
46 | libusb_get_configuration(dev->handle, &config_id); | ||
47 | struct libusb_device_descriptor dev_desc; | ||
48 | libusb_get_device_descriptor(mydev, &dev_desc); | ||
49 | if(dev_desc.bDeviceClass != HWSTUB_CLASS || | ||
50 | dev_desc.bDeviceSubClass != HWSTUB_SUBCLASS || | ||
51 | dev_desc.bDeviceProtocol != HWSTUB_PROTOCOL) | ||
52 | goto Lerr; | 99 | goto Lerr; |
100 | /* try to get actual buffer size */ | ||
101 | struct hwstub_layout_desc_t layout; | ||
102 | int sz = hwstub_get_desc(dev, HWSTUB_DT_LAYOUT, &layout, sizeof(layout)); | ||
103 | if(sz == (int)sizeof(layout)) | ||
104 | dev->buf_sz = layout->dBufferSize; | ||
53 | return dev; | 105 | return dev; |
54 | 106 | ||
55 | Lerr: | 107 | Lerr: |
@@ -66,49 +118,60 @@ int hwstub_release(struct hwstub_device_t *dev) | |||
66 | int hwstub_get_desc(struct hwstub_device_t *dev, uint16_t desc, void *info, size_t sz) | 118 | int hwstub_get_desc(struct hwstub_device_t *dev, uint16_t desc, void *info, size_t sz) |
67 | { | 119 | { |
68 | return libusb_control_transfer(dev->handle, | 120 | return libusb_control_transfer(dev->handle, |
69 | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, | 121 | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, |
70 | LIBUSB_REQUEST_GET_DESCRIPTOR, desc << 8, 0, info, sz, 1000); | 122 | LIBUSB_REQUEST_GET_DESCRIPTOR, desc << 8, dev->intf, info, sz, 1000); |
71 | } | 123 | } |
72 | 124 | ||
73 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) | 125 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz) |
74 | { | 126 | { |
75 | return libusb_control_transfer(dev->handle, | 127 | return libusb_control_transfer(dev->handle, |
76 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, | 128 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, |
77 | HWSTUB_GET_LOG, 0, 0, buf, sz, 1000); | 129 | HWSTUB_GET_LOG, 0, dev->intf, buf, sz, 1000); |
130 | } | ||
131 | |||
132 | static int _hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | ||
133 | { | ||
134 | struct hwstub_read_req_t read; | ||
135 | read.dAddress = addr; | ||
136 | int size = libusb_control_transfer(dev->handle, | ||
137 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT, | ||
138 | HWSTUB_READ, dev->id, dev->intf, &read, sizeof(read), 1000); | ||
139 | if(size != (int)sizeof(read)) | ||
140 | return -1; | ||
141 | return libusb_control_transfer(dev->handle, | ||
142 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, | ||
143 | HWSTUB_READ2, dev->id++, dev->intf, &read, sizeof(read), 1000); | ||
144 | } | ||
145 | |||
146 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz) | ||
147 | { | ||
78 | } | 148 | } |
79 | 149 | ||
80 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) | 150 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz) |
81 | { | 151 | { |
82 | size_t tot_sz = 0; | 152 | return read ? hwstub_read(dev, addr, buf, sz) : hwstub_write(dev, addr, buf, sz); |
83 | while(sz) | ||
84 | { | ||
85 | uint16_t xfer = MIN(1 * 1024, sz); | ||
86 | int ret = libusb_control_transfer(dev->handle, | ||
87 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | | ||
88 | (read ? LIBUSB_ENDPOINT_IN : LIBUSB_ENDPOINT_OUT), | ||
89 | HWSTUB_RW_MEM, addr & 0xffff, addr >> 16, buf, xfer, 1000); | ||
90 | if(ret != xfer) | ||
91 | return ret; | ||
92 | sz -= xfer; | ||
93 | addr += xfer; | ||
94 | buf += xfer; | ||
95 | tot_sz += xfer; | ||
96 | } | ||
97 | return tot_sz; | ||
98 | } | 153 | } |
99 | 154 | ||
100 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr) | 155 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr) |
101 | { | 156 | { |
157 | #if 0 | ||
102 | return libusb_control_transfer(dev->handle, | 158 | return libusb_control_transfer(dev->handle, |
103 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | | 159 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | |
104 | LIBUSB_ENDPOINT_OUT, HWSTUB_CALL, addr & 0xffff, addr >> 16, NULL, 0, | 160 | LIBUSB_ENDPOINT_OUT, HWSTUB_CALL, addr & 0xffff, addr >> 16, NULL, 0, |
105 | 1000); | 161 | 1000); |
162 | #else | ||
163 | return -1; | ||
164 | #endif | ||
106 | } | 165 | } |
107 | 166 | ||
108 | int hwstub_jump(struct hwstub_device_t *dev, uint32_t addr) | 167 | int hwstub_jump(struct hwstub_device_t *dev, uint32_t addr) |
109 | { | 168 | { |
169 | #if 0 | ||
110 | return libusb_control_transfer(dev->handle, | 170 | return libusb_control_transfer(dev->handle, |
111 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | | 171 | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE | |
112 | LIBUSB_ENDPOINT_OUT, HWSTUB_JUMP, addr & 0xffff, addr >> 16, NULL, 0, | 172 | LIBUSB_ENDPOINT_OUT, HWSTUB_JUMP, addr & 0xffff, addr >> 16, NULL, 0, |
113 | 1000); | 173 | 1000); |
174 | #else | ||
175 | return -1; | ||
176 | #endif | ||
114 | } | 177 | } |
diff --git a/utils/hwstub/lib/hwstub.h b/utils/hwstub/lib/hwstub.h index 69fdc63988..1599f6508b 100644 --- a/utils/hwstub/lib/hwstub.h +++ b/utils/hwstub/lib/hwstub.h | |||
@@ -36,6 +36,12 @@ extern "C" { | |||
36 | 36 | ||
37 | struct hwstub_device_t; | 37 | struct hwstub_device_t; |
38 | 38 | ||
39 | /* Returns hwstub interface, or -1 if none was found */ | ||
40 | int hwstub_probe(libusb_device *dev); | ||
41 | /* Helper function which returns a list of all hwstub devices found. The caller | ||
42 | * must unref all of them when done, possibly using libusb_free_device_list(). | ||
43 | * Return number of devices or <0 on error */ | ||
44 | ssize_t hwstub_get_device_list(libusb_context *ctx, libusb_device ***list); | ||
39 | /* Returns NULL on error */ | 45 | /* Returns NULL on error */ |
40 | struct hwstub_device_t *hwstub_open(libusb_device_handle *handle); | 46 | struct hwstub_device_t *hwstub_open(libusb_device_handle *handle); |
41 | /* Returns 0 on success. Does *NOT* close the usb handle */ | 47 | /* Returns 0 on success. Does *NOT* close the usb handle */ |
@@ -46,6 +52,8 @@ int hwstub_get_desc(struct hwstub_device_t *dev, uint16_t desc, void *info, size | |||
46 | /* Returns number of bytes filled */ | 52 | /* Returns number of bytes filled */ |
47 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); | 53 | int hwstub_get_log(struct hwstub_device_t *dev, void *buf, size_t sz); |
48 | /* Returns number of bytes written/read or <0 on error */ | 54 | /* Returns number of bytes written/read or <0 on error */ |
55 | int hwstub_read(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); | ||
56 | int hwstub_write(struct hwstub_device_t *dev, uint32_t addr, void *buf, size_t sz); | ||
49 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); | 57 | int hwstub_rw_mem(struct hwstub_device_t *dev, int read, uint32_t addr, void *buf, size_t sz); |
50 | /* Returns <0 on error */ | 58 | /* Returns <0 on error */ |
51 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); | 59 | int hwstub_call(struct hwstub_device_t *dev, uint32_t addr); |
diff --git a/utils/hwstub/stub/main.c b/utils/hwstub/stub/main.c index c831de0196..a8d99fc863 100644 --- a/utils/hwstub/stub/main.c +++ b/utils/hwstub/stub/main.c | |||
@@ -45,15 +45,14 @@ static bool g_exit = false; | |||
45 | * | 45 | * |
46 | */ | 46 | */ |
47 | 47 | ||
48 | static struct usb_device_descriptor __attribute__((aligned(2))) | 48 | static struct usb_device_descriptor device_descriptor= |
49 | device_descriptor= | ||
50 | { | 49 | { |
51 | .bLength = sizeof(struct usb_device_descriptor), | 50 | .bLength = sizeof(struct usb_device_descriptor), |
52 | .bDescriptorType = USB_DT_DEVICE, | 51 | .bDescriptorType = USB_DT_DEVICE, |
53 | .bcdUSB = 0x0200, | 52 | .bcdUSB = 0x0200, |
54 | .bDeviceClass = HWSTUB_CLASS, | 53 | .bDeviceClass = USB_CLASS_PER_INTERFACE, |
55 | .bDeviceSubClass = HWSTUB_SUBCLASS, | 54 | .bDeviceSubClass = 0, |
56 | .bDeviceProtocol = HWSTUB_PROTOCOL, | 55 | .bDeviceProtocol = 0, |
57 | .bMaxPacketSize0 = 64, | 56 | .bMaxPacketSize0 = 64, |
58 | .idVendor = HWSTUB_USB_VID, | 57 | .idVendor = HWSTUB_USB_VID, |
59 | .idProduct = HWSTUB_USB_PID, | 58 | .idProduct = HWSTUB_USB_PID, |
@@ -66,29 +65,41 @@ static struct usb_device_descriptor __attribute__((aligned(2))) | |||
66 | 65 | ||
67 | #define USB_MAX_CURRENT 200 | 66 | #define USB_MAX_CURRENT 200 |
68 | 67 | ||
69 | static struct usb_config_descriptor __attribute__((aligned(2))) | 68 | static struct usb_config_descriptor config_descriptor = |
70 | config_descriptor = | ||
71 | { | 69 | { |
72 | .bLength = sizeof(struct usb_config_descriptor), | 70 | .bLength = sizeof(struct usb_config_descriptor), |
73 | .bDescriptorType = USB_DT_CONFIG, | 71 | .bDescriptorType = USB_DT_CONFIG, |
74 | .wTotalLength = 0, /* will be filled in later */ | 72 | .wTotalLength = 0, /* will be filled in later */ |
75 | .bNumInterfaces = 0, | 73 | .bNumInterfaces = 1, |
76 | .bConfigurationValue = 1, | 74 | .bConfigurationValue = 1, |
77 | .iConfiguration = 0, | 75 | .iConfiguration = 0, |
78 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, | 76 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, |
79 | .bMaxPower = (USB_MAX_CURRENT + 1) / 2, /* In 2mA units */ | 77 | .bMaxPower = (USB_MAX_CURRENT + 1) / 2, /* In 2mA units */ |
80 | }; | 78 | }; |
81 | 79 | ||
82 | static const struct usb_string_descriptor __attribute__((aligned(2))) | 80 | #define USB_HWSTUB_INTF 0 |
83 | usb_string_iManufacturer = | 81 | |
82 | static struct usb_interface_descriptor interface_descriptor = | ||
83 | { | ||
84 | .bLength = sizeof(struct usb_interface_descriptor), | ||
85 | .bDescriptorType = USB_DT_INTERFACE, | ||
86 | .bInterfaceNumber = USB_HWSTUB_INTF, | ||
87 | .bAlternateSetting = 0, | ||
88 | .bNumEndpoints = 0, | ||
89 | .bInterfaceClass = HWSTUB_CLASS, | ||
90 | .bInterfaceSubClass = HWSTUB_SUBCLASS, | ||
91 | .bInterfaceProtocol = HWSTUB_PROTOCOL, | ||
92 | .iInterface = 3 | ||
93 | }; | ||
94 | |||
95 | static const struct usb_string_descriptor usb_string_iManufacturer = | ||
84 | { | 96 | { |
85 | 24, | 97 | 24, |
86 | USB_DT_STRING, | 98 | USB_DT_STRING, |
87 | {'R', 'o', 'c', 'k', 'b', 'o', 'x', '.', 'o', 'r', 'g'} | 99 | {'R', 'o', 'c', 'k', 'b', 'o', 'x', '.', 'o', 'r', 'g'} |
88 | }; | 100 | }; |
89 | 101 | ||
90 | static const struct usb_string_descriptor __attribute__((aligned(2))) | 102 | static const struct usb_string_descriptor usb_string_iProduct = |
91 | usb_string_iProduct = | ||
92 | { | 103 | { |
93 | 44, | 104 | 44, |
94 | USB_DT_STRING, | 105 | USB_DT_STRING, |
@@ -97,17 +108,22 @@ static const struct usb_string_descriptor __attribute__((aligned(2))) | |||
97 | 's', 't', 'u', 'b'} | 108 | 's', 't', 'u', 'b'} |
98 | }; | 109 | }; |
99 | 110 | ||
111 | static const struct usb_string_descriptor usb_string_iInterface = | ||
112 | { | ||
113 | 14, | ||
114 | USB_DT_STRING, | ||
115 | {'H', 'W', 'S', 't', 'u', 'b'} | ||
116 | }; | ||
117 | |||
100 | /* this is stringid #0: languages supported */ | 118 | /* this is stringid #0: languages supported */ |
101 | static const struct usb_string_descriptor __attribute__((aligned(2))) | 119 | static const struct usb_string_descriptor lang_descriptor = |
102 | lang_descriptor = | ||
103 | { | 120 | { |
104 | 4, | 121 | 4, |
105 | USB_DT_STRING, | 122 | USB_DT_STRING, |
106 | {0x0409} /* LANGID US English */ | 123 | {0x0409} /* LANGID US English */ |
107 | }; | 124 | }; |
108 | 125 | ||
109 | static struct hwstub_version_desc_t __attribute__((aligned(2))) | 126 | static struct hwstub_version_desc_t version_descriptor = |
110 | version_descriptor = | ||
111 | { | 127 | { |
112 | sizeof(struct hwstub_version_desc_t), | 128 | sizeof(struct hwstub_version_desc_t), |
113 | HWSTUB_DT_VERSION, | 129 | HWSTUB_DT_VERSION, |
@@ -116,8 +132,7 @@ static struct hwstub_version_desc_t __attribute__((aligned(2))) | |||
116 | HWSTUB_VERSION_REV | 132 | HWSTUB_VERSION_REV |
117 | }; | 133 | }; |
118 | 134 | ||
119 | static struct hwstub_layout_desc_t __attribute__((aligned(2))) | 135 | static struct hwstub_layout_desc_t layout_descriptor = |
120 | layout_descriptor = | ||
121 | { | 136 | { |
122 | sizeof(struct hwstub_layout_desc_t), | 137 | sizeof(struct hwstub_layout_desc_t), |
123 | HWSTUB_DT_LAYOUT, | 138 | HWSTUB_DT_LAYOUT, |
@@ -131,6 +146,7 @@ static const struct usb_string_descriptor* const usb_strings[USB_NUM_STRINGS] = | |||
131 | &lang_descriptor, | 146 | &lang_descriptor, |
132 | &usb_string_iManufacturer, | 147 | &usb_string_iManufacturer, |
133 | &usb_string_iProduct, | 148 | &usb_string_iProduct, |
149 | &usb_string_iInterface | ||
134 | }; | 150 | }; |
135 | 151 | ||
136 | uint8_t *usb_buffer = oc_bufferstart; | 152 | uint8_t *usb_buffer = oc_bufferstart; |
@@ -176,6 +192,10 @@ static void handle_std_dev_desc(struct usb_ctrlrequest *req) | |||
176 | } | 192 | } |
177 | size = sizeof(struct usb_config_descriptor); | 193 | size = sizeof(struct usb_config_descriptor); |
178 | 194 | ||
195 | /* interface desc */ | ||
196 | memcpy(usb_buffer + size, (void *)&interface_descriptor, | ||
197 | sizeof(interface_descriptor)); | ||
198 | size += sizeof(interface_descriptor); | ||
179 | /* hwstub version */ | 199 | /* hwstub version */ |
180 | memcpy(usb_buffer + size, (void *)&version_descriptor, | 200 | memcpy(usb_buffer + size, (void *)&version_descriptor, |
181 | sizeof(version_descriptor)); | 201 | sizeof(version_descriptor)); |
@@ -194,7 +214,8 @@ static void handle_std_dev_desc(struct usb_ctrlrequest *req) | |||
194 | target_get_config_desc(usb_buffer + size, &size); | 214 | target_get_config_desc(usb_buffer + size, &size); |
195 | /* fix config descriptor */ | 215 | /* fix config descriptor */ |
196 | config_descriptor.wTotalLength = size; | 216 | config_descriptor.wTotalLength = size; |
197 | memcpy(usb_buffer, (void *)&config_descriptor, sizeof(config_descriptor)); | 217 | memcpy(usb_buffer, (void *)&config_descriptor, |
218 | sizeof(config_descriptor)); | ||
198 | 219 | ||
199 | ptr = usb_buffer; | 220 | ptr = usb_buffer; |
200 | break; | 221 | break; |
@@ -208,22 +229,7 @@ static void handle_std_dev_desc(struct usb_ctrlrequest *req) | |||
208 | else | 229 | else |
209 | usb_drv_stall(EP_CONTROL, true, true); | 230 | usb_drv_stall(EP_CONTROL, true, true); |
210 | break; | 231 | break; |
211 | case HWSTUB_DT_VERSION: | ||
212 | ptr = &version_descriptor; | ||
213 | size = sizeof(version_descriptor); | ||
214 | break; | ||
215 | case HWSTUB_DT_LAYOUT: | ||
216 | ptr = &layout_descriptor; | ||
217 | size = sizeof(layout_descriptor); | ||
218 | break; | ||
219 | case HWSTUB_DT_TARGET: | ||
220 | ptr = &target_descriptor; | ||
221 | size = sizeof(target_descriptor); | ||
222 | break; | ||
223 | default: | 232 | default: |
224 | target_get_desc(req->wValue >> 8, &ptr); | ||
225 | if(ptr != 0) | ||
226 | size = ((struct usb_descriptor_header *)ptr)->bLength; | ||
227 | break; | 233 | break; |
228 | } | 234 | } |
229 | 235 | ||
@@ -271,12 +277,70 @@ static void handle_std_dev_req(struct usb_ctrlrequest *req) | |||
271 | } | 277 | } |
272 | } | 278 | } |
273 | 279 | ||
280 | static void handle_std_intf_desc(struct usb_ctrlrequest *req) | ||
281 | { | ||
282 | int size; | ||
283 | void* ptr = NULL; | ||
284 | |||
285 | switch(req->wValue >> 8) | ||
286 | { | ||
287 | case HWSTUB_DT_VERSION: | ||
288 | ptr = &version_descriptor; | ||
289 | size = sizeof(version_descriptor); | ||
290 | break; | ||
291 | case HWSTUB_DT_LAYOUT: | ||
292 | ptr = &layout_descriptor; | ||
293 | size = sizeof(layout_descriptor); | ||
294 | break; | ||
295 | case HWSTUB_DT_TARGET: | ||
296 | ptr = &target_descriptor; | ||
297 | size = sizeof(target_descriptor); | ||
298 | break; | ||
299 | default: | ||
300 | target_get_desc(req->wValue >> 8, &ptr); | ||
301 | if(ptr != 0) | ||
302 | size = ((struct usb_descriptor_header *)ptr)->bLength; | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | if(ptr) | ||
307 | { | ||
308 | int length = MIN(size, req->wLength); | ||
309 | |||
310 | if(ptr != usb_buffer) | ||
311 | memcpy(usb_buffer, ptr, length); | ||
312 | |||
313 | usb_drv_send(EP_CONTROL, usb_buffer, length); | ||
314 | usb_drv_recv(EP_CONTROL, NULL, 0); | ||
315 | } | ||
316 | else | ||
317 | usb_drv_stall(EP_CONTROL, true, true); | ||
318 | } | ||
319 | |||
320 | static void handle_std_intf_req(struct usb_ctrlrequest *req) | ||
321 | { | ||
322 | unsigned intf = req->wIndex & 0xff; | ||
323 | if(intf != USB_HWSTUB_INTF) | ||
324 | return usb_drv_stall(EP_CONTROL, true, true); | ||
325 | |||
326 | switch(req->bRequest) | ||
327 | { | ||
328 | case USB_REQ_GET_DESCRIPTOR: | ||
329 | handle_std_intf_desc(req); | ||
330 | break; | ||
331 | default: | ||
332 | usb_drv_stall(EP_CONTROL, true, true); | ||
333 | } | ||
334 | } | ||
335 | |||
274 | static void handle_std_req(struct usb_ctrlrequest *req) | 336 | static void handle_std_req(struct usb_ctrlrequest *req) |
275 | { | 337 | { |
276 | switch(req->bRequestType & USB_RECIP_MASK) | 338 | switch(req->bRequestType & USB_RECIP_MASK) |
277 | { | 339 | { |
278 | case USB_RECIP_DEVICE: | 340 | case USB_RECIP_DEVICE: |
279 | return handle_std_dev_req(req); | 341 | return handle_std_dev_req(req); |
342 | case USB_RECIP_INTERFACE: | ||
343 | return handle_std_intf_req(req); | ||
280 | default: | 344 | default: |
281 | usb_drv_stall(EP_CONTROL, true, true); | 345 | usb_drv_stall(EP_CONTROL, true, true); |
282 | } | 346 | } |
@@ -291,36 +355,56 @@ static void handle_get_log(struct usb_ctrlrequest *req) | |||
291 | enable_logf(true); | 355 | enable_logf(true); |
292 | } | 356 | } |
293 | 357 | ||
294 | static void handle_rw_mem(struct usb_ctrlrequest *req) | 358 | static void handle_read(struct usb_ctrlrequest *req) |
295 | { | 359 | { |
296 | uint32_t addr = req->wValue | req->wIndex << 16; | 360 | static uint32_t last_addr = 0; |
297 | uint16_t length = req->wLength; | 361 | static uint16_t last_id = 0xffff; |
298 | 362 | uint16_t id = req->wValue; | |
299 | if(req->bRequestType & USB_DIR_IN) | 363 | |
364 | if(req->bRequest == HWSTUB_READ) | ||
300 | { | 365 | { |
301 | memcpy(usb_buffer, (void *)addr, length); | 366 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, req->wLength); |
367 | if(size != sizeof(struct hwstub_read_req_t)) | ||
368 | return usb_drv_stall(EP_CONTROL, true, true); | ||
302 | asm volatile("nop" : : : "memory"); | 369 | asm volatile("nop" : : : "memory"); |
303 | usb_drv_send(EP_CONTROL, usb_buffer, length); | 370 | struct hwstub_read_req_t *read = (void *)usb_buffer; |
304 | usb_drv_recv(EP_CONTROL, NULL, 0); | 371 | last_addr = read->dAddress; |
372 | last_id = id; | ||
373 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
305 | } | 374 | } |
306 | else | 375 | else |
307 | { | 376 | { |
308 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, length); | 377 | if(id != last_id) |
378 | return usb_drv_stall(EP_CONTROL, true, true); | ||
379 | memcpy((void *)last_addr, usb_buffer, req->wLength); | ||
380 | memcpy(usb_buffer, (void *)last_addr, req->wLength); | ||
309 | asm volatile("nop" : : : "memory"); | 381 | asm volatile("nop" : : : "memory"); |
310 | if(size != length) | 382 | usb_drv_send(EP_CONTROL, usb_buffer, req->wLength); |
311 | usb_drv_stall(EP_CONTROL, true, true); | 383 | usb_drv_recv(EP_CONTROL, NULL, 0); |
312 | else | ||
313 | { | ||
314 | memcpy((void *)addr, usb_buffer, length); | ||
315 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
316 | } | ||
317 | } | 384 | } |
318 | } | 385 | }; |
319 | 386 | ||
320 | static void handle_call_jump(struct usb_ctrlrequest *req) | 387 | static void handle_write(struct usb_ctrlrequest *req) |
321 | { | 388 | { |
322 | uint32_t addr = req->wValue | req->wIndex << 16; | 389 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, req->wLength); |
390 | asm volatile("nop" : : : "memory"); | ||
391 | struct hwstub_write_req_t *write = (void *)usb_buffer; | ||
392 | int sz_hdr = sizeof(struct hwstub_write_req_t); | ||
393 | if(size < sz_hdr) | ||
394 | return usb_drv_stall(EP_CONTROL, true, true); | ||
395 | memcpy((void *)write->dAddress, usb_buffer + sz_hdr, req->wLength - sz_hdr); | ||
396 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
397 | } | ||
323 | 398 | ||
399 | static void handle_exec(struct usb_ctrlrequest *req) | ||
400 | { | ||
401 | int size = usb_drv_recv(EP_CONTROL, usb_buffer, req->wLength); | ||
402 | asm volatile("nop" : : : "memory"); | ||
403 | struct hwstub_exec_req_t *exec = (void *)usb_buffer; | ||
404 | if(size != sizeof(struct hwstub_exec_req_t)) | ||
405 | return usb_drv_stall(EP_CONTROL, true, true); | ||
406 | usb_drv_send(EP_CONTROL, NULL, 0); | ||
407 | #if 0 | ||
324 | if(req->bRequest == HWSTUB_CALL) | 408 | if(req->bRequest == HWSTUB_CALL) |
325 | ((void (*)(void))addr)(); | 409 | ((void (*)(void))addr)(); |
326 | else | 410 | else |
@@ -329,23 +413,26 @@ static void handle_call_jump(struct usb_ctrlrequest *req) | |||
329 | usb_drv_exit(); | 413 | usb_drv_exit(); |
330 | asm volatile("bx %0\n" : : "r" (addr) : "memory"); | 414 | asm volatile("bx %0\n" : : "r" (addr) : "memory"); |
331 | } | 415 | } |
416 | #endif | ||
332 | } | 417 | } |
333 | 418 | ||
334 | static void handle_class_dev_req(struct usb_ctrlrequest *req) | 419 | static void handle_class_intf_req(struct usb_ctrlrequest *req) |
335 | { | 420 | { |
421 | unsigned intf = req->wIndex & 0xff; | ||
422 | if(intf != USB_HWSTUB_INTF) | ||
423 | return usb_drv_stall(EP_CONTROL, true, true); | ||
424 | |||
336 | switch(req->bRequest) | 425 | switch(req->bRequest) |
337 | { | 426 | { |
338 | case HWSTUB_GET_LOG: | 427 | case HWSTUB_GET_LOG: |
339 | handle_get_log(req); | 428 | return handle_get_log(req); |
340 | break; | 429 | case HWSTUB_READ: |
341 | case HWSTUB_RW_MEM: | 430 | case HWSTUB_READ2: |
342 | handle_rw_mem(req); | 431 | return handle_read(req); |
343 | break; | 432 | case HWSTUB_WRITE: |
344 | case HWSTUB_CALL: | 433 | return handle_write(req); |
345 | case HWSTUB_JUMP: | 434 | case HWSTUB_EXEC: |
346 | handle_call_jump(req); | 435 | return handle_exec(req); |
347 | break; | ||
348 | break; | ||
349 | default: | 436 | default: |
350 | usb_drv_stall(EP_CONTROL, true, true); | 437 | usb_drv_stall(EP_CONTROL, true, true); |
351 | } | 438 | } |
@@ -355,8 +442,10 @@ static void handle_class_req(struct usb_ctrlrequest *req) | |||
355 | { | 442 | { |
356 | switch(req->bRequestType & USB_RECIP_MASK) | 443 | switch(req->bRequestType & USB_RECIP_MASK) |
357 | { | 444 | { |
445 | case USB_RECIP_INTERFACE: | ||
446 | return handle_class_intf_req(req); | ||
358 | case USB_RECIP_DEVICE: | 447 | case USB_RECIP_DEVICE: |
359 | return handle_class_dev_req(req); | 448 | //return handle_class_dev_req(req); |
360 | default: | 449 | default: |
361 | usb_drv_stall(EP_CONTROL, true, true); | 450 | usb_drv_stall(EP_CONTROL, true, true); |
362 | } | 451 | } |
diff --git a/utils/hwstub/tools/hwstub_shell.cpp b/utils/hwstub/tools/hwstub_shell.cpp index d0fcdfabc2..a10a1dad4e 100644 --- a/utils/hwstub/tools/hwstub_shell.cpp +++ b/utils/hwstub/tools/hwstub_shell.cpp | |||
@@ -754,15 +754,22 @@ int main(int argc, char **argv) | |||
754 | 754 | ||
755 | // look for device | 755 | // look for device |
756 | if(!g_quiet) | 756 | if(!g_quiet) |
757 | printf("Looking for device %#04x:%#04x...\n", HWSTUB_USB_VID, HWSTUB_USB_PID); | 757 | printf("Looking for hwstub device ...\n"); |
758 | 758 | // open first device | |
759 | libusb_device_handle *handle = libusb_open_device_with_vid_pid(ctx, | 759 | libusb_device **list; |
760 | HWSTUB_USB_VID, HWSTUB_USB_PID); | 760 | ssize_t cnt = hwstub_get_device_list(ctx, &list); |
761 | if(handle == NULL) | 761 | if(cnt <= 0) |
762 | { | 762 | { |
763 | printf("No device found\n"); | 763 | printf("No device found\n"); |
764 | return 1; | 764 | return 1; |
765 | } | 765 | } |
766 | libusb_device_handle *handle; | ||
767 | if(libusb_open(list[0], &handle) != 0) | ||
768 | { | ||
769 | printf("Cannot open device\n"); | ||
770 | return 1; | ||
771 | } | ||
772 | libusb_free_device_list(list, 1); | ||
766 | 773 | ||
767 | // admin stuff | 774 | // admin stuff |
768 | libusb_device *mydev = libusb_get_device(handle); | 775 | libusb_device *mydev = libusb_get_device(handle); |