Chinaunix首页 | 论坛 | 博客
  • 博客访问: 184528
  • 博文数量: 13
  • 博客积分: 265
  • 博客等级: 二等列兵
  • 技术积分: 402
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-16 17:19
文章分类

全部博文(13)

文章存档

2014年(2)

2013年(2)

2012年(9)

我的朋友

分类: LINUX

2012-10-18 18:34:47

  1. HAL层(system/bluetooth/bluedroid/bluetooth.c, function: bt_enable(), property_set("ctl.start", "hciattach"))
  2.                 |
  3.                 | 给电之后,启动注册在init.rc里面的hciattach daemon
  4.                 |           
  5. bluez(external/bluetooth/bluez/tools/hciattach.c)
  6.                 |
  7.                 | 打开制定的tty设备,然后做一些通用的设置,并且通过ioctl发送两个命令
  8.                 | TIOCSETD和HCIUARTSETPROTO
  9.                 | 去将设备注册到hci设备中(h4和bcsp,走的是ldisc机制)
  10.                 |
  11. kernel hci层(net/bluetooth/hci_socket.c,hci_core.c)
  12.                 |
  13.                 | 收到HCIDEVUP指令通过hci_dev_open打开设备,调用hdev->open(hci_uart_open,
  14.                 | hci_uart_register_dev时候指定的方法),并且通过__hci_request调用hci_init_req
  15.                 | 去调用一系列的hci_send_cmd发送各种命令,主要是读各种配置以及设置一些基本参数
  16.                 | __hci_request设置了睡眠,它是一个阻塞函数
  17.                 |
  18. kernel hci层(net/bluetooth/hci_core.c),hci_send_cmd
  19.                 |
  20.                 | 调用tasklet_schedule(&hdev->cmd_task)唤起cmd_task,cmd_task在执行
  21.                 | HCIUARTSETPROTO命令时已经设置好了的
  22.                 |
  23. kernel hci层(net/bluetooth/hci_core.c),hci_cmd_task
  24.                 |
  25.                 | 调用hci_send_frame将命令发送给硬件。hci_send_frame见后面的数据发送流程
  26.                 | 数据收到后会通过中断调起数据接收流程,具体流程也见后面。然后进行一系列的处理
  27.                 | (hci_rx_task->hci_event_packet)最后调起hci_req_complete,用wake_up_interruptible                 | 唤醒前面__hci_request设置的睡眠

一共有3个ioctl命令,TIOCSETD和HCIUARTSETPROTO在hciattach.c里面,通过open命令调用 drivers/tty/tty_io.c以及对应的ioctl,具体见下面描述。 HCIDEVUP在bluetooth.c里面,通过socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)发出,BTPROTO_HCI对应的hci_socket.c的ioctl处理。af_bluetooth.c在初始化的时候就 注册了三种proto的socket:hci,l2cap和sco.


TIOCSETD处理流程

  1. tty core(drivers/tty/tty_io.c,function: tty_ioctl调用tiocsetd,传入的参数是hci对应的 discipline id,N_HCI)
  2.                         |
  3. tty ldisc(drivers/tty/tty_ldisc.c,tty_set_ldisc: 1)根据id找ops,ops是在子ldisc初始化时注册到 tty_ldisc.c里面的一个tty_ldisc_ops数组 2) alloc一个ldisc,将前面找到的op设给这个ldisc 3) 通过tty_ldisc_assign将这个ldisc设给tty结构体. 从此,以后对应的函数都是调用子ldisc里面的tty_ldisc_ops函数来处理)
  4.                         |
  5. hci uart(drivers/bluetooth/hci_ldisc.c)


HCIUARTSETPROTO处理流程

  1. tty core(drivers/tty/tty_io.c,function: tty_ioctl调用ld = tty_ldisc_ref_wait(tty); ld->ops->ioctl())
  2.                          |
  3.                          |
  4. hci uart(drivers/bluetooth/hci_ldisc.c,通过init函数注册到tty_ldisc中的, 对应的id是N_HCI.函数hci_uart_tty_ioctl调用hci_uart_set_proto)
  5.                          |
  6.                          | 调用在h4_init或者bcsp_init里面注册的设备的open命令,具体调用哪个open
  7.                          | 取决于hciattach.c里面uart数组对应的定义。
  8.                          | open完了之后通过hci_uart_register_dev alloc一个hci_dev
  9.                          |
  10. hci core(net/bluetooth/hci_core.c,function:hci_register_dev,这里面做的事情比较多,初始化了 3个tasklet(发送,接收以及命令),注册hci设备对应的sysfs,以及注册了该hci设备对应的rfkill,到这一步, 底层的蓝牙虚拟设备hci0就可以通过hciconfig命令看到了


由上面可以看到,一个子uart模块在初始化的时候,应该干这么几件事:

  • 1)通过tty_register_ldisc(id, &tty_ldisc_op)将ops写到tty_ldisc的数组里面,并且子ldisc要实现这么一个hci_uart_proto的数组
  • 2)通过xxx_uart_register_proto(&hci_uart_proto)写到子ldisc的hci_uart_proto数组里面

一旦hci_register_dev完成,也就是hci层加进来以后,HAL层所有的操作都将通过hci-->proto-->ldisc-->tty这么一个流程。

阅读(7188) | 评论(0) | 转发(4) |
给主人留下些什么吧!~~