故障现象:
某客户需要调试一款usb camera,包括黑白和彩色两个sensor:

在调试中发现调用open函数去打开注册的 dev/video1节点时报错:
USBCamera: Cannot open ‘/dev/video1’: 16, Device or resource busy

分析:
1.首先排查硬件的问题。
把该camera连接到PC,下载通用的camera驱动后,设备管理器中显示:

使用网上下载的USB摄像头采集调试工具2020可以正常使用的,说明硬件是好的。

2.检查下camera的uvc驱动注册是正常的:
[ 6.406765] usb 1-1: New USB device found, idVendor=15aa, idProduct=1555
[ 6.412464] usb 1-1: New USB device strings: Mfr=3, Product=1, SerialNumber=2
[ 6.419546] usb 1-1: Product: SIT USB2.0 Camera RGB
[ 6.424433] usb 1-1: Manufacturer: Generic
[ 6.428487] usb 1-1: SerialNumber: 200901010001
[ 6.439198] uvcvideo: Found UVC 1.00 device SIT USB2.0 Camera RGB (15aa:1555)
检查dev下成功注册了video1节点。

3.apk会通过ioctl调到uvc camera的open操作。(uvc_v4l2.c)

const struct v4l2_file_operations uvc_fops = {.owner        = THIS_MODULE,.open        = uvc_v4l2_open,.release   = uvc_v4l2_release,.unlocked_ioctl = uvc_v4l2_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl32 = uvc_v4l2_compat_ioctl32,
#endif.read     = uvc_v4l2_read,.mmap      = uvc_v4l2_mmap,.poll      = uvc_v4l2_poll,
#ifndef CONFIG_MMU.get_unmapped_area = uvc_v4l2_get_unmapped_area,
#endif
};

既然是上层open错误,那肯定是调用到驱动这里的open有错误。
继续添加打印发现是uvc_fops的.open函数uvc_v4l2_open -->ret = usb_autopm_get_interface(stream->dev->intf);
这里返回错误 -16。

4.usb_autopm_get_interface分析。
uvc_v4l2_open函数里会调用usb_autopm_get_interface:

static int uvc_v4l2_open(struct file *file)
{struct uvc_streaming *stream;struct uvc_fh *handle;int ret = 0;uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");stream = video_drvdata(file);if (stream->dev->state & UVC_DEV_DISCONNECTED)return -ENODEV;ret = usb_autopm_get_interface(stream->dev->intf);if (ret < 0)return ret;/* Create the device handle. */handle = kzalloc(sizeof *handle, GFP_KERNEL);if (handle == NULL) {usb_autopm_put_interface(stream->dev->intf);return -ENOMEM;}mutex_lock(&stream->dev->lock);if (stream->dev->users == 0) {ret = uvc_status_start(stream->dev, GFP_KERNEL);if (ret < 0) {mutex_unlock(&stream->dev->lock);usb_autopm_put_interface(stream->dev->intf);kfree(handle);return ret;}}stream->dev->users++;mutex_unlock(&stream->dev->lock);v4l2_fh_init(&handle->vfh, stream->vdev);v4l2_fh_add(&handle->vfh);handle->chain = stream->chain;handle->stream = stream;handle->state = UVC_HANDLE_PASSIVE;file->private_data = handle;return 0;
}

这里就得说一下设备驱动的休眠和唤醒。
usb的驱动结构体中有一个flag:.supports_autosuspend ,用来标识是否支持自动休眠。当USB某个接口繁忙或空闲时通知USB core。主要有如下6个函数来实现休眠、唤醒功能:
int usb_autopm_get_interface(struct usb_interface *intf);
void usb_autopm_put_interface(struct usb_interface *intf);
int usb_autopm_get_interface_async(struct usb_interface *intf);
void usb_autopm_put_interface_async(struct usb_interface *intf);
void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
这些函数通过维护使用计数器来工作。当计数器大于0时,接口将被视为繁忙,内核不会进入autosuspend;当usage counter=0时,接口被认为是空闲的,内核将会进入autosuspend。

重点关注 usb_autopm_get_interface和usb_autopm_put_interface函数。

/*** usb_autopm_get_interface - increment a USB interface's PM-usage counter* @intf: the usb_interface whose counter should be incremented** This routine should be called by an interface driver when it wants to* use @intf and needs to guarantee that it is not suspended.  In addition,* the routine prevents @intf from being autosuspended subsequently.  (Note* that this will not prevent suspend events originating in the PM core.)* This prevention will persist until usb_autopm_put_interface() is called* or @intf is unbound.  A typical example would be a character-device* driver when its device file is opened.** @intf's usage counter is incremented to prevent subsequent autosuspends.* However if the autoresume fails then the counter is re-decremented.** This routine can run only in process context.** Return: 0 on success.*/
int usb_autopm_get_interface(struct usb_interface *intf)
{int    status;status = pm_runtime_get_sync(&intf->dev);if (status < 0)pm_runtime_put_sync(&intf->dev);elseatomic_inc(&intf->pm_usage_cnt);dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",__func__, atomic_read(&intf->dev.power.usage_count),status);if (status > 0)status = 0;return status;
}

●usb_autopm_get_interface将会让usage counter +1,并在设备已经进入suspend时执行autoresume;如果autoresume失败,计数器又会-1到初始值的。

/*** usb_autopm_put_interface - decrement a USB interface's PM-usage counter* @intf: the usb_interface whose counter should be decremented** This routine should be called by an interface driver when it is* finished using @intf and wants to allow it to autosuspend.  A typical* example would be a character-device driver when its device file is* closed.** The routine decrements @intf's usage counter.  When the counter reaches* 0, a delayed autosuspend request for @intf's device is attempted.  The* attempt may fail (see autosuspend_check()).** This routine can run only in process context.*/
void usb_autopm_put_interface(struct usb_interface *intf)
{struct usb_device  *udev = interface_to_usbdev(intf);int          status;usb_mark_last_busy(udev);atomic_dec(&intf->pm_usage_cnt);status = pm_runtime_put_sync(&intf->dev);dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",__func__, atomic_read(&intf->dev.power.usage_count),status);
}

●usb_autopm_put_interface执行和usb_autopm_get_interface相反的功能,让usage counter -1,如果usage counter =0,则进入autosuspend。
简单说,就是在驱动的open里调用usb_autopm_get_interface,在close里调用usb_autopm_put_interface,以此来实现usb的休眠唤醒功能。

回到前面的问题,usb_autopm_get_interface返回错误:-16,说明该usb camera的休眠唤醒有问题,camera无法被唤醒。根据网上的参考怀疑echi处于suspend状态导致camera无法正常open, 由于项目不需要考虑耗电,所以打算暂时去掉pm runtime的功能: #CONFIG_PM_RUNTIME is not set
尴尬的是,android 8.1上注掉CONFIG_PM_RUNTIME会导致kernel编译不过的,使用CONFIG_PM_RUNTIME宏控制的代码很多,这样修改的工作量很大。

继续检查代码,在usb_enumerate_device函数中注释掉port进入休眠就可以正常了:

static int usb_enumerate_device(struct usb_device *udev)
{int err;struct usb_hcd *hcd = bus_to_hcd(udev->bus);if (udev->config == NULL) {err = usb_get_configuration(udev);if (err < 0) {if (err != -ENODEV)dev_err(&udev->dev, "can't read configurations, error %d\n",err);return err;}}/* read the standard strings and cache them if present */udev->product = usb_cache_string(udev, udev->descriptor.iProduct);udev->manufacturer = usb_cache_string(udev,udev->descriptor.iManufacturer);udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);err = usb_enumerate_device_otg(udev);if (err < 0)return err;if (IS_ENABLED(CONFIG_USB_OTG_WHITELIST) && hcd->tpl_support &&!is_targeted(udev)) {/* Maybe it can talk to us, though we can't talk to it.* (Includes HNP test device.)*/if (IS_ENABLED(CONFIG_USB_OTG) && (udev->bus->b_hnp_enable|| udev->bus->is_b_host)) {//stone:注释掉usb的休眠//err = usb_port_suspend(udev, PMSG_AUTO_SUSPEND);if (err < 0)dev_dbg(&udev->dev, "HNP fail, %d\n", err);}return -ENOTSUPP;}usb_detect_interface_quirks(udev);return 0;
}

如果还是打不开,还需要考虑下应用的尺寸设置是否合适。

可以参考:https://www.kernel.org/doc/html/v4.16/driver-api/usb/power-management.html

高通平台android 8.1基线某款usb camera打开dev/video1出错相关推荐

  1. 高通android开源代码下载,高通平台Android源码bootloader分析之sbl1(三)

    前两篇博文分析了启动流程.代码流程.cdt,接下来就分析另外几个需要格外关注的部分. ##log系统 sbl1中的log系统也是sbl1部分调试会经常接触得部分高通平台在sbl中做的log系统并不是很 ...

  2. 高通平台android开发总结 MSM平台上的AMSS

    http://blog.csdn.net/mirkerson/article/details/7691029 MSM平台上的AMSS REX启动分析--基于Qualcomm平台 1.高通平台andro ...

  3. 高通平台android开发总结

    http://www.cnblogs.com/yuzaipiaofei/archive/2012/07/24/4124179.html 1.高通平台android开发总结 1.1 搭建高通平台环境开发 ...

  4. 高通平台 android 12 定时开关机

    高通平台 android 12 定时开关机 关机 关机实现 开机实现 总结 关机 AlarmManager取消了RTC_POWEROFF_WAKEUP 不支持通过AlarmManager设置关机唤醒设 ...

  5. 高通平台android 环境配置编译及开发经验总结

    完全转自:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

  6. 高通平台android开发总结 .

    http://blog.csdn.net/mirkerson/article/details/7691029 http://blog.csdn.net/mirkerson/article/detail ...

  7. 高通平台android 环境配置编译及开发经验总结【转】

    1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流 ...

  8. 高通平台Android源码bootloader分析之sbl1(一)

    高通8k平台的boot过程搞得比较复杂, 我也是前段时间遇到一些问题深入研究了一下才搞明白.不过虽然弄得很复杂,我们需要动的东西其实很少,modem侧基本就sbl1(全称:Secondary boot ...

  9. 高通平台android kernel 开机logo显示和传统linux一样

     由于高通8k平台lk下只有2s多点 故直接在kernel显示logo,这篇文章转载过来制作linux logo,其实这个当时学习就会,只不过忘记了.在这里重提一下ubuntu下的GIMP图片工具 ...

最新文章

  1. 切换执行等级的命令init
  2. html 左右选择框,jquery实现下拉框左右选择功能
  3. 程振波 算法设计与分析_算法分析与设计之动态规划
  4. 计算机office软件改为中文,计算机预装正版Office如何更改为64位程序
  5. 北京理工大学 python专题课程-Python语言程序设计
  6. linux文件目录含义,Linux中文件权限目录权限的意义及权限对文件目录的意义
  7. xterm远程连服务器连不上_VS Code Remote 发布!开启远程开发新时代
  8. 所有配置_明年起,所有新车都要强制增加一项配置!不安装可能会导致...
  9. 多校赛 Barareh on Fire
  10. ipython tesseract_python使用Tesseract库识别验证
  11. java中使用国密SM4算法详解
  12. 飘云阁内存补丁工具使用
  13. Java 设计模式——工厂模式
  14. Django 点击刷新验证码
  15. 正确的座机号码格式_电话号码的正确写法(我就知道你不知道)
  16. laravel框架中Cache缓存类中的原子锁
  17. Excel如何实现单元格内轻松换行?
  18. 聊聊关于使用逻辑斯蒂回归的使用方法
  19. 小米移动流量显示无服务器,小米移动电话卡详解!打电话、上网流量无敌
  20. 多行显示和单行显示溢出部分为...

热门文章

  1. 推荐下阿里巴巴开源的数据库客户端工具Chat2DB
  2. 一个小白对接电子面单的哪些坑?
  3. 当前 IT 行业,软件开发应该掌握的几种编程语言,你学会了几种?
  4. html背景图片拉伸解决办法
  5. 用css3风车转动动画代码
  6. banner生成图像的网站有哪些?
  7. java.jpi在线_JPI中常使用的类介绍:
  8. transact sql mysql_Sql Server数据库常用Transact-SQL脚本(推荐)
  9. 网络安全——攻防对抗
  10. 赠与今年的大学毕业生 (二)