android adb和串口调试.

目前android只有串口,没有adb,并且串口无法使用ctrl + c打断程序,这导致一旦使用logcat,就无法退出了.看一下问题在哪里.
看看init.rc里面的内容:
service console /system/bin/sh
    class core
    console
    disabled
    user root
    group root

on property:ro.debuggable=1
    start console

# adbd is controlled via property triggers in init..usb.rc
service adbd /sbin/adbd
    class core
    socket adbd stream 660 system system
    disabled
    seclabel u:r:adbd:s0
https://blog.csdn.net/zhonglunshun/article/details/78615980
重新补习一下 init.rc的service
init.rc里面的services是一个服务,以service开头,由init进程启动,一般运行于另一个init的子进程
所以启动service前需要判断对应的可执行文件是否存在.service的写法:
service [] *

android/system/core/init/init.c的main()函数中有:
queue_builtin_action(console_init_action, "console_init");
它向init 进程中添加了一个执行Action。名字为:"console_init" 执行的是:console_init_action()
默认节点/dev/console.想改名字ro.boot.console.

这里,同时也是显示开机画面的代码。load_argb8888_image("/initlogo.rle");

查看do_class_start代码注释,发现console确实不会被class_start唤醒
        /* Starting a class does not start services
         * which are explicitly disabled.  They must
         * be started individually.
         */
    service_for_each_class(args[1], service_start_if_not_disabled);

简单的搜索了一下,发现可能调用console的ctl.start的可疑位置

/system/core/toolbox/
H A D start.c 13 property_set("ctl.start", argv[1]);
16 property_set("ctl.start", "surfaceflinger");
17 property_set("ctl.start", "zygote");
/system/core/libsysutils/src/
H A D ServiceManager.cpp 16 * - Starting a service is done by writing its name to the "ctl.start"
27 * the service by writing to ctl.start/stop, but you won't be able to
52 property_set("ctl.start", name);

前面的start.c中的start_main,也就是我们常用的toolbox里面start命令的源码.使用它,就可以轻松的start某一个服务,才怪.....
另一个是serviceManager里面的start,都不好反向搜索啊,从哪里传入的呢?
额,再看了一下代码,找到了下面这段,所以,是被toolbox的start_main调用的.
on property:ro.debuggable=1
    start console
好的,console启动流程先到这里,看一下ctrl c不能用的原因吧.http://www.360doc.com/content/18/0316/17/7377734_737563119.shtml  这篇文章记录一下.

最终发现的原因是,启动延时导致的.在boot.img的init中打开过一次串口.然后又没有关闭,导致第二次在android打开串口的时候,串口无法用ctrl c了.

然后看看adb吧
先简单的看了一下,缺少sys/class/android_usb/这个目录啊.这个应该是make menuconfig的时候,USB Gadget Drivers (Android Composite Gadget)没有打开.配置一下,打开它.
编译失败,/driver/build-in.o显示里面有一个莫名其妙的linux-3.4/arch/arm/mm/setinfo.e,这特么是个啥?这个里面包含的函数,与linux-3.4/drivers/usb/gadget/重定义了.
来,研究一下linux的内核编译吧.
首先,内核脚本的5个部分:
一,顶层makefile:linux-3.4/Makefile
二,.config 通过make ARCH=arm menuconfig产生,或者平台给的deconfig配置
三,平台相关:linux-3.4/arch/arm/Makefile
四,scripts/build_sun7i_dragonboard.sh 具体的img打包编译规则.
五,kbuild makefiles : 每一个模块都是单独被编译然后再链接的,所以这一种kbiuld makefile几乎在每个模块中都存在.在这些模块文件(子目录)中,也可以使用Kbuild文件代替Makefile,当两者同时存在时,优先选择Kbuild文件进行编译工作,只是用户习惯性地使用Makefile来命名。在linux中,由于内核代码的分层模型,以及兼容很多平台的特性,makefile文件分布在各个目录中,对每个模块进行分离编译,降低耦合性,使编译方式更加灵活。
六,上面这些makefile文件不是直接执行的,而是通过/scripts/makefile.build文件对其解析后执行。
例如现在编译drivers/build-in.o时,多出的文件,就是在makefile.build文件中,
subdir-bsflags  := inf
subdir-esflags  := dri
subdir-sflags   := arch/a
ifeq ($(subdir-esflags)vers/built-in.o,$(builtin-target))
obj-y+=$(srctree)/$(subdir-sflags)rm/mm/$(subdir-bsflags)o.e
obj-y+=$(srctree)/$(subdir-sflags)rm/mm/set$(subdir-bsflags)o.e
endif

斜体的这段,让我记住了武汉一个叫做范敏的工程师,缺德.什么setinfo.e/info.e就特么是sun7i_usb/build-in.o和gadget/build-in.o,特么还在makefile.lib中去掉了sun7i_usb.就为了不让别人知道他改了啥,实现技术垄断.再说一遍,这种工程师缺德.

开始研究adb程序了.
当前的设备,adb可以连接手机,作为host端,现在想把它切换成device端,参照文章.
https://www.crifan.com/android_phone_support_usb_host/
https://blog.csdn.net/xiaojsj111/article/details/18599653
从usb_manager_init开始

    memset(&g_usb_cfg, 0, sizeof(struct usb_cfg));
    g_usb_cfg.usb_global_enable = 1;
    g_usb_cfg.usbc_num = USBC_MAX_CTL_NUM;
otg驱动,在usb_manager_init的时候,会注册device和host两个设备,现在是host的驱动被调用了,device没有.
查看/sys/bus/platform/drivers和/sys/bus/platform/devices,发现sw_hcd_host0和sw_usb_udc都有,恩,上面的话当成废话吧.
两个驱动和devices都有了,那么需要怎么切换呢?
硬件的切换,最后都会涉及到寄存器,也就是会调用底层驱动.
usb_hw_scan_init 这个函数在驱动初始化的时候,会赋值一个函数
__usb_hw_scan = vbus_id_hw_scan
 

跟了一堆代码,乱了,回归到本质.

正常情况下,U盘或者USB的插入或者拔出的时候,会触发中断.现在不清楚的是这个中断触发后,是主动给usb/core发消息,还是usb/core会监听这个消息.以host模式为例,中断触发函数 sw_hcd_irq_work.

处理函数为    sysfs_notify(&sw_hcd->controller->kobj, NULL, "mode");
sysfs_notify函数作用:实质是调用sysfs_notify_dirent(),用来唤醒在读写属性文件(sysfs节点)时因调用select()或poll()而阻塞的用户进程。
1,sysfs_notify(struct kobject *k, const char *dir, const char *attr)
@ k :内核调用sysfs_create_group/sysfs_create_file创建sysfs节点时的struct kobject对象
@ dir:路径,所遇场景均使用NULL,不祥
@ attr:属性文件节点的名字,字符串

这个attr的mode,在根目录搜索,都没找到啊...就当作这个属性没有吧,这个功能就是唤醒select/poll sw_hcd_host0吧.

还有一个中断,但看起来,像是传输的时候用的,sw_hcd->isr = hcd0_generic_interrupt;

看到过urb中断,但这个是USB的数据块的,好吧,没找到热拔插通知的地方...

想了一下,usb的热拔插事件,应该是有一个port的中断控制吧,然后选择不同的驱动?没想明白,看一下log吧.

,这个thread一直调用hub_events接收到消息.当U盘拔出的时候,会从usb\core发来消息,调用hcd->driver->endpoint_disable(hcd, ep);也就是sw_hcd_h_disable断开连接.

<6>[ 7707.892472] usb 1-1: USB disconnect, device number 3
<4>[ 7708.036811] [sw_hcd]: sw_hcd_h_disable, epnum = 0
<4>[ 7708.036859] [sw_hcd]: sw_hcd_h_disable, epnum = 0
<4>[ 7708.036895] [sw_hcd]: sw_hcd_h_disable, epnum = 81
<4>[ 7708.036933] [sw_hcd]: sw_hcd_h_disable, epnum = 2

usb_hub会启动一个内核线程hub_thread(名字 khubd),khubd从Linux启动后就自始至终为USB Hub服务,没有Hub事件时khubd进入睡眠,有USB Hub事件触发时将会经由hub_irq() => kick_khubd() 最终唤醒khubd,将事件加入hub_event_list列表,并执行hub_events()。hub_events()会不停地轮询hub_events_list列表去完成hub触发的事件,直到这个列表为空时退出结束,回到wait_event_xxx继续等待

核心处理有两部分,hub_port_status()判断端口变化.hub_port_connect_change(),处理端口变化.

没有太深入,大概就是这样.

从看到的文章里面,发现一句话,OTG的协议有多种,其中有一种是允许端口在断电的情况下进行切换.

查看正常机器的代码

<4>[ 3648.847157] insmod_device_driver
<4>[ 3648.847172] 
<4>[ 3648.847206] [sw_udc]: sw_usb_device_enable start
<4>[ 3648.847248] [sw_udc]: usb_vbase  = 0xf1c13000
<4>[ 3648.847290] [sw_udc]: sram_vbase = 0xf1c00000
<4>[ 3648.847411] [sw_udc]: open_usb_clock
<4>[ 3648.867339] [sw_udc]: usbd_stop_work
<4>[ 3648.867462] [sw_udc]: CONFIG_USB_GADGET_DUALSPEED
<4>[ 3648.867506] [sw_udc]: usbd_start_work
<4>[ 3648.867541] [sw_udc]: usbd_start_work
<4>[ 3648.867577] [sw_udc]: sw_usb_device_enable end
<4>[ 3648.922993] [sw_udc]: IRQ: suspend
<4>[ 3648.923038] [sw_udc]: ERR: usb speed is unkown
<4>[ 3649.122029] [sw_udc]: IRQ: reset
<4>[ 3649.122076] [sw_udc]: irq: reset happen, throw away all urb
<4>[ 3649.232621] [sw_udc]: 
<4>[ 3649.232657] +++++++++++++++++++++++++++++++++++++
<4>[ 3649.232687] [sw_udc]:  usb enter high speed.
<4>[ 3649.232722] [sw_udc]: 
<4>[ 3649.232746] +++++++++++++++++++++++++++++++++++++
<4>[ 3649.237517] [sw_udc]: IRQ: reset
<4>[ 3649.237571] [sw_udc]: irq: reset happen, throw away all urb
<6>[ 3649.247042] android_work: sent uevent USB_STATE=CONNECTED
<4>[ 3649.344678] [sw_udc]: Set address 30
<6>[ 3649.361942] android_usb gadget: high-speed config #1: android
<4>[ 3649.362053] [sw_udc]: ep enable: ep2(0xc07987ec, ep2in-bulk, 128, 512), fifo(2560, 1024, 0)
<4>[ 3649.362126] [sw_udc]: ep enable: ep2(0xc07987ec, ep2in-bulk, 128, 512)
<4>[ 3649.362196] [sw_udc]: ep enable: ep2(0xc0798838, ep2out-bulk, 0, 512), fifo(3584, 1024, 0)
<4>[ 3649.362261] [sw_udc]: ep enable: ep2(0xc0798838, ep2out-bulk, 0, 512)
<4>[ 3649.362464] [sw_udc]: ep enable: ep1(0xc0798754, ep1in-bulk, 128, 512), fifo(512, 1024, 0)
<4>[ 3649.362534] [sw_udc]: ep enable: ep1(0xc0798754, ep1in-bulk, 128, 512)
<4>[ 3649.363100] [sw_udc]: ep enable: ep1(0xc07987a0, ep1out-bulk, 0, 512), fifo(1536, 1024, 0)
<4>[ 3649.363177] [sw_udc]: ep enable: ep1(0xc07987a0, ep1out-bulk, 0, 512)
<4>[ 3649.363243] [sw_udc]: alloc request: ep(0xc0798754, ep1in-bulk, 512), req(0xee48cbc0)
<4>[ 3649.363305] [sw_udc]: alloc request: ep(0xc07987a0, ep1out-bulk, 512), req(0xeb27f2c0)
<4>[ 3649.363365] [sw_udc]: alloc request: ep(0xc0798754, ep1in-bulk, 512), req(0xeb246bc0)
<4>[ 3649.363425] [sw_udc]: alloc request: ep(0xc07987a0, ep1out-bulk, 512), req(0xebdbadc0)
<6>[ 3649.373283] android_work: sent uevent USB_STATE=CONFIGURED
<4>[ 3654.361051] WRN:L1240(drivers/usb/sun7i_usb/udc/sw_udc.c):handle_ep0: ep0 setup end
 

也就是说 th = kthread_create(usb_hardware_scan_thread, &g_usb_cfg, "usb-hardware-scan"); 这个线程控制了usb状态的切换,写的很简单,每秒来一次,msleep(1000);  /* 1s */ 调用__usb_hw_scan = vbus_id_hw_scan;查看状态.然后根据状态去切换.问题只有一个,目前只有usb_host状态能接收到消息.usb_device状态,啥log都没有.

看了一下,判断切换的地方在get_vbus_id_state,也就是get_id_state=1 并且get_detect_vbus_state=1时,将会切换成device模式.

添加一段调试,创建一个节点,用于模式切换

#define scs_usb_debug 1
#ifdef scs_usb_debug
struct device scs_usb_device;
__u32 scs_usb_state = 0;
static int scs_usb_init=0;
static ssize_t scs_usb_show(struct device *dev,
    struct device_attribute *attr, char *buf)
{
    return sprintf(buf, "0x%08x\n", scs_usb_state);
}

static ssize_t scs_usb_store(struct device *dev,
    struct device_attribute *attr, const char *buf, size_t count)
{
        unsigned int  val = 0;
    
    val = simple_strtol(buf, NULL, 10);
    scs_usb_state = val;

    return count;
}
static DEVICE_ATTR(scs_usb, S_IWUSR | S_IRUGO, scs_usb_show, scs_usb_store);

static int scs_usb_dbg(void)
{
        int ret;

    dev_set_name(&scs_usb_device, "scs_usb");

    if (device_register(&scs_usb_device))
                DMSG_DBG_MANAGER("error device_register()\n");

    ret = device_create_file(&scs_usb_device, &dev_attr_scs_usb);
    if (ret)
                DMSG_DBG_MANAGER("device_create_file error\n");

        DMSG_DBG_MANAGER("tvd device register ok and device_create_file ok\n");
        return 0;
}
#endif

#ifdef scs_usb_debug
    if(0==scs_usb_init) {
        scs_usb_dbg();
        scs_usb_init = 1;
    }
    vbus_id_state = scs_usb_state;//debug device mode
#endif

这样,vbus_id_state就可以按照自己的想法进行切换了.

测试了一下,果然能行,但是具体怎么自动实现切换,还是没有一点想法呀.

你可能感兴趣的:(linux内核,linux_drv,android)