source: mainline/uspace/lib/usb/src/host/bandwidth.c@ da9ebca

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

Add USB bandwidth manager

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
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#include <assert.h>
30#include <errno.h>
31#include <usb/host/bandwidth.h>
32
33typedef struct {
34 usb_address_t address;
35 usb_endpoint_t endpoint;
36 usb_transfer_type_t transfer_type;
37 size_t max_packet_size;
38 size_t size;
39} __attribute__((aligned (sizeof(unsigned long)))) transfer_t;
40/*----------------------------------------------------------------------------*/
41typedef struct {
42 transfer_t transfer;
43 link_t link;
44 bool used;
45} transfer_status_t;
46/*----------------------------------------------------------------------------*/
47#define BUCKET_COUNT 7
48#define MAX_KEYS (sizeof(transfer_t) / sizeof(unsigned long))
49/*----------------------------------------------------------------------------*/
50static hash_index_t transfer_hash(unsigned long key[])
51{
52 hash_index_t hash = 0;
53 unsigned i = 0;
54 for (;i < MAX_KEYS; ++i) {
55 hash ^= key[i];
56 }
57 hash %= BUCKET_COUNT;
58 return hash;
59}
60/*----------------------------------------------------------------------------*/
61static int trans_compare(unsigned long key[], hash_count_t keys, link_t *item)
62{
63 assert(item);
64 transfer_status_t *status =
65 hash_table_get_instance(item, transfer_status_t, link);
66 const size_t bytes =
67 keys < MAX_KEYS ? keys * sizeof(unsigned long) : sizeof(transfer_t);
68 return bcmp(key, &status->transfer, bytes);
69}
70/*----------------------------------------------------------------------------*/
71static void dummy(link_t *item) {}
72/*----------------------------------------------------------------------------*/
73hash_table_operations_t op = {
74 .hash = transfer_hash,
75 .compare = trans_compare,
76 .remove_callback = dummy,
77};
78/*----------------------------------------------------------------------------*/
79int bandwidth_init(bandwidth_t *instance)
80{
81 assert(instance);
82 fibril_mutex_initialize(&instance->guard);
83 return
84 hash_table_create(&instance->reserved, BUCKET_COUNT, MAX_KEYS, &op);
85}
86/*----------------------------------------------------------------------------*/
87void bandwidth_destroy(bandwidth_t *instance)
88{
89 hash_table_destroy(&instance->reserved);
90}
91/*----------------------------------------------------------------------------*/
92int bandwidth_reserve(bandwidth_t *instance, usb_address_t address,
93 usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
94 size_t max_packet_size, size_t size, unsigned interval)
95{
96 assert(instance);
97 transfer_t trans = {
98 .address = address,
99 .endpoint = endpoint,
100 .transfer_type = transfer_type,
101 .max_packet_size = max_packet_size,
102 .size = size,
103 };
104 fibril_mutex_lock(&instance->guard);
105 link_t *item =
106 hash_table_find(&instance->reserved, (unsigned long*)&trans);
107 if (item != NULL) {
108 fibril_mutex_unlock(&instance->guard);
109 return EEXISTS;
110 }
111
112 transfer_status_t *status = malloc(sizeof(transfer_status_t));
113 if (status == NULL) {
114 fibril_mutex_unlock(&instance->guard);
115 return ENOMEM;
116 }
117
118 status->transfer = trans;
119 status->used = false;
120 link_initialize(&status->link);
121
122 hash_table_insert(&instance->reserved,
123 (unsigned long*)&status->transfer, &status->link);
124 fibril_mutex_unlock(&instance->guard);
125 return EOK;
126 /* TODO: compute bandwidth used */
127}
128/*----------------------------------------------------------------------------*/
129int bandwidth_release(bandwidth_t *instance, usb_address_t address,
130 usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
131 size_t max_packet_size, size_t size, unsigned interval)
132{
133 assert(instance);
134 transfer_t trans = {
135 .address = address,
136 .endpoint = endpoint,
137 .transfer_type = transfer_type,
138 .max_packet_size = max_packet_size,
139 .size = size,
140 };
141 fibril_mutex_lock(&instance->guard);
142 link_t *item =
143 hash_table_find(&instance->reserved, (unsigned long*)&trans);
144 if (item == NULL) {
145 fibril_mutex_unlock(&instance->guard);
146 return EINVAL;
147 }
148
149 hash_table_remove(&instance->reserved,
150 (unsigned long*)&trans, MAX_KEYS);
151
152 fibril_mutex_unlock(&instance->guard);
153 return EOK;
154 /* TODO: compute bandwidth freed */
155}
156/*----------------------------------------------------------------------------*/
157int bandwidth_use(bandwidth_t *instance, usb_address_t address,
158 usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
159 size_t max_packet_size, size_t size, unsigned interval)
160{
161 assert(instance);
162 transfer_t trans = {
163 .address = address,
164 .endpoint = endpoint,
165 .transfer_type = transfer_type,
166 .max_packet_size = max_packet_size,
167 .size = size,
168 };
169 fibril_mutex_lock(&instance->guard);
170 link_t *item =
171 hash_table_find(&instance->reserved, (unsigned long*)&trans);
172 int ret = EOK;
173 if (item != NULL) {
174 transfer_status_t *status =
175 hash_table_get_instance(item, transfer_status_t, link);
176 assert(status);
177 if (status->used) {
178 ret = EINPROGRESS;
179 }
180 status->used = true;
181 } else {
182 ret = EINVAL;
183 }
184 fibril_mutex_unlock(&instance->guard);
185 return ret;
186}
187/*----------------------------------------------------------------------------*/
188int bandwidth_free(bandwidth_t *instance, usb_address_t address,
189 usb_endpoint_t endpoint, usb_transfer_type_t transfer_type,
190 size_t max_packet_size, size_t size, unsigned interval)
191{
192 assert(instance);
193 transfer_t trans = {
194 .address = address,
195 .endpoint = endpoint,
196 .transfer_type = transfer_type,
197 .max_packet_size = max_packet_size,
198 .size = size,
199 };
200 fibril_mutex_lock(&instance->guard);
201 link_t *item =
202 hash_table_find(&instance->reserved, (unsigned long*)&trans);
203 int ret = EOK;
204 if (item != NULL) {
205 transfer_status_t *status =
206 hash_table_get_instance(item, transfer_status_t, link);
207 assert(status);
208 if (!status->used) {
209 ret = ENOENT;
210 }
211 status->used = false;
212 } else {
213 ret = EINVAL;
214 }
215 fibril_mutex_unlock(&instance->guard);
216 return ret;
217}
Note: See TracBrowser for help on using the repository browser.