source: mainline/uspace/drv/uhci/root_hub/root_hub.c@ bf5a3be

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bf5a3be was bf5a3be, checked in by Jan Vesely <jano.vesely@…>, 15 years ago

added creation of device match ids

new debug output system
TODO set address

get descriptor/parse descriptor

device removal

  • Property mode set to 100644
File size: 7.0 KB
Line 
1#include <bool.h>
2#include <ddi.h>
3#include <devman.h>
4#include <async.h>
5#include <errno.h>
6#include <stdint.h>
7#include <stdio.h>
8
9#include "../name.h"
10#include "../uhci.h"
11#include "../debug.h"
12#include "port_status.h"
13#include "root_hub.h"
14
15#define ROOT_HUB_WAIT_USEC 10000000 /* 10 second */
16
17struct usb_match {
18 int id_score;
19 const char *id_string;
20};
21
22static int uhci_root_hub_check_ports( void *hc );
23static int uhci_root_hub_new_device( device_t *hc, unsigned port );
24static usb_address_t uhci_root_hub_assign_address( device_t *hc );
25static int uhci_root_hub_report_new_device(
26 device_t *hc, usb_address_t address, int port, devman_handle_t *handle );
27static int uhci_root_hub_port_set_enabled(
28 uhci_root_hub_t *instance, unsigned port, bool enabled );
29
30/*----------------------------------------------------------------------------*/
31int uhci_root_hub_init( uhci_root_hub_t *hub, device_t *hc, void *addr )
32{
33 assert( hub );
34
35 /* allow access to root hub registers */
36 port_regs_t *regs;
37 const int ret = pio_enable( addr, sizeof(port_regs_t), (void**)&regs);
38 if (ret < 0) {
39 uhci_print_error(
40 ": Failed to gain access to port registers at %p\n", regs );
41 return ret;
42 }
43 hub->registers = regs;
44
45 /* add fibril for periodic checks */
46 hub->checker = fibril_create( uhci_root_hub_check_ports, hc );
47 if (hub->checker == 0) {
48 uhci_print_error( ": failed to launch root hub fibril." );
49 return ENOMEM;
50 }
51 fibril_add_ready( hub->checker );
52
53 return EOK;
54}
55/*----------------------------------------------------------------------------*/
56int uhci_root_hub_fini( uhci_root_hub_t* instance )
57{
58 assert( instance );
59 // TODO:
60 //destroy fibril here
61 //disable access to registers
62 return EOK;
63}
64/*----------------------------------------------------------------------------*/
65static int uhci_root_hub_port_set_enabled( uhci_root_hub_t *instance,
66 unsigned port, bool enabled )
67{
68 assert( instance );
69 assert( instance->registers );
70 assert( port < UHCI_ROOT_HUB_PORT_COUNT );
71
72 volatile uint16_t * address =
73 &(instance->registers->portsc[port]);
74
75 /* read register value */
76 port_status_t port_status;
77 port_status.raw_value = pio_read_16( address );
78
79 /* enable port: register write */
80 port_status.status.enabled_change = 0;
81 port_status.status.enabled = (bool)enabled;
82 pio_write_16( address, port_status.raw_value );
83
84 uhci_print_info( "Enabled port %d.\n", port );
85 return EOK;
86}
87/*----------------------------------------------------------------------------*/
88static int uhci_root_hub_check_ports( void * device )
89{
90 assert( device );
91 uhci_t *uhci_instance = ((device_t*)device)->driver_data;
92
93 while (1) {
94 int i = 0;
95 for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
96 volatile uint16_t * address =
97 &(uhci_instance->root_hub.registers->portsc[i]);
98
99 uhci_print_info( "Port(%d) status address %p:\n", i, address );
100
101 /* read register value */
102 port_status_t port_status;
103 port_status.raw_value = pio_read_16( address );
104
105 /* debug print */
106 uhci_print_info( "Port(%d) status %#x:\n", i, port_status.raw_value );
107 print_port_status( &port_status );
108
109 if (port_status.status.connect_change) {
110 if (port_status.status.connected) {
111 /* assign address and report new device */
112 uhci_root_hub_new_device( (device_t*)device, i );
113 } else {
114 /* TODO */
115 /* remove device here */
116 }
117 }
118 }
119 async_usleep( ROOT_HUB_WAIT_USEC );
120 }
121 return ENOTSUP;
122}
123/*----------------------------------------------------------------------------*/
124int uhci_root_hub_new_device( device_t *hc, unsigned port )
125{
126 assert( hc );
127 assert( hc->driver_data );
128 assert( port < UHCI_ROOT_HUB_PORT_COUNT );
129
130 uhci_print_info( "Adding new device on port %d.\n", port );
131
132 uhci_t *uhci_instance = (uhci_t*)hc->driver_data;
133
134 /* get default address */
135 usb_address_keeping_reserve_default( &uhci_instance->address_manager );
136
137 /* enable port */
138 uhci_root_hub_port_set_enabled( &uhci_instance->root_hub, port, true );
139
140 /* assign address to device */
141 usb_address_t address = uhci_root_hub_assign_address( hc );
142
143 /* release default address */
144 usb_address_keeping_release_default( &uhci_instance->address_manager );
145
146 if (address <= 0) { /* address assigning went wrong */
147 uhci_root_hub_port_set_enabled( &uhci_instance->root_hub, port, false );
148 uhci_print_error( "Failed to assign address to the device" );
149 return ENOMEM;
150 }
151
152 /* report to devman */
153 devman_handle_t child = 0;
154 uhci_root_hub_report_new_device( hc, address, port, &child );
155
156 /* bind address */
157 usb_address_keeping_devman_bind( &uhci_instance->address_manager,
158 address, child );
159
160
161 return EOK;
162}
163/*----------------------------------------------------------------------------*/
164static usb_address_t uhci_root_hub_assign_address( device_t *hc )
165{
166 assert( hc );
167 assert( hc->driver_data );
168
169 uhci_t *uhci_instance = (uhci_t*)hc->driver_data;
170 /* get new address */
171 const usb_address_t usb_address =
172 usb_address_keeping_request( &uhci_instance->address_manager );
173
174 /* assign new address */
175 /* TODO send new address to the device*/
176 uhci_print_error( "Assigned address %#x.\n", usb_address );
177
178 return usb_address;
179}
180/*----------------------------------------------------------------------------*/
181static int uhci_root_hub_report_new_device(
182 device_t *hc, usb_address_t address, int hub_port, devman_handle_t *handle )
183{
184 assert( hc );
185 assert( address > 0 );
186 assert( address <= USB11_ADDRESS_MAX );
187
188 device_t *child = create_device();
189 if (child == NULL)
190 { return ENOMEM; }
191
192 char *name;
193 int ret;
194
195 ret = asprintf( &name, "usbdevice on hc%p/%d/%#x", hc, hub_port, address );
196 if (ret < 0) {
197 uhci_print_error( "Failed to create device name.\n" );
198 delete_device( child );
199 return ret;
200 }
201 child->name = name;
202
203 /* TODO get and parse device descriptor */
204 const int vendor = 1;
205 const int product = 1;
206 const char* release = "unknown";
207 const char* class = "unknown";
208
209 /* create match ids TODO fix class printf*/
210 static const struct usb_match usb_matches[] = {
211 { 100, "usb&vendor=%d&product=%d&release=%s" },
212 { 90, "usb&vendor=%d&product=%d" },
213 { 50, "usb&class=%d" },
214 { 1, "usb&fallback" }
215 };
216
217 unsigned i = 0;
218 for (;i < sizeof( usb_matches )/ sizeof( struct usb_match ); ++i ) {
219 char *match_str;
220 const int ret = asprintf(
221 &match_str, usb_matches[i].id_string, vendor, product, release, class );
222 if (ret < 0 ) {
223 uhci_print_error( "Failed to create matchid string.\n" );
224 delete_device( child );
225 return ret;
226 }
227 uhci_print_info( "Adding match id rule:%s\n", match_str );
228
229 match_id_t *id = create_match_id();
230 if (id == NULL) {
231 uhci_print_error( "Failed to create matchid.\n" );
232 delete_device( child );
233 free( match_str );
234 return ENOMEM;
235 }
236 id->id = match_str;
237 id->score = usb_matches[i].id_score;
238 add_match_id( &child->match_ids, id );
239
240 uhci_print_info( "Added match id, score: %d, string %s\n",
241 id->score, id->id );
242 }
243
244 ret = child_device_register( child, hc );
245 if (ret < 0) {
246 uhci_print_error( "Failed to create device name.\n" );
247 delete_device( child );
248 return ret;
249 }
250
251 if (handle != NULL)
252 { *handle = child->handle; }
253
254 return EOK;
255}
Note: See TracBrowser for help on using the repository browser.