source: mainline/uspace/drv/usbhub/utils.c@ 7964475

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7964475 was b5ec347, checked in by Matus Dekanek <smekideki@…>, 15 years ago

various convenience definitions
removing of usb_hcd_hub_info_t from public declarations
usb-side implementation of adding a new device (assign addressand enable port)

  • Property mode set to 100644
File size: 11.8 KB
RevLine 
[dac43be]1/*
2 * Copyright (c) 2010 Matus Dekanek
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusb usb
30 * @{
31 */
32/** @file
33 * @brief Hub driver.
34 */
[4317827]35#include <driver.h>
[dac43be]36#include <usb/devreq.h>
37#include <usbhc_iface.h>
[4317827]38#include <usb/usbdrv.h>
[dac43be]39#include <usb/descriptor.h>
40#include <driver.h>
41#include <bool.h>
42#include <errno.h>
43#include <usb/classes/hub.h>
[4317827]44#include "usbhub.h"
[b5ec347]45#include "usbhub_private.h"
46#include "port_status.h"
47#include <usb/devreq.h>
[dac43be]48
49static void check_hub_changes(void);
50
51size_t USB_HUB_MAX_DESCRIPTOR_SIZE = 71;
52
53//*********************************************
54//
55// various utils
56//
57//*********************************************
58
[b5ec347]59//hub descriptor utils
[dac43be]60void * usb_serialize_hub_descriptor(usb_hub_descriptor_t * descriptor) {
61 //base size
62 size_t size = 7;
63 //variable size according to port count
64 size_t var_size = descriptor->ports_count / 8 + ((descriptor->ports_count % 8 > 0) ? 1 : 0);
65 size += 2 * var_size;
66 uint8_t * result = (uint8_t*) malloc(size);
67 //size
68 result[0] = size;
69 //descriptor type
70 result[1] = USB_DESCTYPE_HUB;
71 result[2] = descriptor->ports_count;
72 /// @fixme handling of endianness??
73 result[3] = descriptor->hub_characteristics / 256;
74 result[4] = descriptor->hub_characteristics % 256;
75 result[5] = descriptor->pwr_on_2_good_time;
76 result[6] = descriptor->current_requirement;
77
78 size_t i;
79 for (i = 0; i < var_size; ++i) {
80 result[7 + i] = descriptor->devices_removable[i];
81 }
82 for (i = 0; i < var_size; ++i) {
83 result[7 + var_size + i] = 255;
84 }
85 return result;
86}
87
88usb_hub_descriptor_t * usb_deserialize_hub_desriptor(void * serialized_descriptor) {
89 uint8_t * sdescriptor = (uint8_t*) serialized_descriptor;
90 if (sdescriptor[1] != USB_DESCTYPE_HUB) return NULL;
[b5ec347]91 usb_hub_descriptor_t * result = usb_new(usb_hub_descriptor_t);
[dac43be]92 //uint8_t size = sdescriptor[0];
93 result->ports_count = sdescriptor[2];
94 /// @fixme handling of endianness??
95 result->hub_characteristics = sdescriptor[4] + 256 * sdescriptor[3];
96 result->pwr_on_2_good_time = sdescriptor[5];
97 result->current_requirement = sdescriptor[6];
98 size_t var_size = result->ports_count / 8 + ((result->ports_count % 8 > 0) ? 1 : 0);
99 result->devices_removable = (uint8_t*) malloc(var_size);
100
101 size_t i;
102 for (i = 0; i < var_size; ++i) {
103 result->devices_removable[i] = sdescriptor[7 + i];
104 }
105 return result;
106}
107
[b5ec347]108//control transactions
109int usb_drv_sync_control_read(
110 int phone, usb_target_t target,
111 usb_device_request_setup_packet_t * request,
112 void * rcvd_buffer, size_t rcvd_size, size_t * actual_size
113){
114 usb_handle_t handle;
115 int opResult;
116 //setup
117 opResult = usb_drv_async_control_read_setup(phone, target,
118 request, sizeof(usb_device_request_setup_packet_t),
119 &handle);
120 if(opResult!=EOK){
121 return opResult;
122 }
123 opResult = usb_drv_async_wait_for(handle);
124 if(opResult!=EOK){
125 return opResult;
126 }
127 //read
128 opResult = usb_drv_async_control_read_data(phone, target,
129 rcvd_buffer, rcvd_size, actual_size,
130 &handle);
131 if(opResult!=EOK){
132 return opResult;
133 }
134 opResult = usb_drv_async_wait_for(handle);
135 if(opResult!=EOK){
136 return opResult;
137 }
138 //finalize
139 opResult = usb_drv_async_control_read_status(phone, target,
140 &handle);
141 if(opResult!=EOK){
142 return opResult;
143 }
144 opResult = usb_drv_async_wait_for(handle);
145 if(opResult!=EOK){
146 return opResult;
147 }
148 return EOK;
149}
150
151
152int usb_drv_sync_control_write(
153 int phone, usb_target_t target,
154 usb_device_request_setup_packet_t * request,
155 void * sent_buffer, size_t sent_size
156){
157 usb_handle_t handle;
158 int opResult;
159 //setup
160 opResult = usb_drv_async_control_write_setup(phone, target,
161 request, sizeof(usb_device_request_setup_packet_t),
162 &handle);
163 if(opResult!=EOK){
164 return opResult;
165 }
166 opResult = usb_drv_async_wait_for(handle);
167 if(opResult!=EOK){
168 return opResult;
169 }
170 //write
171 opResult = usb_drv_async_control_write_data(phone, target,
172 sent_buffer, sent_size,
173 &handle);
174 if(opResult!=EOK){
175 return opResult;
176 }
177 opResult = usb_drv_async_wait_for(handle);
178 if(opResult!=EOK){
179 return opResult;
180 }
181 //finalize
182 opResult = usb_drv_async_control_write_status(phone, target,
183 &handle);
184 if(opResult!=EOK){
185 return opResult;
186 }
187 opResult = usb_drv_async_wait_for(handle);
188 if(opResult!=EOK){
189 return opResult;
190 }
191 return EOK;
192}
193
194//list implementation
195
196usb_general_list_t * usb_lst_create(void){
197 usb_general_list_t* result = usb_new(usb_general_list_t);
198 usb_lst_init(result);
199 return result;
200}
201
202void usb_lst_init(usb_general_list_t * lst){
203 lst->prev = lst;
204 lst->next = lst;
205 lst->data = NULL;
206}
207
208void usb_lst_prepend(usb_general_list_t* item, void* data){
209 usb_general_list_t* appended = usb_new(usb_general_list_t);
210 appended->data=data;
211 appended->next=item;
212 appended->prev=item->prev;
213 item->prev->next = appended;
214 item->prev = appended;
215}
216
217void usb_lst_append(usb_general_list_t* item, void* data){
218 usb_general_list_t* appended =usb_new(usb_general_list_t);
219 appended->data=data;
220 appended->next=item->next;
221 appended->prev=item;
222 item->next->prev = appended;
223 item->next = appended;
224}
225
226
227void usb_lst_remove(usb_general_list_t* item){
228 item->next->prev = item->prev;
229 item->prev->next = item->next;
230}
231
232
[dac43be]233
234//*********************************************
235//
236// hub driver code
237//
238//*********************************************
239
[b5ec347]240usb_hub_info_t * usb_create_hub_info(device_t * device) {
241 usb_hub_info_t* result = usb_new(usb_hub_info_t);
242 //result->device = device;
243 result->port_count = -1;
244
245 //get hc connection
246 int hc = usb_drv_hc_connect(NULL, 0);
247 printf("[usb_hub] phone to hc = %d\n",hc);
248 if (hc < 0) {
249 return result;
250 }
251 //get some hub info
252
253 usb_address_t addr = usb_drv_get_my_address(hc,device);
254 printf("[usb_hub] addres of newly created hub = %d\n",addr);
255 /*if(addr<0){
256 //return result;
257
258 }*/
259 result->device = usb_new(usb_hcd_attached_device_info_t);
260 result->device->address=addr;
261 //hub configuration?
262 printf("[usb_hub] hub info created\n");
[dac43be]263
[b5ec347]264
265
[dac43be]266 return result;
267}
268
269/** Callback when new hub device is detected.
270 *
271 * @param dev New device.
272 * @return Error code.
273 */
274int usb_add_hub_device(device_t *dev) {
[4317827]275 printf(NAME ": add_hub_device(handle=%d)\n", (int) dev->handle);
[b5ec347]276 printf("[usb_hub] hub device\n");
[dac43be]277
278 /*
279 * We are some (probably deeply nested) hub.
280 * Thus, assign our own operations and explore already
281 * connected devices.
282 */
283
284 //create the hub structure
[b5ec347]285 usb_hub_info_t * hub_info = usb_create_hub_info(dev);
286 usb_lst_append(&usb_hub_list, hub_info);
287 printf("[usb_hub] hub info added to list\n");
288 //(void)hub_info;
289 check_hub_changes();
290 printf("[usb_hub] hub dev added\n");
291 //test port status type...
[dac43be]292
293 return EOK;
294 //return ENOTSUP;
295}
296
297
[b5ec347]298
299
[dac43be]300/** Check changes on all known hubs.
301 */
302static void check_hub_changes(void) {
303 /*
[4317827]304 * Iterate through all hubs.
[dac43be]305 */
[b5ec347]306 usb_general_list_t * lst_item;
307 for (lst_item = usb_hub_list.next;
308 lst_item != &usb_hub_list;
309 lst_item = lst_item->next) {
310 printf("[usb_hub] checking hub changes\n");
[4317827]311 /*
312 * Check status change pipe of this hub.
313 */
[b5ec347]314
[4317827]315 usb_target_t target = {
316 .address = 5,
317 .endpoint = 1
318 };
[b5ec347]319 /// \TODO uncomment once it works correctly
320 //target.address = usb_create_hub_info(lst_item)->device->address;
[4317827]321
322 size_t port_count = 7;
323
[dac43be]324 /*
[4317827]325 * Connect to respective HC.
[dac43be]326 */
[b5ec347]327 /// \FIXME this is incorrect code: here
328 /// must be used particular device instead of NULL
[4317827]329 int hc = usb_drv_hc_connect(NULL, 0);
330 if (hc < 0) {
331 continue;
[dac43be]332 }
[4317827]333
334 // FIXME: count properly
335 size_t byte_length = (port_count / 8) + 1;
336
337 void *change_bitmap = malloc(byte_length);
338 size_t actual_size;
339 usb_handle_t handle;
340
341 /*
342 * Send the request.
343 */
[b5ec347]344 int opResult = usb_drv_async_interrupt_in(hc, target,
[4317827]345 change_bitmap, byte_length, &actual_size,
346 &handle);
347
348 usb_drv_async_wait_for(handle);
349
[b5ec347]350 if(opResult!=EOK){
351 printf("[usb_hub] something went wrong while getting status of hub\n");
352 continue;
353 }
354 unsigned int port;
355 for(port=0;port<port_count;++port){
356 bool interrupt = (((uint8_t*)change_bitmap)[port/8]>>(port%8))%2;
357 if(interrupt){
358 printf("[usb_hub] interrupt at port %d\n",port);
359 //determine type of change
360 usb_port_status_t status;
361 size_t rcvd_size;
362 usb_device_request_setup_packet_t request;
363 usb_hub_set_port_status_request(&request,port);
364
365 opResult = usb_drv_sync_control_read(
366 hc, target,
367 &request,
368 &status, 4, &rcvd_size
369 );
370 if(opResult!=EOK){
371 continue;
372 }
373 if(rcvd_size!=sizeof(usb_port_status_t)){
374 continue;
375 }
376
377 if(usb_port_connect_change(&status)){
378 printf("[usb_hub] some connectionchanged\n");
379 usb_drv_reserve_default_address(hc);
380 //enable port
381 usb_hub_set_enable_port_request(&request,port);
382 opResult = usb_drv_sync_control_write(
383 hc, target,
384 &request,
385 NULL, 0
386 );
387 if(opResult!=EOK){
388 continue;
389 }
390 //set address
391 usb_address_t new_device_address =
392 usb_drv_request_address(hc);
393 usb_hub_set_set_address_request
394 (&request,new_device_address);
395 opResult = usb_drv_sync_control_write(
396 hc, target,
397 &request,
398 NULL, 0
399 );
400 //some other work with drivers
401 /// \TODO do the work with drivers
402
403
404 usb_drv_release_default_address(hc);
405 }else{
406 printf("[usb_hub] no supported event occured\n");
407 }
408 /// \TODO handle other changes
409 /// \TODO debug log for various situations
410
411
412
413 /*
414 //configure device
415 usb_drv_reserve_default_address(hc);
416
417 usb_address_t new_device_address = usb_drv_request_address(hc);
418
419
420 usb_drv_release_default_address(hc);
421 * */
422 }
423 }
424
425
[4317827]426 /*
427 * TODO: handle the changes.
428 */
429
[9ca0013]430 /*
431 * WARNING: sample code, will not work out of the box.
432 * And does not contain code for checking for errors.
433 */
434#if 0
435 /*
436 * Before opening the port, we must acquire the default
437 * address.
438 */
439 usb_drv_reserve_default_address(hc);
440
441 usb_address_t new_device_address = usb_drv_request_address(hc);
442
443 // TODO: open the port
444
445 // TODO: send request for setting address to new_device_address
446
447 /*
448 * Once new address is set, we can release the default
449 * address.
450 */
451 usb_drv_release_default_address(hc);
452
453 /*
454 * Obtain descriptors and create match ids for devman.
455 */
456
457 // TODO: get device descriptors
458
459 // TODO: create match ids
460
461 // TODO: add child device
462
463 // child_device_register sets the device handle
464 // TODO: store it here
465 devman_handle_t new_device_handle = 0;
466
467 /*
468 * Inform the HC that the new device has devman handle
469 * assigned.
470 */
471 usb_drv_bind_address(hc, new_device_address, new_device_handle);
472
473 /*
474 * That's all.
475 */
476#endif
477
[4317827]478
479 /*
480 * Hang-up the HC-connected phone.
481 */
482 ipc_hangup(hc);
[dac43be]483 }
484}
485
486/**
487 * @}
488 */
Note: See TracBrowser for help on using the repository browser.