source: mainline/uspace/drv/uhci/root_hub/port.c@ 7bd34e5

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

Add synchronization via fibril_semaphore

WARNING: fibril_semaphore BREAKS the deadlock detection system
used by fibril synch primitives

  • Property mode set to 100644
File size: 5.8 KB
Line 
1
2#include <atomic.h>
3#include <errno.h>
4#include <usb/devreq.h>
5#include <usb/usb.h>
6
7#include "debug.h"
8#include "uhci.h"
9#include "port.h"
10#include "port_status.h"
11#include "utils/hc_synchronizer.h"
12
13struct usb_match {
14 int id_score;
15 const char *id_string;
16};
17
18static int uhci_port_new_device(uhci_port_t *port);
19static int uhci_port_set_enabled(uhci_port_t *port, bool enabled);
20static usb_address_t assign_address_to_zero_device( device_t *hc );
21static int report_new_device(
22 device_t *hc, usb_address_t address, int hub_port, devman_handle_t *handle);
23
24/*----------------------------------------------------------------------------*/
25int uhci_port_check(void *port)
26{
27 uhci_port_t *port_instance = port;
28 assert(port_instance);
29
30 while (1) {
31 uhci_print_info("Port(%d) status address %p:\n",
32 port_instance->number, port_instance->address);
33
34 /* read register value */
35 port_status_t port_status;
36 port_status.raw_value = pio_read_16(port_instance->address);
37
38 /* debug print */
39 uhci_print_info("Port(%d) status %#x:\n",
40 port_instance->number, port_status.raw_value);
41 print_port_status( &port_status );
42
43 if (port_status.status.connect_change) {
44 if (port_status.status.connected) {
45 /* assign address and report new device */
46 uhci_port_new_device(port_instance);
47 } else {
48 /* TODO */
49 /* remove device here */
50 }
51 }
52 async_usleep(port_instance->wait_period_usec);
53 }
54 return EOK;
55}
56/*----------------------------------------------------------------------------*/
57static int uhci_port_new_device(uhci_port_t *port)
58{
59 assert(port);
60 assert(port->hc);
61
62 uhci_print_info("Adding new device on port %d.\n", port->number);
63
64 uhci_t *uhci_instance = (uhci_t*)(port->hc->driver_data);
65
66 /* get default address */
67 usb_address_keeping_reserve_default(&uhci_instance->address_manager);
68
69 /* enable port */
70 uhci_port_set_enabled( port, true );
71
72 /* assign address to device */
73 usb_address_t address = assign_address_to_zero_device(port->hc);
74
75 /* release default address */
76 usb_address_keeping_release_default(&uhci_instance->address_manager);
77
78 if (address <= 0) { /* address assigning went wrong */
79 uhci_port_set_enabled(port, false);
80 uhci_print_error("Failed to assign address to the device");
81 return ENOMEM;
82 }
83
84 /* report to devman */
85 devman_handle_t child = 0;
86 report_new_device(port->hc, address, port->number, &child);
87
88 /* bind address */
89 usb_address_keeping_devman_bind(&uhci_instance->address_manager,
90 address, child);
91
92 return EOK;
93}
94/*----------------------------------------------------------------------------*/
95static int uhci_port_set_enabled(uhci_port_t *port, bool enabled)
96{
97 assert(port);
98
99 /* read register value */
100 port_status_t port_status;
101 port_status.raw_value = pio_read_16( port->address );
102
103 /* enable port: register write */
104 port_status.status.enabled_change = 0;
105 port_status.status.enabled = (bool)enabled;
106 pio_write_16( port->address, port_status.raw_value );
107
108 uhci_print_info( "Enabled port %d.\n", port->number );
109 return EOK;
110}
111/*----------------------------------------------------------------------------*/
112static int report_new_device(
113 device_t *hc, usb_address_t address, int hub_port, devman_handle_t *handle)
114{
115 assert( hc );
116 assert( address > 0 );
117 assert( address <= USB11_ADDRESS_MAX );
118
119 device_t *child = create_device();
120 if (child == NULL)
121 { return ENOMEM; }
122
123 char *name;
124 int ret;
125
126 ret = asprintf( &name, "usbdevice on hc%p/%d/%#x", hc, hub_port, address );
127 if (ret < 0) {
128 uhci_print_error( "Failed to create device name.\n" );
129 delete_device( child );
130 return ret;
131 }
132 child->name = name;
133
134 /* TODO get and parse device descriptor */
135 const int vendor = 1;
136 const int product = 1;
137 const char* release = "unknown";
138 const char* class = "unknown";
139
140 /* create match ids TODO fix class printf*/
141 static const struct usb_match usb_matches[] = {
142 { 100, "usb&vendor=%d&product=%d&release=%s" },
143 { 90, "usb&vendor=%d&product=%d" },
144 { 50, "usb&class=%d" },
145 { 1, "usb&fallback" }
146 };
147
148 unsigned i = 0;
149 for (;i < sizeof( usb_matches )/ sizeof( struct usb_match ); ++i ) {
150 char *match_str;
151 const int ret = asprintf(
152 &match_str, usb_matches[i].id_string, vendor, product, release, class );
153 if (ret < 0 ) {
154 uhci_print_error( "Failed to create matchid string.\n" );
155 delete_device( child );
156 return ret;
157 }
158 uhci_print_verbose( "Adding match id rule:%s\n", match_str );
159
160 match_id_t *id = create_match_id();
161 if (id == NULL) {
162 uhci_print_error( "Failed to create matchid.\n" );
163 delete_device( child );
164 free( match_str );
165 return ENOMEM;
166 }
167 id->id = match_str;
168 id->score = usb_matches[i].id_score;
169 add_match_id( &child->match_ids, id );
170
171 uhci_print_info( "Added match id, score: %d, string %s\n",
172 id->score, id->id );
173 }
174
175 ret = child_device_register( child, hc );
176 if (ret < 0) {
177 uhci_print_error( "Failed to create device name.\n" );
178 delete_device( child );
179 return ret;
180 }
181
182 if (handle != NULL)
183 { *handle = child->handle; }
184
185 return EOK;
186}
187
188static usb_address_t assign_address_to_zero_device( device_t *hc )
189{
190 assert( hc );
191 assert( hc->driver_data );
192
193 uhci_t *uhci_instance = (uhci_t*)hc->driver_data;
194 /* get new address */
195 const usb_address_t usb_address =
196 usb_address_keeping_request(&uhci_instance->address_manager);
197
198 if (usb_address <= 0) {
199 return usb_address;
200 }
201
202 /* assign new address */
203 usb_target_t new_device = { USB_ADDRESS_DEFAULT, 0 };
204 usb_device_request_setup_packet_t data =
205 {
206 .request_type = 0,
207 .request = USB_DEVREQ_SET_ADDRESS,
208 { .value = usb_address },
209 .index = 0,
210 .length = 0
211 };
212
213 sync_value_t value;
214 sync_init(&value);
215
216 uhci_setup(
217 hc, new_device, USB_TRANSFER_CONTROL, &data, sizeof(data),
218 sync_out_callback, (void*)&value );
219 uhci_print_verbose("address assignment sent, waiting to complete.\n");
220
221 sync_wait_for(&value);
222
223 uhci_print_info( "Assigned address %#x.\n", usb_address );
224
225 return usb_address;
226}
Note: See TracBrowser for help on using the repository browser.