>udev, writesize, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
if (copy_from_user(buf, user_buffer, writesize)) {
retval = -EFAULT;
goto error;
}
/* this lock makes sure we don't submit URBs to gone devices */
mutex_lock(&dev->io_mutex);
if (!dev->interface) {
/* disconnect() was called */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
goto error;
}
/*当数据从用户空间正确复制到局部缓冲区后,urb必须在可以被提交给USB核心之前被正确初始化*/
usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), buf, writesize, skel_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 把数据从批量OUT端口发出 */
retval = usb_submit_urb(urb, GFP_KERNEL);
mutex_unlock(&dev->io_mutex);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}
/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb);
return writesize;
error:
if (urb) {
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
usb_free_urb(urb);
}
up(&dev->limit_sem);
exit:
return retval;
}
//字符设备的file_operations结构体,这个结构体中的成员实现
static const struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver skel_class = {
.name = "skel%d",
.fops = &skel_fops,
.minor_base = USB_SKEL_MINOR_BASE,
};
//7、探测函数skel_probe
探测和断开:当一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用,探测函数检查传递给它的设备信息,确定驱动程序是否真的适合该设备。当驱动程序因为某种原因不应该控制设备时,断开函数被调用,它可以做一些清理工作。探测回调函数中,USB驱动程序初始化任何可能用于控制USB设备的局部结构体,它还把所需的任何设备相关信息保存到一个局部结构体中
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_skel *dev; //usb_skel设备
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint; //端点描述符
size_t buffer_size;
int i;
int retval = -ENOMEM;
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL); //分配设备状态的内存并初始化
if (!dev) {
err("Out of memory");
goto error;
}
kref_init(&dev->kref); //初始化引用计数,设置为1
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); //
mutex_init(&dev->io_mutex);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
/* 设置端点信息 */
/* 只使用第一个批量IN和批量OUT端点 */
iface_desc = interface->cur_altsetting;
/*在探测函数里,这个循环首先访问该接口中存在的每一个端点,给该端点一个局部指针以便以后访问*/
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
/*如果所有这些探测都通过了,驱动程序就知道它已经发现了正确的端点类型,可以把该端点的相关信息保存到一个局部结构体中以便稍后用它来和端点进行通信*/