__mmc_claim_host讲解

20210928 我的第一次总结
这个接口是用来保证中间执行的代码不被打断的。
20211005 我的第二次总结 把host加入到等待队列中,

20211007
我的第三次理解:用sdio_claim_host和sdio_release_host是为了以独占的方式访问SDIO的host

void sdio_claim_host(struct sdio_func *func)
{
	mmc_claim_host(func->card->host);
}
 
static inline void mmc_claim_host(struct mmc_host *host)
{
	__mmc_claim_host(host, NULL);
}
 
/**
 *	__mmc_claim_host - exclusively claim a host
 *	@host: mmc host to claim
 *	@abort: whether or not the operation should be aborted
 *
 *	Claim a host for a set of operations.  If @abort is non null and
 *	dereference a non-zero value then this will return prematurely with
 *	that non-zero value without acquiring the lock.  Returns zero
 *	with the lock held otherwise.
 */
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
	DECLARE_WAITQUEUE(wait, current);
	unsigned long flags;
	int stop;
 
	might_sleep();
 
	add_wait_queue(&host->wq, &wait);
	spin_lock_irqsave(&host->lock, flags);
	while (1) {
		set_current_state(TASK_UNINTERRUPTIBLE);
		stop = abort ? atomic_read(abort) : 0;
		if (stop || !host->claimed || host->claimer == current)
			break;
		spin_unlock_irqrestore(&host->lock, flags);
		schedule();
		spin_lock_irqsave(&host->lock, flags);
	}
	set_current_state(TASK_RUNNING);
	if (!stop) {
		host->claimed = 1;
		host->claimer = current;
		host->claim_cnt += 1;
	} else
		wake_up(&host->wq);
	spin_unlock_irqrestore(&host->lock, flags);
	remove_wait_queue(&host->wq, &wait);
	if (!stop)
		mmc_host_enable(host);
	return stop;
}

显然干事的是__mmc_claim_host,且其第二个参数为NULL。
23行,DECLARE_WAITQUEUE是一个宏,我们把它展开:

#define DECLARE_WAITQUEUE(name, tsk)					\
	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
#define __WAITQUEUE_INITIALIZER(name, tsk) {				\
	.private	= tsk,						\
	.func		= default_wake_function,			\
	.task_list	= { NULL, NULL } }
 
#define current (get_current())
 
DECLARE_WAITQUEUE(wait, current);
wait_queue_t wait = {
	.private = get_current(),
	.func		= default_wake_function,			\
	.task_list	= { NULL, NULL }
}

这里创建一个名为"wait"的等待队列并对其成员初始化,设置其private成员为当前进程。

27行,might_sleep()提醒使用代码的人,这个函数可能会睡眠。如果在原子型上下文(spinlock, irq-handler, …)调用,this macro will print a stack trace,当然开启该功能需要打开相应的config。这里不多说。

29行,add_wait_queue(&host->wq, &wait),把自己(“wait”)加入到等待队列中(host->wq)。host->wq在SDIO驱动(2)Host注册流程提到的mmc_alloc_host()函数中已经初始化。

30行,spin_lock_irqsave(&host->lock, flags),这个spinlock执行三个动作:保存当前中断标志(到flag),禁止CPU中断,获取lock;自然spin_unlock_irqrestore执行相反的操作。

31~39行之间的 while循环,首先设置进程状态为TASK_UNINTERRUPTIBLE不可中断,进而对信号不做响应,保证当前进程在等待时不会受到干扰。传进来的第二个参数为NULL,所以stop等于0。接着进行判断,如果我们获取了host的使用权则结束循环,否则恢复中断、释放spinlock并进行调度,当前进程进入睡眠状态等待唤醒。什么情况下唤醒?另一个进程release host的时候:

static void mmc_do_release_host(struct mmc_host *host)
{
	unsigned long flags;
 
	spin_lock_irqsave(&host->lock, flags);
	if (--host->claim_cnt) {
		/* Release for nested claim */
		spin_unlock_irqrestore(&host->lock, flags);
	} else {
		host->claimed = 0;
		host->claimer = NULL;
		spin_unlock_irqrestore(&host->lock, flags);
		wake_up(&host->wq);
	}
}

很清楚了不是?
当前进程被唤醒, set_current_state(TASK_RUNNING)继续运行。

41~45行,表明host被当前进程占用了并增加计数。

46行移除等待队列,50行使能host。

sdio_claim_host(func);
ret = sdio_set_block_size(func, 0);
sdio_release_host(func);

这2个接口的配对使用,目的是为了独占式的使用host。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libusb_claim_interface 函数的主要作用是请求操作系统分配指定接口的控制权,以便通过该接口与 USB 设备进行通信。 函数原型如下: ```c int libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number); ``` 其中,参数 `dev_handle` 是一个指向 USB 设备句柄的指针,参数 `interface_number` 是要请求控制权的接口号。 函数返回值为 0 表示成功,否则表示失败。 函数实现的具体过程包括以下步骤: 1. 检查输入参数的有效性,包括检查设备句柄是否为空、接口号是否合法等。 2. 向 USB 设备发送请求控制权的命令,并等待设备响应。 3. 如果操作成功,将设备句柄中对应接口的状态设置为 CLAIMED,并返回 0;否则返回错误码。 以下是一个简单的 libusb_claim_interface 函数的实现示例: ```c int libusb_claim_interface(libusb_device_handle *dev_handle, int interface_number) { int r = 0; struct libusb_device *dev; struct libusb_interface *iface; struct libusb_interface_descriptor *iface_desc; struct libusb_config_descriptor *config; uint8_t iface_claimed = 0; int i, j; if (!dev_handle || interface_number < 0) { return LIBUSB_ERROR_INVALID_PARAM; } dev = libusb_get_device(dev_handle); if (!dev) { return LIBUSB_ERROR_INVALID_PARAM; } r = libusb_get_active_config_descriptor(dev, &config); if (r < 0) { return r; } for (i = 0; i < config->bNumInterfaces; i++) { iface = &config->interface[i]; for (j = 0; j < iface->num_altsetting; j++) { iface_desc = &iface->altsetting[j]; if (iface_desc->bInterfaceNumber == interface_number) { if (iface_desc->bAlternateSetting == 0) { r = libusb_control_transfer(dev_handle, LIBUSB_REQUEST_TYPE_STANDARD, LIBUSB_REQUEST_SET_INTERFACE, interface_number, iface_desc->bAlternateSetting, NULL, 0, 1000); if (r < 0) { libusb_free_config_descriptor(config); return r; } iface_claimed = 1; } break; } } if (iface_claimed) { break; } } if (iface_claimed) { libusb_device_handle_add_claimed_interface(dev_handle, interface_number); libusb_free_config_descriptor(config); return 0; } else { libusb_free_config_descriptor(config); return LIBUSB_ERROR_NOT_FOUND; } } ``` 这段代码的具体实现细节可能因不同平台、不同操作系统和不同版本的 libusb 库而有所不同,但是其基本原理和功能都是相通的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值