📄 usb.c
字号:
/* put into sysfs, with device and config specific files */
err = device_add (&dev->dev);
if (err)
return err;
usb_create_driverfs_dev_files (dev);
/* Register all of the interfaces for this device with the driver core.
* Remember, interfaces get bound to drivers, not devices. */
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
struct usb_interface_descriptor *desc;
desc = &interface->altsetting [interface->act_altsetting].desc;
interface->dev.parent = &dev->dev;
interface->dev.driver = NULL;
interface->dev.bus = &usb_bus_type;
interface->dev.dma_mask = parent->dma_mask;
sprintf (&interface->dev.bus_id[0], "%d-%s:%d",
dev->bus->busnum, dev->devpath,
desc->bInterfaceNumber);
if (!desc->iInterface
|| usb_string (dev, desc->iInterface,
interface->dev.name,
sizeof interface->dev.name) <= 0) {
/* typically devices won't bother with interface
* descriptions; this is the normal case. an
* interface's driver might describe it better.
* (also: iInterface is per-altsetting ...)
*/
sprintf (&interface->dev.name[0],
"usb-%s-%s interface %d",
dev->bus->bus_name, dev->devpath,
desc->bInterfaceNumber);
DPRINT1(".........................usb_new_device: %s\n", interface->dev.name);
}
dev_dbg (&dev->dev, "%s - registering interface %s\n", __FUNCTION__, interface->dev.bus_id);
device_add (&interface->dev);
usb_create_driverfs_intf_files (interface);
}
/* add a /proc/bus/usb entry */
//usbfs_add_device(dev);
return 0;
fail:
dev->state = USB_STATE_DEFAULT;
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return err;
}
/**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP
* @dev: device the buffer will be used with
* @size: requested buffer size
* @mem_flags: affect whether allocation may block
* @dma: used to return DMA address of buffer
*
* Return value is either null (indicating no buffer could be allocated), or
* the cpu-space pointer to a buffer that may be used to perform DMA to the
* specified device. Such cpu-space buffers are returned along with the DMA
* address (through the pointer provided).
*
* These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to
* avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
* hardware for long idle periods. The implementation varies between
* platforms, depending on details of how DMA will work to this device.
* Using these buffers also helps prevent cacheline sharing problems on
* architectures where CPU caches are not DMA-coherent.
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
void *usb_buffer_alloc (
struct usb_device *dev,
size_t size,
int mem_flags,
dma_addr_t *dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
return 0;
return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
}
/**
* usb_buffer_free - free memory allocated with usb_buffer_alloc()
* @dev: device the buffer was used with
* @size: requested buffer size
* @addr: CPU address of buffer
* @dma: DMA address of buffer
*
* This reclaims an I/O buffer, letting it be reused. The memory must have
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
void usb_buffer_free (
struct usb_device *dev,
size_t size,
void *addr,
dma_addr_t dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
return;
dev->bus->op->buffer_free (dev->bus, size, addr, dma);
}
/**
* usb_buffer_map - create DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer will be mapped
*
* Return value is either null (indicating no buffer could be mapped), or
* the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the
* operation succeeds. If the device is connected to this system through
* a non-DMA controller, this operation always succeeds.
*
* This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync()
* calls to synchronize memory and dma state. It may not be used for
* control requests.
*
* Reverse the effect of this call with usb_buffer_unmap().
*/
struct urb *usb_buffer_map (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
if (!urb
|| usb_pipecontrol (urb->pipe)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return 0;
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= URB_NO_DMA_MAP;
return urb;
}
/**
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer will be synchronized
*/
void usb_buffer_dmasync (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
if (!urb
|| !(urb->transfer_flags & URB_NO_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return;
if (controller->dma_mask)
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/**
* usb_buffer_unmap - free DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer will be unmapped
*
* Reverses the effect of usb_buffer_map().
*/
void usb_buffer_unmap (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
if (!urb
|| !(urb->transfer_flags & URB_NO_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return;
if (controller->dma_mask)
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
urb->transfer_flags &= ~URB_NO_DMA_MAP;
}
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
* Return value is either < 0 (indicating no buffers could be mapped), or
* the number of DMA mapping array entries in the scatterlist.
*
* The caller is responsible for placing the resulting DMA addresses from
* the scatterlist into URB transfer buffer pointers, and for setting the
* URB_NO_DMA_MAP transfer flag in each of those URBs.
*
* Top I/O rates come from queuing URBs, instead of waiting for each one
* to complete before starting the next I/O. This is particularly easy
* to do with scatterlists. Just allocate and submit one URB for each DMA
* mapping entry returned, stopping on the first error or when all succeed.
* Better yet, use the usb_sg_*() calls, which do that (and more) for you.
*
* This call would normally be used when translating scatterlist requests,
* rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
* may be able to coalesce mappings for improved I/O efficiency.
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
|| usb_pipecontrol (pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// FIXME generic api broken like pci, can't report errors
return dma_map_sg (controller, sg, nents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
dma_sync_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
dma_unmap_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.hotplug = usb_hotplug,
};
#ifndef MODULE
static int __init usb_setup_disable(char *str)
{
nousb = 1;
return 1;
}
/* format to disable USB on kernel command line is: nousb */
__setup("nousb", usb_setup_disable);
#endif
/*
* for external read access to <nousb>
*/
int STDCALL usb_disabled(void)
{
return nousb;
}
/*
* Init
*/
int STDCALL __init usb_init(void)
{
if (nousb) {
info("USB support disabled\n");
return 0;
}
bus_register(&usb_bus_type);
usb_major_init();
usbfs_init();
usb_hub_init();
driver_register(&usb_generic_driver);
return 0;
}
/*
* Cleanup
*/
void STDCALL __exit usb_exit(void)
{
/* This will matter if shutdown/reboot does exitcalls. */
if (nousb)
return;
driver_unregister(&usb_generic_driver);
usb_major_cleanup();
usbfs_cleanup();
usb_hub_cleanup();
bus_unregister(&usb_bus_type);
}
subsys_initcall(usb_init);
module_exit(usb_exit);
/*
* USB may be built into the kernel or be built as modules.
* These symbols are exported for device (or host controller)
* driver modules to use.
*/
EXPORT_SYMBOL(usb_epnum_to_ep_desc);
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_disabled);
EXPORT_SYMBOL(usb_device_probe);
EXPORT_SYMBOL(usb_device_remove);
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_put_dev);
EXPORT_SYMBOL(usb_get_dev);
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_connect);
EXPORT_SYMBOL(usb_disconnect);
EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);
EXPORT_SYMBOL (usb_buffer_map);
EXPORT_SYMBOL (usb_buffer_dmasync);
EXPORT_SYMBOL (usb_buffer_unmap);
EXPORT_SYMBOL (usb_buffer_map_sg);
EXPORT_SYMBOL (usb_buffer_dmasync_sg);
EXPORT_SYMBOL (usb_buffer_unmap_sg);
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -