Index: uspace/lib/usb/src/host/bandwidth.c
===================================================================
--- uspace/lib/usb/src/host/bandwidth.c	(revision 88702300c98dd32f6dcd809fc99e6a0c9ae9a70a)
+++ uspace/lib/usb/src/host/bandwidth.c	(revision 322a8066dd6a2df80d2650aaf0b4e19bbe60b576)
@@ -58,5 +58,6 @@
 }
 /*----------------------------------------------------------------------------*/
-static int trans_compare(unsigned long key[], hash_count_t keys, link_t *item)
+static int transfer_compare(
+    unsigned long key[], hash_count_t keys, link_t *item)
 {
 	assert(item);
@@ -68,16 +69,62 @@
 }
 /*----------------------------------------------------------------------------*/
-static void dummy(link_t *item) {}
+static void transfer_remove(link_t *item)
+{
+	assert(item);
+	transfer_status_t *status =
+	    hash_table_get_instance(item, transfer_status_t, link);
+	assert(status);
+	free(status);
+}
 /*----------------------------------------------------------------------------*/
 hash_table_operations_t op = {
 	.hash = transfer_hash,
-	.compare = trans_compare,
-	.remove_callback = dummy,
+	.compare = transfer_compare,
+	.remove_callback = transfer_remove,
 };
 /*----------------------------------------------------------------------------*/
-int bandwidth_init(bandwidth_t *instance)
+size_t bandwidth_count_usb11(usb_speed_t speed, usb_transfer_type_t type,
+    size_t size, size_t max_packet_size)
+{
+	const unsigned packet_count =
+	    (size + max_packet_size - 1) / max_packet_size;
+	/* TODO: It may be that ISO and INT transfers use only one data packet
+	 * per transaction, but I did not find text in UB spec that confirms
+	 * this */
+	/* NOTE: All data packets will be considered to be max_packet_size */
+	switch (speed)
+	{
+	case USB_SPEED_LOW:
+		assert(type == USB_TRANSFER_INTERRUPT);
+		/* Protocol overhead 13B
+		 * (3 SYNC bytes, 3 PID bytes, 2 Endpoint + CRC bytes, 2
+		 * CRC bytes, and a 3-byte interpacket delay)
+		 * see USB spec page 45-46. */
+		/* Speed penalty 8: low speed is 8-times slower*/
+		return packet_count * (13 + max_packet_size) * 8;
+	case USB_SPEED_FULL:
+		/* Interrupt transfer overhead see above
+		 * or page 45 of USB spec */
+		if (type == USB_TRANSFER_INTERRUPT)
+			return packet_count * (13 + max_packet_size);
+
+		assert(type == USB_TRANSFER_ISOCHRONOUS);
+		/* Protocol overhead 9B
+		 * (2 SYNC bytes, 2 PID bytes, 2 Endpoint + CRC bytes, 2 CRC
+		 * bytes, and a 1-byte interpacket delay)
+		 * see USB spec page 42 */
+		return packet_count * (9 + max_packet_size);
+	default:
+		return 0;
+	}
+}
+/*----------------------------------------------------------------------------*/
+int bandwidth_init(bandwidth_t *instance, size_t bandwidth,
+    size_t (*usage_fnc)(usb_speed_t, usb_transfer_type_t, size_t, size_t))
 {
 	assert(instance);
 	fibril_mutex_initialize(&instance->guard);
+	instance->free = bandwidth;
+	instance->usage_fnc = usage_fnc;
 	return
 	    hash_table_create(&instance->reserved, BUCKET_COUNT, MAX_KEYS, &op);
@@ -94,11 +141,26 @@
     unsigned interval)
 {
-	assert(instance);
-	transfer_t trans = {
-		.address = address,
-		.endpoint = endpoint,
-		.direction = direction,
-	};
-	fibril_mutex_lock(&instance->guard);
+	if (transfer_type != USB_TRANSFER_ISOCHRONOUS &&
+	    transfer_type != USB_TRANSFER_INTERRUPT) {
+		return ENOTSUP;
+	}
+
+	assert(instance);
+	assert(instance->usage_fnc);
+
+	transfer_t trans = {
+		.address = address,
+		.endpoint = endpoint,
+		.direction = direction,
+	};
+	fibril_mutex_lock(&instance->guard);
+	const size_t required =
+	    instance->usage_fnc(speed, transfer_type, size, max_packet_size);
+
+	if (required > instance->free) {
+		fibril_mutex_unlock(&instance->guard);
+		return ENOSPC;
+	}
+
 	link_t *item =
 	    hash_table_find(&instance->reserved, (unsigned long*)&trans);
@@ -115,5 +177,5 @@
 
 	status->transfer = trans;
-	status->required = 0;
+	status->required = required;
 	status->used = false;
 	link_initialize(&status->link);
@@ -121,4 +183,5 @@
 	hash_table_insert(&instance->reserved,
 	    (unsigned long*)&status->transfer, &status->link);
+	instance->free -= required;
 	fibril_mutex_unlock(&instance->guard);
 	return EOK;
@@ -142,4 +205,9 @@
 		return EINVAL;
 	}
+
+	transfer_status_t *status =
+	    hash_table_get_instance(item, transfer_status_t, link);
+
+	instance->free += status->required;
 
 	hash_table_remove(&instance->reserved,
