API_EXPORTED int
libusb_claim_interface(libusb_device_handle *dev,
int interface_number)
{
int r = 0;
usbi_dbg("interface %d", interface_number);
if (interface_number >= sizeof(dev->claimed_interfaces) * 8)
return LIBUSB_ERROR_INVALID_PARAM;
// 看来这个interface_number 还是跟dev 有关,难道是dev中有许多interface? 然后我们启用其中一个?
//将设备进行加锁 通过修改dev_lock实现
pthread_mutex_lock(&dev->lock);
if (dev->claimed_interfaces & (1 << interface_number))
goto out;
//实际上通过该函数实现底层声明借口
r = usbi_backend->claim_interface(dev, interface_number);
if (r == 0)
dev->claimed_interfaces |= 1 << interface_number;
out:
pthread_mutex_unlock(&dev->lock);
return r;
}
现在来查看下struct libusb_dev_handle
struct libusb_device_handle {
/* lock protects claimed_interfaces */
pthread_mutex_t lock;
unsigned long claimed_interfaces;
struct list_head list;
struct libusb_device *dev;
unsigned char os_priv[0];
};
当我们打开一个libusb_device的时候会返回给一个设备处理指针
libusb_device_handle * libusb_open_device_with_vid_pid(libusb_context *ctx , uint vid , uint pid);
/** /ingroup dev
* Convenience function for finding a device with a particular
* idVendor/idProduct combination. This function is intended
* for those scenarios where you are using libusb to knock up a quick test
* application - it allows you to avoid calling libusb_get_device_list() and
* worrying about traversing/freeing the list.
*
* This function has limitations and is hence not intended for use in real
* applications: if multiple devices have the same IDs it will only
* give you the first one, etc.
*
* /param ctx the context to operate on, or NULL for the default context
* /param vendor_id the idVendor value to search for
* /param product_id the idProduct value to search for
* /returns a handle for the first found device, or NULL on error or if the
* device could not be found. */
API_EXPORTED libusb_device_handle *libusb_open_device_with_vid_pid(
libusb_context *ctx, uint16_t vendor_id, uint16_t product_id)
{
struct libusb_device **devs;
struct libusb_device *found = NULL;
struct libusb_device *dev;
struct libusb_device_handle *handle = NULL;
size_t i = 0;
int r;
if (libusb_get_device_list(ctx, &devs) < 0)
return NULL;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
r = libusb_get_device_descriptor(dev, &desc);
if (r < 0)
goto out;
//看来vid和pid还是存放在libusb_descriptor中的
if (desc.idVendor == vendor_id && desc.idProduct == product_id) {
found = dev;
break;
}
}
if (found) {
r = libusb_open(found, &handle);
if (r < 0)
handle = NULL;
}
out:
libusb_free_device_list(devs, 1);
return handle;
}
他其实调用的还是int libusb_open(libusb_device , libusb_device_handle &);
现在分析下如何 通过libusb_open将 libusb_device_handle 中的unsigned long claimed_interface修改下。
API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct libusb_device_handle *_handle;
size_t priv_size = usbi_backend->device_handle_priv_size;
unsigned char dummy = 1;
int r;
usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
_handle = malloc(sizeof(*_handle) + priv_size);
if (!_handle)
return LIBUSB_ERROR_NO_MEM;
//对于每一个handle创建一个lock
r = pthread_mutex_init(&_handle->lock, NULL);
if (r)
return LIBUSB_ERROR_OTHER;
_handle->dev = libusb_ref_device(dev);
//将claimedInterface设置默认为0
_handle->claimed_interfaces = 0;
memset(&_handle->os_priv, 0, priv_size);
r = usbi_backend->open(_handle);
if (r < 0) {
libusb_unref_device(dev);
free(_handle);
return r;
}
pthread_mutex_lock(&ctx->open_devs_lock);
list_add(&_handle->list, &ctx->open_devs);
pthread_mutex_unlock(&ctx->open_devs_lock);
*handle = _handle;
/* At this point, we want to interrupt any existing event handlers so
* that they realise the addition of the new device's poll fd. One
* example when this is desirable is if the user is running a separate
* dedicated libusb events handling thread, which is running with a long
* or infinite timeout. We want to interrupt that iteration of the loop,
* so that it picks up the new fd, and then continues. */
/* record that we are messing with poll fds */
pthread_mutex_lock(&ctx->pollfd_modify_lock);
ctx->pollfd_modify++;
pthread_mutex_unlock(&ctx->pollfd_modify_lock);
/* write some data on control pipe to interrupt event handlers */
r = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
if (r <= 0) {
usbi_warn(ctx, "internal signalling write failed");
pthread_mutex_lock(&ctx->pollfd_modify_lock);
ctx->pollfd_modify--;
//可见每一个ctx中也有一个lock
pthread_mutex_unlock(&ctx->pollfd_modify_lock);
return 0;
}
/* take event handling lock */
libusb_lock_events(ctx);
/* read the dummy data */
r = read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy));
if (r <= 0)
usbi_warn(ctx, "internal signalling read failed");
/* we're done with modifying poll fds */
pthread_mutex_lock(&ctx->pollfd_modify_lock);
ctx->pollfd_modify--;
pthread_mutex_unlock(&ctx->pollfd_modify_lock);
/* Release event handling lock and wake up event waiters */
libusb_unlock_events(ctx);
return 0;
}
总结: claim_interface是libusb_device_handle的成员变量在libusb_open(libusb_device *dev, libusb_context **handle)将其默认为0
他具体有什么作用的,求高手指教?