Qualcomm usb modem驱动小结

前段时间再为我们公司的模块产品sim5210写linux下的驱动, sim5210使用的是qualcomm的6280芯片, 该平台提供了USB功能, 并再USB之上提供了modem, diag, nmea等设备接口, 即再usb之上我们的模块实现了modem功能, diag(诊断)功能, nmea(gps)功能, 由于在linux下有现成的标准CDC modem的驱动, 所以我们以此为参考实现了我们的非标准modem, 和用于收发at command的diag的驱动. 下面我们重点总结一下modem驱动的编写方法,  diag类似.

我们的modem驱动是tty+usb的层次关系, 即上层跟用户交互的接口使用tty驱动类型, 初始化时先注册一个设备文件, 以后用户使用时直接通过这个设备文件与设备打交道, 当用户的操作传递到我们的tty驱动层后, 在我们的驱动中在把这些操作(read, write)转化为对usb设备的操作, 最后通过usb总线与usb设备交互, 整个驱动结构如下:

下面详细讲解这个驱动的整个流程:

1 通过module_init() 和 module_exit()注册我们驱动的init和exit函数, init函数将会在驱动加载时被调用, exit函数将会在驱动卸载时被调用.

2 我们的init函数是

static int __init qcmdm_init()

{

/*1 调用alloc_tty_driver()分配一个tty_driver对象: qcmdm_tty_driver */

/*2 初始化qcmdm_tty_driver 的相关field*/

/*3 调用tty_set_operations 为qcmdm_tty_driver 设好操作函数表, 即tty驱动的函数表*/

/*4 调用tty_register_driver()把qcmdm_tty_driver注册到系统中去*/

/*调用usb_register()注册我们的usb驱动对象 qcmdm_usb_driver(静态分配并初始化好的)*/

return 0;

}

通过这一步, 我们注册了usb驱动对象, 和tty驱动对象, 但这时设备文件还没创建好,因此这个tty驱动还没法用, 当modem查上后linux内核会调用我们先前注册的usb驱动对象中的probe函数(整个调用流程可以参考我写的另一篇文章<<usb设备probe全过程>>)

我们的exit函数是:

static void __exit qcmdm_exit()

{

/*1 调用tty_unregister_driver() 来卸载qcmdm_tty_driver*/

/*2 调用put_tty_driver() 来释放qcmdm_tty_driver占用的内存*/

/*3 调用 usb_deregister()来下载qcmdm_usb_driver*/

}

3 我们qcmdm_usb_driver的probe函数:

static int qcmdm_probe(struct usb_interface *intf,  /*匹配的接口*/

const struct usb_device_id *id /*驱动支持的设备表项*/)

{

/*

1 根据设备的配置判断这个interface是否就是我们驱动支持的接口,

一般到了这步说明这个接口匹配了我们的device_id列表(这是我们驱动

提供的用于判断一个接口是否是我们驱动支持的这么一个列表), 但由于我们

的设备是个多接口的设备,所以这里还要进一步判断是否匹配,

*/

/*

2  检测设备的其他信息是否和我们的真是设备的信息匹配(如端点数量,端点类型等)

*/

/*

* 3 一般每个驱动都会定义一个记录我们设备信息的私有数据结构,我的驱动中定义的是

* strcut qcmdm,  这里我们分配一个qcmdm的对象mdm,并初始化好它的各个字段(如保存各个端点信息等)

*/

/*4 我们在mdm中保存了一个读和写的urb列表, 这里我们为每个urb分配内存(usb_alloc_urb), 并为每个每个urb分配DMA缓冲(usb_buffer_alloc). 并初始化好每个urb(usb_fill_xxx_urb())*/

/*5 调用tty_register_device() 来把qcmdm_tty_driver和这个interface绑定起来,并创建设备文件, 以后对这个设备文件的操作就会映射到qcmdm_tty_driver的操作函数.*/

}

此外,我们还可以在probe中保存额外的一些信息, 如调用usb_set_intfdata(intf, mdm)来将mdm保存在intf的相关字段中, 这样在以后使用中可以直接通过usb_get_intfdata()来获取mdm指针.

4我们qcmdm_usb_driver的disconnect函数(在设备拔出时调用): 这个函数主要做一些和probe相反的工作

static void qcmdm_disconnect(struct usb_interface *intf)

{

/*1 删除urb  (usb_kill_urb())*/

/*2  reset 读写list*/

/*3 释放相关资源, 如urb memory, usb dma memory等*/

/*4 调用tty_unregister_device()来释放驱动和设备的绑定,并删除设备文件*/

/*5 其他资源的释放或reset*/

}

总之在probe中申请了什么资源应该在disconnect中释放掉, 因为下次设备连上后,又会调用probe, 此时又会去分配资源.

5 打开函数: 这个函数是tty driver的一部分, 当打开我们创建的设备文件时会调用这个函数, 它的工作主要也是做一些初始化工作, 并调用usb_submit_urb()提交一个中断类型的urb(因为我们的设备上有个interrupt的端点, 用于设备上报一些自身状态的改变信息, 所以这里我们应该准备好接收这些状态信息)

6 write函数: 这也是tty driver的一部分, 在我们的驱动中保存了一个用于写usb的缓冲链表, 每次要写时就去获取一个空闲表项, 并把端点,数据等信息填充号这个表项中的urb, 特别的一般我们还会填充一个我们自己的用于完成后的回调函数. 然后调用usb_submit_urb提交这个写操作, 在usb写完或错误后会调用我们的回调函数(注意这是运行在中断上下文的), 这样我们就知道成功与否.

7 read函数:  这也是tty driver的一部分跟write相似,也有一个用于读的链表, 每个读操作也是先填充urb, 然后在提交,在完成后调用我们的回调函数, 此时我们得到了数据, 可以通过tty_insert_flip_string()和tty_flip_buffer_push()把数据提交到tty核心,在由tty核心交给用户. 由于在usb核心收到数据后应该快速的返回给用户, 因此在读的部分, 我们使用了tasklet, 以加快数据读出,又可避免直接在中断上下文读数据.

8 其他函数相对简单,在此不作介绍

Qualcomm usb modem驱动小结相关推荐

  1. 通用USB设备驱动源码分析

    通用USB设备驱动源码分析 Author:aaron 前段时间写了篇<qualcomm usb modem驱动小结>的文章, 描述了自己如何为高通的一个usb modem设备写驱动的过程, ...

  2. 淘宝cp210X提示“VeriFone USB Modem”无法匹配驱动

    淘宝cp210X提示"VeriFone USB Modem"无法匹配驱动 前段时间,在淘宝上买了cp210X usb转串口芯片,安装-调试板驱动CP210x-Windows-Dri ...

  3. Linux设备驱动之usb设备驱动详解

    原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316 1.Linux usb设备驱动框架 USB是通用串行总线的总称,Linu ...

  4. USB转串口驱动应用于macbook

    USB转串口驱动应用于macbook 查到的资料支持 macbook的为 Prolific(PL2303) 和 keyspan 卸载驱动的方法: rm -rf /System/Library/Exte ...

  5. 第八章 USB 设备驱动移植

    8.1 USB协议     USB协议系统主要组成,总线拓扑结构,内部层次关系,数据流模式,USB调度等等         8.1.1 主要组成部分             USB的连接部分,USB的 ...

  6. Linux usb设备驱动

    原文地址:http://blog.csdn.net/chenjin_zhong/article/details/6329316 1.Linux usb设备驱动框架 USB是通用串行总线的总称,Linu ...

  7. linux hub设备,Linux设备驱动之USB hub驱动(续)

    5.2.2:接口驱动中的hub_thread()函数 我们之前在分析usb_hub_init()的代码的时候,忽略掉了一部份. 代码片段如下所示: int usb_hub_init(void) { - ...

  8. Linux环境下使用 USB转串口驱动(二)

    minicom是linux下串口通信的软件,它的使用完全依靠键盘的操作,虽然没有"超级终端"那么易用,但是使用习惯之后读者将会体会到它的高效与便利,下面将讲解minicom的安装和 ...

  9. USB gadget 驱动之 android.c

    1. Gadget驱动 1.1 Gadget框架结构 kernel/drivers/usb/gadget,这个目录是android下usb gadget的主要目录. (1)Gadget功能组织单元:主 ...

最新文章

  1. 米勒罗宾素性测试(Miller–Rabin primality test)
  2. node.js初步认识
  3. WINDOWS高级窗口的客户区域拖动技术及其应用
  4. 你被人工智能给忽悠了吗?原来我们曾经认为的都是假的
  5. python 函数中所有print保存csv_python for循环print怎样才能输出csv呢
  6. 告别码公式的痛苦,公式OCR终于来了!
  7. 【Windows】Mathpix Snip-公式神器
  8. office软件提示“您的组织策略阻止我们进行该操作”错误的解决办法-终极汇总
  9. python中多态是什么意思_python类的多态是什么
  10. ASP.NET复习资料
  11. 麦吉尔大学 计算机科学和阿尔伯特,加拿大低龄留学-阿尔伯特学院-Albert College...
  12. 解决:No routes matched location “/“
  13. python求高阶导数_高阶导数 - 问答 - Python中文网
  14. windows通过浏览器远程连接Linux服务器的jupyter
  15. python爬虫app步骤_Python爬虫之App爬虫视频下载的实现
  16. Linux下自动重启系统
  17. 推荐系统-推荐引擎的架构
  18. lazarus ui设计_Golang绑定VCL和LCL组件
  19. matlab imagesc 坐标,[转载]matlab 中imagesc的用法
  20. 会计台式计算机使用年限,电脑等电子设备,使用年限必须是5年吗?残值 – 手机爱问...

热门文章

  1. 微信 html页面遮罩层,微信内网页提示浏览器打开代码——遮罩层提示代码实现!...
  2. 计算机机房分区,2021年高校计算机新建机房硬盘分区及软件安装计划硬盘分区教程win10.docx...
  3. 【R语言学习笔记】rep函数
  4. 【CSS用法】css限制一行文字数量,超出部分用省略号显示
  5. CF604B货物打包题解
  6. vue3 组件传值之 props 与 attrs 的区别
  7. 无线路由器接网线上网如何设置?
  8. linux中 gzip bizp2 xz zip怎么用,解压缩
  9. 如何去实现机械灵巧手玩魔方和弹钢琴_机械“影子手”上线!玩转魔方不在话下!...
  10. 小米运动显示同步到服务器失败,小米手环上的数据无法同步到手机APP上怎么办?解决方法看这里!...