source: mainline/uspace/lib/usb/src/host/usb_endpoint_manager.c@ 6ce42e85

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

Set data member

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights eps.
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#include <bool.h>
30#include <assert.h>
31#include <errno.h>
32
33#include <usb/host/usb_endpoint_manager.h>
34
35#define BUCKET_COUNT 7
36
37typedef struct {
38 usb_address_t address;
39 usb_endpoint_t endpoint;
40 usb_direction_t direction;
41} __attribute__((aligned (sizeof(unsigned long)))) id_t;
42#define MAX_KEYS (sizeof(id_t) / sizeof(unsigned long))
43typedef struct {
44 union {
45 id_t id;
46 unsigned long key[MAX_KEYS];
47 };
48 link_t link;
49 size_t bw;
50 void *data;
51 void (*data_remove_callback)(void* data);
52} ep_t;
53/*----------------------------------------------------------------------------*/
54static hash_index_t ep_hash(unsigned long key[])
55{
56 hash_index_t hash = 0;
57 unsigned i = 0;
58 for (;i < MAX_KEYS; ++i) {
59 hash ^= key[i];
60 }
61 hash %= BUCKET_COUNT;
62 return hash;
63}
64/*----------------------------------------------------------------------------*/
65static int ep_compare(unsigned long key[], hash_count_t keys, link_t *item)
66{
67 assert(item);
68 ep_t *ep = hash_table_get_instance(item, ep_t, link);
69 hash_count_t i = 0;
70 for (; i < keys; ++i) {
71 if (key[i] != ep->key[i])
72 return false;
73 }
74 return true;
75}
76/*----------------------------------------------------------------------------*/
77static void ep_remove(link_t *item)
78{
79 assert(item);
80 ep_t *ep =
81 hash_table_get_instance(item, ep_t, link);
82 ep->data_remove_callback(ep->data);
83 free(ep);
84}
85/*----------------------------------------------------------------------------*/
86static hash_table_operations_t op = {
87 .hash = ep_hash,
88 .compare = ep_compare,
89 .remove_callback = ep_remove,
90};
91/*----------------------------------------------------------------------------*/
92size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
93 size_t size, size_t max_packet_size)
94{
95 const unsigned packet_count =
96 (size + max_packet_size - 1) / max_packet_size;
97 /* TODO: It may be that ISO and INT transfers use only one data packet
98 * per transaction, but I did not find text in UB spec that confirms
99 * this */
100 /* NOTE: All data packets will be considered to be max_packet_size */
101 switch (speed)
102 {
103 case USB_SPEED_LOW:
104 assert(type == USB_TRANSFER_INTERRUPT);
105 /* Protocol overhead 13B
106 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
107 * CRC bytes, and a 3-byte interpacket delay)
108 * see USB spec page 45-46. */
109 /* Speed penalty 8: low speed is 8-times slower*/
110 return packet_count * (13 + max_packet_size) * 8;
111 case USB_SPEED_FULL:
112 /* Interrupt transfer overhead see above
113 * or page 45 of USB spec */
114 if (type == USB_TRANSFER_INTERRUPT)
115 return packet_count * (13 + max_packet_size);
116
117 assert(type == USB_TRANSFER_ISOCHRONOUS);
118 /* Protocol overhead 9B
119 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
120 * bytes, and a 1-byte interpacket delay)
121 * see USB spec page 42 */
122 return packet_count * (9 + max_packet_size);
123 default:
124 return 0;
125 }
126}
127/*----------------------------------------------------------------------------*/
128int usb_endpoint_manager_init(usb_endpoint_manager_t *instance,
129 size_t available_bandwidth)
130{
131 assert(instance);
132 fibril_mutex_initialize(&instance->guard);
133 fibril_condvar_initialize(&instance->change);
134 instance->free_bw = available_bandwidth;
135 bool ht =
136 hash_table_create(&instance->ep_table, BUCKET_COUNT, MAX_KEYS, &op);
137 return ht ? EOK : ENOMEM;
138}
139/*----------------------------------------------------------------------------*/
140void usb_endpoint_manager_destroy(usb_endpoint_manager_t *instance)
141{
142 hash_table_destroy(&instance->ep_table);
143}
144/*----------------------------------------------------------------------------*/
145int usb_endpoint_manager_register_ep(usb_endpoint_manager_t *instance,
146 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
147 void *data, void (*data_remove_callback)(void* data), size_t bw)
148{
149 assert(instance);
150
151 id_t id = {
152 .address = address,
153 .endpoint = endpoint,
154 .direction = direction,
155 };
156 fibril_mutex_lock(&instance->guard);
157
158 link_t *item =
159 hash_table_find(&instance->ep_table, (unsigned long*)&id);
160 if (item != NULL) {
161 fibril_mutex_unlock(&instance->guard);
162 return EEXISTS;
163 }
164
165 if (bw > instance->free_bw) {
166 fibril_mutex_unlock(&instance->guard);
167 return ENOSPC;
168 }
169
170 ep_t *ep = malloc(sizeof(ep_t));
171 if (ep == NULL) {
172 fibril_mutex_unlock(&instance->guard);
173 return ENOMEM;
174 }
175
176 ep->id = id;
177 ep->bw = bw;
178 ep->data = data;
179 link_initialize(&ep->link);
180
181 hash_table_insert(&instance->ep_table, (unsigned long*)&id, &ep->link);
182 instance->free_bw -= bw;
183 fibril_mutex_unlock(&instance->guard);
184 fibril_condvar_broadcast(&instance->change);
185 return EOK;
186}
187/*----------------------------------------------------------------------------*/
188int usb_endpoint_manager_unregister_ep(usb_endpoint_manager_t *instance,
189 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction)
190{
191 assert(instance);
192 id_t id = {
193 .address = address,
194 .endpoint = endpoint,
195 .direction = direction,
196 };
197 fibril_mutex_lock(&instance->guard);
198 link_t *item =
199 hash_table_find(&instance->ep_table, (unsigned long*)&id);
200 if (item == NULL) {
201 fibril_mutex_unlock(&instance->guard);
202 return EINVAL;
203 }
204
205 ep_t *ep = hash_table_get_instance(item, ep_t, link);
206 instance->free_bw += ep->bw;
207 hash_table_remove(&instance->ep_table, (unsigned long*)&id, MAX_KEYS);
208
209 fibril_mutex_unlock(&instance->guard);
210 fibril_condvar_broadcast(&instance->change);
211 return EOK;
212}
213/*----------------------------------------------------------------------------*/
214void * usb_endpoint_manager_get_ep_data(usb_endpoint_manager_t *instance,
215 usb_address_t address, usb_endpoint_t endpoint, usb_direction_t direction,
216 size_t *bw)
217{
218 assert(instance);
219 id_t id = {
220 .address = address,
221 .endpoint = endpoint,
222 .direction = direction,
223 };
224 fibril_mutex_lock(&instance->guard);
225 link_t *item =
226 hash_table_find(&instance->ep_table, (unsigned long*)&id);
227 if (item == NULL) {
228 fibril_mutex_unlock(&instance->guard);
229 return NULL;
230 }
231 ep_t *ep = hash_table_get_instance(item, ep_t, link);
232 if (bw)
233 *bw = ep->bw;
234
235 fibril_mutex_unlock(&instance->guard);
236 return ep->data;
237}
Note: See TracBrowser for help on using the repository browser.