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

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

fix: enable port AFTER reserving default address

  • Property mode set to 100644
File size: 5.2 KB
Line 
1#include <ddi.h>
2#include <async.h>
3#include <errno.h>
4#include <stdint.h>
5#include <stdio.h>
6
7#include <usb/debug.h>
8
9#include "../name.h"
10#include "../uhci.h"
11#include "port_status.h"
12#include "root_hub.h"
13
14#define ROOT_HUB_WAIT_USEC 10000000 /* 10 second */
15
16static int uhci_root_hub_check_ports( void *hc );
17static int uhci_root_hub_new_device( device_t *hc, unsigned port );
18static usb_address_t uhci_root_hub_assign_address( device_t *hc );
19static int uhci_root_hub_report_new_device(
20 device_t *hc, usb_address_t address, int port, devman_handle_t *handle );
21
22/*----------------------------------------------------------------------------*/
23int uhci_root_hub_init( uhci_root_hub_t *hub, device_t *hc, void *addr )
24{
25 assert( hub );
26
27 /* allow access to root hub registers */
28 port_regs_t *regs;
29 const int ret = pio_enable( addr, sizeof(port_regs_t), (void**)&regs);
30 if (ret < 0) {
31 printf( NAME": Failed to gain access to port registers at %p\n", regs );
32 return ret;
33 }
34 hub->registers = regs;
35
36 /* add fibril for periodic checks */
37 hub->checker = fibril_create( uhci_root_hub_check_ports, hc );
38 if (hub->checker == 0) {
39 printf( NAME": failed to launch root hub fibril." );
40 return ENOMEM;
41 }
42 fibril_add_ready( hub->checker );
43
44 return EOK;
45}
46/*----------------------------------------------------------------------------*/
47int uhci_root_hub_fini( uhci_root_hub_t* instance )
48{
49 assert( instance );
50 // TODO:
51 //destroy fibril here
52 //disable access to registers
53 return EOK;
54}
55/*----------------------------------------------------------------------------*/
56static int uhci_root_hub_check_ports( void * device )
57{
58 assert( device );
59 uhci_t *uhci_instance = ((device_t*)device)->driver_data;
60
61 while (1) {
62 int i = 0;
63 for (; i < UHCI_ROOT_HUB_PORT_COUNT; ++i) {
64 volatile uint16_t * address =
65 &(uhci_instance->root_hub.registers->portsc[i]);
66
67 usb_dprintf( NAME, 1, "Port(%d) status address %p:\n", i, address );
68
69 /* read register value */
70 port_status_t port_status;
71 port_status.raw_value = pio_read_16( address );
72
73 /* debug print */
74 usb_dprintf( NAME, 1, "Port(%d) status 0x%x:\n", i, port_status.raw_value );
75 print_port_status( &port_status );
76
77 if (port_status.status.connect_change) {
78 if (port_status.status.connected) {
79 /* assign address and report new device */
80 uhci_root_hub_new_device( (device_t*)device, i );
81 } else {
82 /* TODO */
83 /* remove device here */
84 }
85 }
86 }
87 async_usleep( ROOT_HUB_WAIT_USEC );
88 }
89 return ENOTSUP;
90}
91/*----------------------------------------------------------------------------*/
92int uhci_root_hub_new_device( device_t *hc, unsigned port )
93{
94 assert( hc );
95 assert( hc->driver_data );
96 assert( port < UHCI_ROOT_HUB_PORT_COUNT );
97
98 usb_dprintf( NAME, 2, "Adding new device on port %d.\n", port );
99
100 uhci_t *uhci_instance = (uhci_t*)hc->driver_data;
101
102 /* get default address */
103 usb_address_keeping_reserve_default( &uhci_instance->address_manager );
104
105 /* enable port */
106 {
107 volatile uint16_t * address =
108 &(uhci_instance->root_hub.registers->portsc[port]);
109
110 /* read register value */
111 port_status_t port_status;
112 port_status.raw_value = pio_read_16( address );
113
114 /* enable port: register write */
115 port_status.status.enabled = 1;
116 pio_write_16( address, port_status.raw_value );
117
118 usb_dprintf( NAME, 2, "Enabled port %d.\n", port );
119 }
120
121 /* assign address to device */
122 usb_address_t address =
123 uhci_root_hub_assign_address( hc );
124 if (address <= 0) {
125 printf( NAME": Failed to assign address to the device" );
126 return ENOMEM;
127 }
128 /* release default address */
129 usb_address_keeping_release_default( &uhci_instance->address_manager );
130
131 /* report to devman */
132 devman_handle_t child = 0;
133 uhci_root_hub_report_new_device( hc, address, port, &child );
134
135 /* bind address */
136 usb_address_keeping_devman_bind( &uhci_instance->address_manager,
137 address, child );
138
139
140 return EOK;
141}
142/*----------------------------------------------------------------------------*/
143static usb_address_t uhci_root_hub_assign_address( device_t *hc )
144{
145 assert( hc );
146 assert( hc->driver_data );
147
148 uhci_t *uhci_instance = (uhci_t*)hc->driver_data;
149 /* get new address */
150 const usb_address_t usb_address = usb_address_keeping_request(
151 &uhci_instance->address_manager );
152
153 /* assign new address */
154 /* TODO send new address*/
155 usb_dprintf( NAME, 3, "Assigned address 0x%x.\n", usb_address );
156
157 return usb_address;
158}
159/*----------------------------------------------------------------------------*/
160static int uhci_root_hub_report_new_device(
161 device_t *hc, usb_address_t address, int hub_port, devman_handle_t *handle )
162{
163 assert( hc );
164 assert( address > 0 );
165 assert( address <= USB11_ADDRESS_MAX );
166
167 int ret;
168 device_t *child = create_device();
169 if (child == NULL)
170 { return ENOMEM; }
171 char *name;
172
173 ret = asprintf( &name, "usbdevice on hc%p/%d/0x%x", hc, hub_port, address );
174 if (ret < 0) {
175 usb_dprintf( NAME, 4, "Failed to create device name.\n" );
176 delete_device( child );
177 return ret;
178 }
179 child->name = name;
180
181 /* TODO create match ids */
182
183 ret = child_device_register( child, hc );
184 if (ret < 0) {
185 usb_dprintf( NAME, 4, "Failed to create device name.\n" );
186 delete_device( child );
187 return ret;
188 }
189
190 if (handle != NULL)
191 { *handle = child->handle; }
192
193 return EOK;
194}
Note: See TracBrowser for help on using the repository browser.