偶然浏览Linux-USB的代码,发现了变长数据的妙用,总结一下,学起来。
所示的函数中
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
printk(KERN_ERR "alloc_urb: kmalloc failed\n");
return NULL;
}
usb_init_urb(urb);
return urb;
}
其中,
kmalloc分配新的urb时,多分配了一下内存,用于存储数据。
iso_packets * sizeof(struct usb_iso_packet_descriptor)
再来看urb结构体定义,结构体的末尾有个零数组,可以再分配urb的同时,在urb后的连续内存上,非配不等长的内存用来存储数据。
struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref;/* reference count of the URB */
void *hcpriv;/* private data for host controller */
atomic_t use_count;/* concurrent submissions counter */
atomic_t reject;/* submissions will fail */
int unlinked;/* unlink error code */
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list;/* list head for use by the urb's
* current owner */
struct list_head anchor_list;/* the URB may be anchored */
struct usb_anchor *anchor;
struct usb_device *dev;/* (in) pointer to associated device */
struct usb_host_endpoint *ep;/* (internal) pointer to endpoint */
unsigned int pipe;/* (in) pipe information */
unsigned int stream_id;/* (in) stream ID */
int status;/* (return) non-ISO status */
unsigned int transfer_flags;/* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer;/* (in) associated data buffer */
dma_addr_t transfer_dma;/* (in) dma addr for transfer_buffer */
struct scatterlist *sg;/* (in) scatter gather buffer list */
int num_mapped_sgs;/* (internal) mapped sg entries */
int num_sgs;/* (in) number of entries in the sg list */
u32 transfer_buffer_length;/* (in) data buffer length */
u32 actual_length;/* (return) actual transfer length */
unsigned char *setup_packet;/* (in) setup packet (control only) */
dma_addr_t setup_dma;/* (in) dma addr for setup_packet */
int start_frame;/* (modify) start frame (ISO) */
int number_of_packets;/* (in) number of ISO packets */
int interval;/* (modify) transfer interval
* (INT/ISO) */
int error_count;/* (return) number of ISO errors */
void *context;/* (in) context for completion */
usb_complete_t complete;/* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) ISO ONLY */
};