ftdi_sio驱动学习笔记 3 - 端口操作

news2024/11/20 19:46:06

目录

1. ftdi_port_probe

1.1 私有数据结构ftdi_private

1.2 特殊probe处理

1.3 确定FTDI设备类型

1.4 确定最大数据包大小

1.5 设置读取延迟时间

1.6 初始化GPIO

1.6.1 使能GPIO

1.6.2 添加到系统

1.6.2.1 设置GPIO控制器的基本信息

1.6.2.2 设置GPIO控制器的元信息

1.6.3 GPIO实例

 2. ftdi_gpio_remove


int (*port_probe)(struct usb_serial_port *port): 端口探测函数ftdi_port_probe,用于初始化单个端口。

void (*port_remove)(struct usb_serial_port *port): 端口移除函数ftdi_port_remove
ftdi_port_remove,用于清理单个端口。

1. ftdi_port_probe

1.1 私有数据结构ftdi_private

这个结构是FTDI设备特有的,其实就是用来在驱动中传递参数用的。在这个结构体中定义了FTDI设备私有的一些变量。

struct ftdi_private *priv;
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv)
	return -ENOMEM;

这个私有数据是通过usb_set_serial_port_data放到port的私有数据保存。

usb_set_serial_port_data(port, priv);

1.2 特殊probe处理

和上一节一样,端口的probe处理也是有特殊的情况。这个结构体是通过port->serial传递的。

const struct ftdi_quirk *quirk = usb_get_serial_data(port->serial);
if (quirk && quirk->port_probe)
	quirk->port_probe(priv);

1.3 确定FTDI设备类型

result = ftdi_determine_type(port);
if (result)
	goto err_free;

 该类型是通过设备描述符中的bcdDevice来区别的。

version = le16_to_cpu(udev->descriptor.bcdDevice);

以FT4232H为例,该值可以在设备属性的硬件ID中查看到,如下图REV_0800 

case 0x800:
	priv->chip_type = FT4232H;
	break;

通过当前接口初始化通道编号,这只对多串口有意义(比如FT2232H和FT4232H)

#define CHANNEL_A		1
#define CHANNEL_B		2
#define CHANNEL_C		3
#define CHANNEL_D		4

ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
priv->channel = CHANNEL_A + ifnum;

而baud_base是指波特率产生器的参考时钟,默认设置的是H系列的值:120M的二分频。

priv->baud_base = 120000000 / 2;

最后是向设备节点发送消息,表明检测到了哪种类型的FTDI芯片。

dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);

在命令“sudo dmesg”返回结果中可以找到这句信息内容,例如:

[16005.322690] usb 2-1: Detected FT4232H

1.4 确定最大数据包大小

ftdi_set_max_packet_size(port);

这是从设备的端点描述符中获取设备端点最大数据包大小。这一步更像是检查FT232R的端点数据包最大值被客制为0的情况,当被改为0时数据包大小设置为64字节。

1.5 设置读取延迟时间

if (read_latency_timer(port) < 0)
	priv->latency = 16;
write_latency_timer(port);

这段代码的作用是确保设备的读取延迟时间被正确设置,如果无法获取当前的延迟时间,则会使用一个默认值进行设置。

获取这个参数是通过函数usb_control_msg_recv实现的。

int usb_control_msg_recv(struct usb_device *dev, __u8 endpoint, __u8 request,
		__u8 requesttype, __u16 value, __u16 index,
		void *driver_data, __u16 size, int timeout,
		gfp_t memflags)

对应的调用:

rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
			FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0,
			priv->channel, &buf, 1, WDR_TIMEOUT,
			GFP_KERNEL);

其中参数request和requesttype在ftdi_sio.h中有定义:

#define FTDI_SIO_GET_LATENCY_TIMER	0x0a /* Get the latency timer */
#define  FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER
#define  FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0

这属于FTDI定义的命令。

同样,写这个参数的命令是:

#define FTDI_SIO_SET_LATENCY_TIMER	9 /* Set the latency timer */
#define  FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER
#define  FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40

rv = usb_control_msg(udev,
			 usb_sndctrlpipe(udev, 0),
			 FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
			 FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
			 l, priv->channel,
			 NULL, 0, WDR_TIMEOUT);

1.6 初始化GPIO

这部分是利用了FTDI的CBUS实现USB转GPIO的功能。这一步是受内核配置CONFIG_GPIOLIB控制的,如果没有使能GPIOLIB,则没有这部分功能。

1.6.1 使能GPIO

由于不是所有的FTDI芯片都支持CBUS功能,所以前面有做芯片类型的判断,这里会引用这个变量分别处理。

switch (priv->chip_type) {
case FT232H:
	result = ftdi_gpio_init_ft232h(port);
	break;
case FT232R:
	result = ftdi_gpio_init_ft232r(port);
	break;
case FTX:
	result = ftdi_gpio_init_ftx(port);
	break;
default:
	return 0;
}

只有3类芯片支持CBUS功能,这里3个分支都是从芯片(或外置EEPROM)中读取CBUS配置信息使能CBUS脚。例如FT232H,一共有4个CBUS脚,分别为AC5,AC6,AC8和AC9,从eeprom的地址0x1a读入4个字节

ret = ftdi_read_eeprom(port->serial, buf, 0x1a, 4);
if (ret < 0)
	goto out_free;

每个GPIO由4位表示方向和电平。

/*
* FT232H CBUS Memory Map
*
* 0x1a: X- (upper nibble -> AC5)
* 0x1b: -X (lower nibble -> AC6)
* 0x1c: XX (upper nibble -> AC9 | lower nibble -> AC8)
*/
cbus_config = buf[2] << 8 | (buf[1] & 0xf) << 4 | (buf[0] & 0xf0) >> 4;

最后更新priv->gc.ngpio和gpio_altfunc,对应GPIO使能的话,gpio_altfunc对应的位清零

priv->gc.ngpio = 4;
priv->gpio_altfunc = 0xff;

for (i = 0; i < priv->gc.ngpio; ++i) {
	if ((cbus_config & 0xf) == FTDI_FTX_CBUS_MUX_GPIO)
		priv->gpio_altfunc &= ~BIT(i);
	cbus_config >>= 4;
}

1.6.2 添加到系统

这一步是通过标准的gpiochip的驱动API函数gpiochip_add_data实现。

priv->gc.label = "ftdi-cbus";
priv->gc.request = ftdi_gpio_request;
priv->gc.get_direction = ftdi_gpio_direction_get;
priv->gc.direction_input = ftdi_gpio_direction_input;
priv->gc.direction_output = ftdi_gpio_direction_output;
priv->gc.init_valid_mask = ftdi_gpio_init_valid_mask;
priv->gc.get = ftdi_gpio_get;
priv->gc.set = ftdi_gpio_set;
priv->gc.get_multiple = ftdi_gpio_get_multiple;
priv->gc.set_multiple = ftdi_gpio_set_multiple;
priv->gc.owner = THIS_MODULE;
priv->gc.parent = &serial->interface->dev;
priv->gc.base = -1;
priv->gc.can_sleep = true;

result = gpiochip_add_data(&priv->gc, port);
if (!result)
	priv->gpio_registered = true;

第一个参数priv->gc是配置好的`gpio_chip`结构体,第二个参数是该gpio_chip的私有数据,即实现接口参数的传递,例如:

static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset)
{
	struct usb_serial_port *port = gpiochip_get_data(gc);
1.6.2.1 设置GPIO控制器的基本信息
  • priv->gc.label: 设置GPIO控制器的标签为"ftdi-cbus"。
  • priv->gc.request: 设置请求GPIO引脚的函数为`ftdi_gpio_request`,用于在使用前申请GPIO资源。
  • priv->gc.get_direction: 设置获取GPIO引脚方向(输入或输出)的函数为`ftdi_gpio_direction_get`。
  • priv->gc.direction_input: 设置将GPIO引脚配置为输入模式的函数为`ftdi_gpio_direction_input`。
  • priv->gc.direction_output: 设置将GPIO引脚配置为输出模式的函数为`ftdi_gpio_direction_output`。
  • priv->gc.init_valid_mask: 设置初始化有效掩码的函数为`ftdi_gpio_init_valid_mask`,用于确定哪些GPIO引脚可以被使用。
  • priv->gc.get: 设置读取GPIO引脚状态的函数为`ftdi_gpio_get`。
  • priv->gc.set: 设置设置GPIO引脚状态的函数为`ftdi_gpio_set`。
  • priv->gc.get_multiple: 设置批量读取GPIO引脚状态的函数为`ftdi_gpio_get_multiple`。
  • priv->gc.set_multiple: 设置批量设置GPIO引脚状态的函数为`ftdi_gpio_set_multiple`。
1.6.2.2 设置GPIO控制器的元信息
  • priv->gc.owner: 设置拥有者为当前模块,表明这个GPIO控制器是由当前驱动程序管理的。
  • priv->gc.parent: 设置父设备为`serial->interface->dev`,这通常是一个USB设备或串口设备,表明GPIO控制器与之关联。
  • priv->gc.base: 设置GPIO引脚的起始编号为-1,实际值将在注册时由系统分配。
  • priv->gc.can_sleep: 设置为`true`表示这个GPIO控制器可以在睡眠状态下工作。

1.6.3 GPIO实例

例如使用FT232H,使用FT_PROG设置AC9为I/O Mode

在Linux中可以看到多一个gpiochip512的文件夹

/sys/class/gpio$ ls
export  gpiochip512  unexport
/sys/class/gpio/gpiochip512$ ls
base  device  label  ngpio  power  subsystem  uevent
/sys/class/gpio/gpiochip512$ cat label
ftdi-cbus
/sys/class/gpio/gpiochip512$ cat ngpio
4
/sys/class/gpio/gpiochip512$ cat base
512

可以看到一共分配了4个gpio,因为AC9是第四个GPIO,所以其GPIO编号应该为512 + 3 = 515.

/sys/class/gpio# echo "515" > /sys/class/gpio/export 
/sys/class/gpio# ls
export  gpio515  gpiochip512  unexport

注意,这里FT_PROG虽然只配置了一个GPIO,但是驱动层还是按照4个GPIO分配,如果暴露512可以看到返回错误:

/sys/class/gpio# echo "512" > /sys/class/gpio/export 
bash: echo: 写入错误:无效的参数

 2. ftdi_gpio_remove

这个函数将gpio移除和释放内存。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2165907.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Apache Iceberg 与 Spark整合-使用教程(Iceberg 官方文档解析)

官方文档链接&#xff08;Spark整合Iceberg&#xff09; 1.Getting Started Spark 目前是进行 Iceberg 操作最丰富的计算引擎。官方建议从 Spark 开始&#xff0c;以理解 Iceberg 的概念和功能。 The latest version of Iceberg is 1.6.1.&#xff08;2024年9月24日11:45:55&…

如何在云端使用 Browserless 进行网页抓取?

云浏览器是什么&#xff1f; 云浏览器是一种基于云的组合&#xff0c;它将网页浏览器应用程序与一个虚拟化的容器相结合&#xff0c;实现了远程浏览器隔离的概念。开发人员可以使用流行的工具&#xff08;如 Playwright 和​ Puppeteer​&#xff09;来自动化网页浏览器&#…

repo 查看指定日期内,哪些仓库有修改,具体的修改详情

文章目录 想看指定时间段内仓库中修改了哪些具体的文件&#xff0c;是谁修改的&#xff0c;commit的备注信息等详情只想看某段时间内有更改的仓库的修改详情&#xff0c;其他没有修改的仓库不显示。 想看指定时间段内仓库中修改了哪些具体的文件&#xff0c;是谁修改的&#xf…

VSCode#include头文件时找不到头文件:我的解决方法

0.前言 1.在学习了Linux之后&#xff0c;我平常大部分都使用本地的XShell或者VSCode连接远程云服务器写代码&#xff0c;CentOS的包管理器为我省去了不少繁琐的事情&#xff0c;今天使用vscode打开本地目录想写点代码发现#include头文件后&#xff0c;下方出现了波浪线&#…

SparkSQL-初识

一、概览 Spark SQL and DataFrames - Spark 3.5.2 Documentation 我们先看下官网的描述&#xff1a; SparkSQL是用于结构化数据处理的Spark模块&#xff0c;与基本的Spark RDD API不同。Spark SQL提供的接口为Spark提供了更多关于正在执行的数据和计算结构的信息。在内部&a…

C++中vector类的使用

目录 1.vector类常用接口说明 1.1默认成员函数 1.1.1构造函数(constructor) 1.1.2 赋值运算符重载(operator()) 2. vector对象的访问及遍历操作(Iterators and Element access) 3.vector类对象的容量操作(Capacity) 4. vector类对象的修改及相关操作(Modifiers and Stri…

【Java数据结构】 ---对象的比较

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 前言 上图中&#xff0c;线性表、堆…

[Redis][主从复制][上]详细讲解

目录 0.前言1.配置1.建立复制2.断开复制3.安全性4.只读5.传输延迟 2.拓扑1.一主一从结构2.一主多从结构2.树形主从结构 0.前言 说明&#xff1a;该章节相关操作不需要记忆&#xff0c;理解流程和原理即可&#xff0c;用的时候能自主查到即可主从复制&#xff1f; 分布式系统中…

PyTorch自定义学习率调度器实现指南

在深度学习训练过程中&#xff0c;学习率调度器扮演着至关重要的角色。这主要是因为在训练的不同阶段&#xff0c;模型的学习动态会发生显著变化。 在训练初期&#xff0c;损失函数通常呈现剧烈波动&#xff0c;梯度值较大且不稳定。此阶段的主要目标是在优化空间中快速接近某…

ResNet残差网络:深度学习的里程碑

引言 在深度学习领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;的发展一直推动着图像识别、目标检测等任务的进步。然而&#xff0c;随着网络层数的增加&#xff0c;传统的CNN面临着梯度消失和梯度爆炸等难题&#xff0c;限制了深层网络的训练效果。为了克服这些挑…

oracle direct path read处理过程

文章目录 缘起处理过程1.AWR Report 分析2.调查direct path read发生的table3.获取sql text4.解释sql并输出执行计划&#xff1a; 结论&#xff1a;补充direct path read等待事件说明 缘起 记录direct path read处理过程 处理过程 1.AWR Report 分析 问题发生时间段awr如下…

FortiGate OSPF动态路由协议配置

1.目的 本文档针对 FortiGate 的 OSPF 动态路由协议说明。OSPF 路由协议是一种 典型的链路状态(Link-state)的路由协议,一般用于同一个路由域内。在这里,路由 域是指一个自治系统,即 AS,它是指一组通过统一的路由政策或路由协议互相交 换路由信息的网络。在这个 AS 中,所有的 …

基于JSP+Servlet+Layui实现的博客系统

> 这是一个使用 Java 和 JSP 开发的博客系统&#xff0c;并使用 Layui 作为前端框架。 > 它包含多种功能&#xff0c;比如文章发布、评论管理、用户管理等。 > 它非常适合作为 Java 初学者的练习项目。 一、项目演示 - 博客首页 - 加载动画 - 右侧搜索框可以输入…

开源服务器管理软件Nexterm

什么是 Nexterm &#xff1f; Nexterm 是一款用于 SSH、VNC 和 RDP 的开源服务器管理软件。 安装 在群晖上以 Docker 方式安装。 在注册表中搜索 nexterm &#xff0c;选择第一个 germannewsmaker/nexterm&#xff0c;版本选择 latest。 本文写作时&#xff0c; latest 版本对…

【STM32】RTT-Studio中HAL库开发教程七:IIC通信--EEPROM存储器FM24C04

文章目录 一、简介二、模拟IIC时序三、读写流程四、完整代码五、测试验证 一、简介 FM24C04D&#xff0c;4K串行EEPROM&#xff1a;内部32页&#xff0c;每个16字节&#xff0c;4K需要一个11位的数据字地址进行随机字寻址。FM24C04D提供4096位串行电可擦除和可编程只读存储器&a…

Excel 设置自动换行

背景 版本&#xff1a;office 专业版 11.0 表格内输入长信息&#xff0c;发现默认状态时未自动换行的&#xff0c;找了很久设置按钮&#xff0c;遂总结成经验帖。 操作 1&#xff09;选中需设置的单元格/区域/行/列。 2&#xff09;点击【开始】下【对齐方式】中的【自动换…

HAproxy,nginx实现七层负载均衡

环境准备&#xff1a; 192.168.88.25 &#xff08;client&#xff09; 192.168.88.26 &#xff08;HAproxy&#xff09; 192.168.88.27 &#xff08;web1&#xff09; 192.168.88.28 (web2) 192.168.88.29 &#xff08;php1&#xff09; 192.168.88.30…

基于微信小程序的教学质量评价系统ssm(lw+演示+源码+运行)

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的教学质量评价系统的开发全过程。通过分析基于微信小程序的教学质量评价系统管理的不足&#xff0c;创建了一个计算机管理基于微信小程序的教学…

【Anti-UAV410】论文阅读

摘要 无人机在红外视频中的感知&#xff0c;对于有效反无人机是很重要的。现有的跟踪数据集存在目标大小和环境问题&#xff0c;不能完全表示复杂的逼真场景。因此作者就提出了Anti-UAV410数据集&#xff0c;该数据集总共410个视频和超过438K个标注框。为了应对复杂环境无人机跟…

丹摩智算(damodel)部署stable diffusion实验

名词解释&#xff1a; 丹摩智算&#xff08;damodel&#xff09;&#xff1a;是一款带有RTX4090&#xff0c;Tesla-P40等显卡的公有云服务器。 stable diffusion&#xff1a;是一个大模型&#xff0c;可支持文生图&#xff0c;图生图&#xff0c;文生视频等功能 一.实验目标 …