669 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			669 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
// SPDX-License-Identifier: GPL-2.0+
 | 
						|
/*
 | 
						|
 * (C) Copyright 2003
 | 
						|
 * Gerry Hamel, geh@ti.com, Texas Instruments
 | 
						|
 *
 | 
						|
 * Based on
 | 
						|
 * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
 | 
						|
 *
 | 
						|
 * Copyright (c) 2000, 2001, 2002 Lineo
 | 
						|
 * Copyright (c) 2001 Hewlett Packard
 | 
						|
 *
 | 
						|
 * By:
 | 
						|
 *	Stuart Lynne <sl@lineo.com>,
 | 
						|
 *	Tom Rushworth <tbr@lineo.com>,
 | 
						|
 *	Bruce Balden <balden@lineo.com>
 | 
						|
 */
 | 
						|
 | 
						|
#include <malloc.h>
 | 
						|
#include <usbdevice.h>
 | 
						|
 | 
						|
#define MAX_INTERFACES 2
 | 
						|
 | 
						|
 | 
						|
int maxstrings = 20;
 | 
						|
 | 
						|
/* Global variables ************************************************************************** */
 | 
						|
 | 
						|
struct usb_string_descriptor **usb_strings;
 | 
						|
 | 
						|
int usb_devices;
 | 
						|
 | 
						|
extern struct usb_function_driver ep0_driver;
 | 
						|
 | 
						|
int registered_functions;
 | 
						|
int registered_devices;
 | 
						|
 | 
						|
char *usbd_device_events[] = {
 | 
						|
	"DEVICE_UNKNOWN",
 | 
						|
	"DEVICE_INIT",
 | 
						|
	"DEVICE_CREATE",
 | 
						|
	"DEVICE_HUB_CONFIGURED",
 | 
						|
	"DEVICE_RESET",
 | 
						|
	"DEVICE_ADDRESS_ASSIGNED",
 | 
						|
	"DEVICE_CONFIGURED",
 | 
						|
	"DEVICE_SET_INTERFACE",
 | 
						|
	"DEVICE_SET_FEATURE",
 | 
						|
	"DEVICE_CLEAR_FEATURE",
 | 
						|
	"DEVICE_DE_CONFIGURED",
 | 
						|
	"DEVICE_BUS_INACTIVE",
 | 
						|
	"DEVICE_BUS_ACTIVITY",
 | 
						|
	"DEVICE_POWER_INTERRUPTION",
 | 
						|
	"DEVICE_HUB_RESET",
 | 
						|
	"DEVICE_DESTROY",
 | 
						|
	"DEVICE_FUNCTION_PRIVATE",
 | 
						|
};
 | 
						|
 | 
						|
char *usbd_device_states[] = {
 | 
						|
	"STATE_INIT",
 | 
						|
	"STATE_CREATED",
 | 
						|
	"STATE_ATTACHED",
 | 
						|
	"STATE_POWERED",
 | 
						|
	"STATE_DEFAULT",
 | 
						|
	"STATE_ADDRESSED",
 | 
						|
	"STATE_CONFIGURED",
 | 
						|
	"STATE_UNKNOWN",
 | 
						|
};
 | 
						|
 | 
						|
char *usbd_device_requests[] = {
 | 
						|
	"GET STATUS",		/* 0 */
 | 
						|
	"CLEAR FEATURE",	/* 1 */
 | 
						|
	"RESERVED",		/* 2 */
 | 
						|
	"SET FEATURE",		/* 3 */
 | 
						|
	"RESERVED",		/* 4 */
 | 
						|
	"SET ADDRESS",		/* 5 */
 | 
						|
	"GET DESCRIPTOR",	/* 6 */
 | 
						|
	"SET DESCRIPTOR",	/* 7 */
 | 
						|
	"GET CONFIGURATION",	/* 8 */
 | 
						|
	"SET CONFIGURATION",	/* 9 */
 | 
						|
	"GET INTERFACE",	/* 10 */
 | 
						|
	"SET INTERFACE",	/* 11 */
 | 
						|
	"SYNC FRAME",		/* 12 */
 | 
						|
};
 | 
						|
 | 
						|
char *usbd_device_descriptors[] = {
 | 
						|
	"UNKNOWN",		/* 0 */
 | 
						|
	"DEVICE",		/* 1 */
 | 
						|
	"CONFIG",		/* 2 */
 | 
						|
	"STRING",		/* 3 */
 | 
						|
	"INTERFACE",		/* 4 */
 | 
						|
	"ENDPOINT",		/* 5 */
 | 
						|
	"DEVICE QUALIFIER",	/* 6 */
 | 
						|
	"OTHER SPEED",		/* 7 */
 | 
						|
	"INTERFACE POWER",	/* 8 */
 | 
						|
};
 | 
						|
 | 
						|
char *usbd_device_status[] = {
 | 
						|
	"USBD_OPENING",
 | 
						|
	"USBD_OK",
 | 
						|
	"USBD_SUSPENDED",
 | 
						|
	"USBD_CLOSING",
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/* Descriptor support functions ************************************************************** */
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_get_string - find and return a string descriptor
 | 
						|
 * @index: string index to return
 | 
						|
 *
 | 
						|
 * Find an indexed string and return a pointer to a it.
 | 
						|
 */
 | 
						|
struct usb_string_descriptor *usbd_get_string (__u8 index)
 | 
						|
{
 | 
						|
	if (index >= maxstrings) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return usb_strings[index];
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Access to device descriptor functions ***************************************************** */
 | 
						|
 | 
						|
 | 
						|
/* *
 | 
						|
 * usbd_device_configuration_instance - find a configuration instance for this device
 | 
						|
 * @device:
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 *
 | 
						|
 * Get specifed device configuration. Index should be bConfigurationValue-1.
 | 
						|
 */
 | 
						|
static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
 | 
						|
		unsigned int port, unsigned int configuration)
 | 
						|
{
 | 
						|
	if (configuration >= device->configurations)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	return device->configuration_instance_array + configuration;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* *
 | 
						|
 * usbd_device_interface_instance
 | 
						|
 * @device:
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @interface: index to interface
 | 
						|
 *
 | 
						|
 * Return the specified interface descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
 | 
						|
{
 | 
						|
	struct usb_configuration_instance *configuration_instance;
 | 
						|
 | 
						|
	if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	if (interface >= configuration_instance->interfaces) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return configuration_instance->interface_instance_array + interface;
 | 
						|
}
 | 
						|
 | 
						|
/* *
 | 
						|
 * usbd_device_alternate_descriptor_list
 | 
						|
 * @device:
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @interface: index to interface
 | 
						|
 * @alternate: alternate setting
 | 
						|
 *
 | 
						|
 * Return the specified alternate descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
 | 
						|
{
 | 
						|
	struct usb_interface_instance *interface_instance;
 | 
						|
 | 
						|
	if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (alternate >= interface_instance->alternates) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return interface_instance->alternates_instance_array + alternate;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* *
 | 
						|
 * usbd_device_device_descriptor
 | 
						|
 * @device: which device
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @port: which port
 | 
						|
 *
 | 
						|
 * Return the specified configuration descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
 | 
						|
{
 | 
						|
	return (device->device_descriptor);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_device_configuration_descriptor
 | 
						|
 * @device: which device
 | 
						|
 * @port: which port
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 *
 | 
						|
 * Return the specified configuration descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
 | 
						|
									   usb_device_instance
 | 
						|
									   *device, int port, int configuration)
 | 
						|
{
 | 
						|
	struct usb_configuration_instance *configuration_instance;
 | 
						|
	if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return (configuration_instance->configuration_descriptor);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_device_interface_descriptor
 | 
						|
 * @device: which device
 | 
						|
 * @port: which port
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @interface: index to interface
 | 
						|
 * @alternate: alternate setting
 | 
						|
 *
 | 
						|
 * Return the specified interface descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
 | 
						|
								   *device, int port, int configuration, int interface, int alternate)
 | 
						|
{
 | 
						|
	struct usb_interface_instance *interface_instance;
 | 
						|
	if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_device_endpoint_descriptor_index
 | 
						|
 * @device: which device
 | 
						|
 * @port: which port
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @interface: index to interface
 | 
						|
 * @alternate: index setting
 | 
						|
 * @index: which index
 | 
						|
 *
 | 
						|
 * Return the specified endpoint descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
 | 
						|
								       *device, int port, int configuration, int interface, int alternate, int index)
 | 
						|
{
 | 
						|
	struct usb_alternate_instance *alternate_instance;
 | 
						|
 | 
						|
	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	if (index >= alternate_instance->endpoints) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return *(alternate_instance->endpoints_descriptor_array + index);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_device_endpoint_transfersize
 | 
						|
 * @device: which device
 | 
						|
 * @port: which port
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @interface: index to interface
 | 
						|
 * @index: which index
 | 
						|
 *
 | 
						|
 * Return the specified endpoint transfer size;
 | 
						|
 */
 | 
						|
int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
 | 
						|
{
 | 
						|
	struct usb_alternate_instance *alternate_instance;
 | 
						|
 | 
						|
	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (index >= alternate_instance->endpoints) {
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return *(alternate_instance->endpoint_transfersize_array + index);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_device_endpoint_descriptor
 | 
						|
 * @device: which device
 | 
						|
 * @port: which port
 | 
						|
 * @configuration: index to configuration, 0 - N-1
 | 
						|
 * @interface: index to interface
 | 
						|
 * @alternate: alternate setting
 | 
						|
 * @endpoint: which endpoint
 | 
						|
 *
 | 
						|
 * Return the specified endpoint descriptor for the specified device.
 | 
						|
 */
 | 
						|
struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
 | 
						|
{
 | 
						|
	struct usb_endpoint_descriptor *endpoint_descriptor;
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
 | 
						|
		if (endpoint_descriptor->bEndpointAddress == endpoint) {
 | 
						|
			return endpoint_descriptor;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_endpoint_halted
 | 
						|
 * @device: point to struct usb_device_instance
 | 
						|
 * @endpoint: endpoint to check
 | 
						|
 *
 | 
						|
 * Return non-zero if endpoint is halted.
 | 
						|
 */
 | 
						|
int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
 | 
						|
{
 | 
						|
	return (device->status == USB_STATUS_HALT);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_rcv_complete - complete a receive
 | 
						|
 * @endpoint:
 | 
						|
 * @len:
 | 
						|
 * @urb_bad:
 | 
						|
 *
 | 
						|
 * Called from rcv interrupt to complete.
 | 
						|
 */
 | 
						|
void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
 | 
						|
{
 | 
						|
	if (endpoint) {
 | 
						|
		struct urb *rcv_urb;
 | 
						|
 | 
						|
		/*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
 | 
						|
 | 
						|
		/* if we had an urb then update actual_length, dispatch if neccessary */
 | 
						|
		if ((rcv_urb = endpoint->rcv_urb)) {
 | 
						|
 | 
						|
			/*usbdbg("actual: %d buffer: %d\n", */
 | 
						|
			/*rcv_urb->actual_length, rcv_urb->buffer_length); */
 | 
						|
 | 
						|
			/* check the urb is ok, are we adding data less than the packetsize */
 | 
						|
			if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
 | 
						|
			  /*usbdbg("updating actual_length by %d\n",len); */
 | 
						|
 | 
						|
				/* increment the received data size */
 | 
						|
				rcv_urb->actual_length += len;
 | 
						|
 | 
						|
			} else {
 | 
						|
				usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
 | 
						|
				       rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
 | 
						|
 | 
						|
				rcv_urb->actual_length = 0;
 | 
						|
				rcv_urb->status = RECV_ERROR;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			usberr("no rcv_urb!");
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		usberr("no endpoint!");
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_tx_complete - complete a transmit
 | 
						|
 * @endpoint:
 | 
						|
 * @resetart:
 | 
						|
 *
 | 
						|
 * Called from tx interrupt to complete.
 | 
						|
 */
 | 
						|
void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
 | 
						|
{
 | 
						|
	if (endpoint) {
 | 
						|
		struct urb *tx_urb;
 | 
						|
 | 
						|
		/* if we have a tx_urb advance or reset, finish if complete */
 | 
						|
		if ((tx_urb = endpoint->tx_urb)) {
 | 
						|
			int sent = endpoint->last;
 | 
						|
			endpoint->sent += sent;
 | 
						|
			endpoint->last -= sent;
 | 
						|
 | 
						|
			if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
 | 
						|
				tx_urb->actual_length = 0;
 | 
						|
				endpoint->sent = 0;
 | 
						|
				endpoint->last = 0;
 | 
						|
 | 
						|
				/* Remove from active, save for re-use */
 | 
						|
				urb_detach(tx_urb);
 | 
						|
				urb_append(&endpoint->done, tx_urb);
 | 
						|
				/*usbdbg("done->next %p, tx_urb %p, done %p", */
 | 
						|
				/*	 endpoint->done.next, tx_urb, &endpoint->done); */
 | 
						|
 | 
						|
				endpoint->tx_urb = first_urb_detached(&endpoint->tx);
 | 
						|
				if( endpoint->tx_urb ) {
 | 
						|
					endpoint->tx_queue--;
 | 
						|
					usbdbg("got urb from tx list");
 | 
						|
				}
 | 
						|
				if( !endpoint->tx_urb ) {
 | 
						|
					/*usbdbg("taking urb from done list"); */
 | 
						|
					endpoint->tx_urb = first_urb_detached(&endpoint->done);
 | 
						|
				}
 | 
						|
				if( !endpoint->tx_urb ) {
 | 
						|
					usbdbg("allocating new urb for tx_urb");
 | 
						|
					endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* URB linked list functions ***************************************************** */
 | 
						|
 | 
						|
/*
 | 
						|
 * Initialize an urb_link to be a single element list.
 | 
						|
 * If the urb_link is being used as a distinguished list head
 | 
						|
 * the list is empty when the head is the only link in the list.
 | 
						|
 */
 | 
						|
void urb_link_init (urb_link * ul)
 | 
						|
{
 | 
						|
	if (ul) {
 | 
						|
		ul->prev = ul->next = ul;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Detach an urb_link from a list, and set it
 | 
						|
 * up as a single element list, so no dangling
 | 
						|
 * pointers can be followed, and so it can be
 | 
						|
 * joined to another list if so desired.
 | 
						|
 */
 | 
						|
void urb_detach (struct urb *urb)
 | 
						|
{
 | 
						|
	if (urb) {
 | 
						|
		urb_link *ul = &urb->link;
 | 
						|
		ul->next->prev = ul->prev;
 | 
						|
		ul->prev->next = ul->next;
 | 
						|
		urb_link_init (ul);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Return the first urb_link in a list with a distinguished
 | 
						|
 * head "hd", or NULL if the list is empty.  This will also
 | 
						|
 * work as a predicate, returning NULL if empty, and non-NULL
 | 
						|
 * otherwise.
 | 
						|
 */
 | 
						|
urb_link *first_urb_link (urb_link * hd)
 | 
						|
{
 | 
						|
	urb_link *nx;
 | 
						|
	if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
 | 
						|
		/* There is at least one element in the list */
 | 
						|
		/* (besides the distinguished head). */
 | 
						|
		return (nx);
 | 
						|
	}
 | 
						|
	/* The list is empty */
 | 
						|
	return (NULL);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Return the first urb in a list with a distinguished
 | 
						|
 * head "hd", or NULL if the list is empty.
 | 
						|
 */
 | 
						|
struct urb *first_urb (urb_link * hd)
 | 
						|
{
 | 
						|
	urb_link *nx;
 | 
						|
	if (NULL == (nx = first_urb_link (hd))) {
 | 
						|
		/* The list is empty */
 | 
						|
		return (NULL);
 | 
						|
	}
 | 
						|
	return (p2surround (struct urb, link, nx));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Detach and return the first urb in a list with a distinguished
 | 
						|
 * head "hd", or NULL if the list is empty.
 | 
						|
 *
 | 
						|
 */
 | 
						|
struct urb *first_urb_detached (urb_link * hd)
 | 
						|
{
 | 
						|
	struct urb *urb;
 | 
						|
	if ((urb = first_urb (hd))) {
 | 
						|
		urb_detach (urb);
 | 
						|
	}
 | 
						|
	return urb;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Append an urb_link (or a whole list of
 | 
						|
 * urb_links) to the tail of another list
 | 
						|
 * of urb_links.
 | 
						|
 */
 | 
						|
void urb_append (urb_link * hd, struct urb *urb)
 | 
						|
{
 | 
						|
	if (hd && urb) {
 | 
						|
		urb_link *new = &urb->link;
 | 
						|
 | 
						|
		/* This allows the new urb to be a list of urbs, */
 | 
						|
		/* with new pointing at the first, but the link */
 | 
						|
		/* must be initialized. */
 | 
						|
		/* Order is important here... */
 | 
						|
		urb_link *pul = hd->prev;
 | 
						|
		new->prev->next = hd;
 | 
						|
		hd->prev = new->prev;
 | 
						|
		new->prev = pul;
 | 
						|
		pul->next = new;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* URB create/destroy functions ***************************************************** */
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
 | 
						|
 * @device: device instance
 | 
						|
 * @endpoint: endpoint
 | 
						|
 *
 | 
						|
 * Allocate an urb structure. The usb device urb structure is used to
 | 
						|
 * contain all data associated with a transfer, including a setup packet for
 | 
						|
 * control transfers.
 | 
						|
 *
 | 
						|
 * NOTE: endpoint_address MUST contain a direction flag.
 | 
						|
 */
 | 
						|
struct urb *usbd_alloc_urb (struct usb_device_instance *device,
 | 
						|
			    struct usb_endpoint_instance *endpoint)
 | 
						|
{
 | 
						|
	struct urb *urb;
 | 
						|
 | 
						|
	if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
 | 
						|
		usberr (" F A T A L:  malloc(%zu) FAILED!!!!",
 | 
						|
			sizeof (struct urb));
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Fill in known fields */
 | 
						|
	memset (urb, 0, sizeof (struct urb));
 | 
						|
	urb->endpoint = endpoint;
 | 
						|
	urb->device = device;
 | 
						|
	urb->buffer = (u8 *) urb->buffer_data;
 | 
						|
	urb->buffer_length = sizeof (urb->buffer_data);
 | 
						|
 | 
						|
	urb_link_init (&urb->link);
 | 
						|
 | 
						|
	return urb;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_dealloc_urb - deallocate an URB and associated buffer
 | 
						|
 * @urb: pointer to an urb structure
 | 
						|
 *
 | 
						|
 * Deallocate an urb structure and associated data.
 | 
						|
 */
 | 
						|
void usbd_dealloc_urb (struct urb *urb)
 | 
						|
{
 | 
						|
	if (urb) {
 | 
						|
		free (urb);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Event signaling functions ***************************************************** */
 | 
						|
 | 
						|
/**
 | 
						|
 * usbd_device_event - called to respond to various usb events
 | 
						|
 * @device: pointer to struct device
 | 
						|
 * @event: event to respond to
 | 
						|
 *
 | 
						|
 * Used by a Bus driver to indicate an event.
 | 
						|
 */
 | 
						|
void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
 | 
						|
{
 | 
						|
	usb_device_state_t state;
 | 
						|
 | 
						|
	if (!device || !device->bus) {
 | 
						|
		usberr("(%p,%d) NULL device or device->bus", device, event);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	state = device->device_state;
 | 
						|
 | 
						|
	usbinfo("%s", usbd_device_events[event]);
 | 
						|
 | 
						|
	switch (event) {
 | 
						|
	case DEVICE_UNKNOWN:
 | 
						|
		break;
 | 
						|
	case DEVICE_INIT:
 | 
						|
		device->device_state = STATE_INIT;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_CREATE:
 | 
						|
		device->device_state = STATE_ATTACHED;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_HUB_CONFIGURED:
 | 
						|
		device->device_state = STATE_POWERED;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_RESET:
 | 
						|
		device->device_state = STATE_DEFAULT;
 | 
						|
		device->address = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_ADDRESS_ASSIGNED:
 | 
						|
		device->device_state = STATE_ADDRESSED;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_CONFIGURED:
 | 
						|
		device->device_state = STATE_CONFIGURED;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_DE_CONFIGURED:
 | 
						|
		device->device_state = STATE_ADDRESSED;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_BUS_INACTIVE:
 | 
						|
		if (device->status != USBD_CLOSING) {
 | 
						|
			device->status = USBD_SUSPENDED;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case DEVICE_BUS_ACTIVITY:
 | 
						|
		if (device->status != USBD_CLOSING) {
 | 
						|
			device->status = USBD_OK;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_SET_INTERFACE:
 | 
						|
		break;
 | 
						|
	case DEVICE_SET_FEATURE:
 | 
						|
		break;
 | 
						|
	case DEVICE_CLEAR_FEATURE:
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_POWER_INTERRUPTION:
 | 
						|
		device->device_state = STATE_POWERED;
 | 
						|
		break;
 | 
						|
	case DEVICE_HUB_RESET:
 | 
						|
		device->device_state = STATE_ATTACHED;
 | 
						|
		break;
 | 
						|
	case DEVICE_DESTROY:
 | 
						|
		device->device_state = STATE_UNKNOWN;
 | 
						|
		break;
 | 
						|
 | 
						|
	case DEVICE_FUNCTION_PRIVATE:
 | 
						|
		break;
 | 
						|
 | 
						|
	default:
 | 
						|
		usbdbg("event %d - not handled",event);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	debug("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
 | 
						|
		device->name, event, state,
 | 
						|
		device->device_state, device->status, device->address);
 | 
						|
 | 
						|
	/* tell the bus interface driver */
 | 
						|
	if( device->event ) {
 | 
						|
		/* usbdbg("calling device->event"); */
 | 
						|
		device->event(device, event, data);
 | 
						|
	}
 | 
						|
}
 |