FBTFT源码逻辑分析

fbtft源码逻辑分析

  • 分析逻辑

分析逻辑

我们分析一个驱动模块,最重要的,也是最先的,就是找到它的probe函数,然后再根据probe中的逻辑去逐个分析其他函数源码。
通过查找,我们能在fbtft的源码中发现和probe有关的函数。
fbtft_device.c中

static int __init fbtft_device_init(void)
{
	struct spi_board_info *spi = NULL;
	struct fbtft_platform_data *pdata;
	bool found = false;
	int i = 0;
	int ret = 0;

	if (!name) { name是在模块载入时可设定的参数,指显示屏的名字
#ifdef MODULE
		pr_err("missing module parameter: 'name'\n");
		return -EINVAL;
#else
		return 0;
#endif
	}

	if (init_num > FBTFT_MAX_INIT_SEQUENCE) { init_num初始化命令长度
		pr_err("init parameter: exceeded max array size: %d\n",
		       FBTFT_MAX_INIT_SEQUENCE);
		return -EINVAL;
	}

	if (verbose > 2) { 打印所有支持显示屏的名字
		pr_spi_devices(); /* print list of registered SPI devices */
		pr_p_devices(); /* print list of 'fb' platform devices */
	}

	pr_debug("name='%s', busnum=%d, cs=%d\n", name, busnum, cs);

	if (rotate > 0 && rotate < 4) {
		rotate = (4 - rotate) * 90;
		pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
			rotate);
	}
	if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
		pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
			rotate);
		rotate = 0;
	}

	/* name=list lists all supported displays */
	if (strcmp(name, "list") == 0) {
		pr_info("Supported displays:\n");

		for (i = 0; i < ARRAY_SIZE(displays); i++)
			pr_info("%s\n", displays[i].name);
		return -ECANCELED;
	}

	if (custom) { 利用custom可以添加设备
		i = ARRAY_SIZE(displays) - 1;
		displays[i].name = name;
		if (speed == 0) {
			displays[i].pdev->name = name;
			displays[i].spi = NULL;
		} else {
			size_t len;

			len = strlcpy(displays[i].spi->modalias, name,
				      SPI_NAME_SIZE);
			if (len >= SPI_NAME_SIZE)
				pr_warn("modalias (name) truncated to: %s\n",
					displays[i].spi->modalias);
			displays[i].pdev = NULL;
		}
	}

	for (i = 0; i < ARRAY_SIZE(displays); i++) {
		if (strncmp(name, displays[i].name, SPI_NAME_SIZE) == 0) {
			if (displays[i].spi) {
				spi = displays[i].spi;
				spi->chip_select = cs;
				spi->bus_num = busnum;
				if (speed)
					spi->max_speed_hz = speed;
				if (mode != -1)
					spi->mode = mode;
				pdata = (void *)spi->platform_data;
			} else if (displays[i].pdev) {
				p_device = displays[i].pdev;
				pdata = p_device->dev.platform_data;
			} else {
				pr_err("broken displays array\n");
				return -EINVAL;
			}

			pdata->rotate = rotate;
			if (bgr == 0)
				pdata->bgr = false;
			else if (bgr == 1)
				pdata->bgr = true;
			if (startbyte)
				pdata->startbyte = startbyte;
			if (gamma)
				pdata->gamma = gamma;
			pdata->display.debug = debug;
			if (fps)
				pdata->fps = fps;
			if (txbuflen)
				pdata->txbuflen = txbuflen;
			if (init_num)
				pdata->display.init_sequence = init;
			if (custom) {
				pdata->display.width = width;
				pdata->display.height = height;
				pdata->display.buswidth = buswidth;
				pdata->display.backlight = 1;
			}

			if (displays[i].spi) {
				ret = fbtft_device_spi_device_register(spi);
				if (ret) {
					pr_err("failed to register SPI device\n");
					return ret;
				}
			} else {
				ret = platform_device_register(p_device);
				if (ret < 0) {
					pr_err("platform_device_register() returned %d\n",
					       ret);
					return ret;
				}
			}
			found = true;
			break;
		}
	}

	if (!found) {
		pr_err("display not supported: '%s'\n", name);
		return -EINVAL;
	}

	if (spi_device && (verbose > 1))
		pr_spi_devices();
	if (p_device && (verbose > 1))
		pr_p_devices();

	return 0;
}

arch_initcall(fbtft_device_init);

总之,在fbtft_device_init中会读取模块载入时用户设置的变量,存进platform_data供下一步使用,并称调用fbtft_device_spi_device_register向SPI子系统申请SPI设备。
然后我们可以发现,这里用的是arch_initcall(fbtft_device_init);,一般都是module_init

#define arch_initcall(fn)		__define_initcall(fn, 3)

#define module_init(x)  __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn)		__define_initcall(fn, 6)
都是调用arch_initcall,但是数字越小优先级越高,启动的时候就会优先启动

继续寻找

int fbtft_probe_common(struct fbtft_display *display,
		       struct spi_device *sdev,
		       struct platform_device *pdev)
{
	struct device *dev;
	struct fb_info *info;
	struct fbtft_par *par;
	struct fbtft_platform_data *pdata;
	int ret;

	if (sdev)
		dev = &sdev->dev;
	else
		dev = &pdev->dev;

	if (unlikely(display->debug & DEBUG_DRIVER_INIT_FUNCTIONS))
		dev_info(dev, "%s()\n", __func__);

	pdata = dev->platform_data; 获取fbtft_device设定的platform_data
	if (!pdata) { 如果没有就从设备树获取
		pdata = fbtft_probe_dt(dev);
		if (IS_ERR(pdata))
			return PTR_ERR(pdata);
	}

	info = fbtft_framebuffer_alloc(display, dev, pdata); 重点函数,提取信息设置到info里
	if (!info)
		return -ENOMEM;

	par = info->par;
	par->spi = sdev;
	par->pdev = pdev;

	if (display->buswidth == 0) {
		dev_err(dev, "buswidth is not set\n");
		return -EINVAL;
	}
    从这开始,设置一些默认的操作函数,例如:SPI写入8 Bits
	/* write register functions */
	if (display->regwidth == 8 && display->buswidth == 8)
		par->fbtftops.write_register = fbtft_write_reg8_bus8;
	else if (display->regwidth == 8 && display->buswidth == 9 && par->spi)
		par->fbtftops.write_register = fbtft_write_reg8_bus9;
	else if (display->regwidth == 16 && display->buswidth == 8)
		par->fbtftops.write_register = fbtft_write_reg16_bus8;
	else if (display->regwidth == 16 && display->buswidth == 16)
		par->fbtftops.write_register = fbtft_write_reg16_bus16;
	else
		dev_warn(dev,
			 "no default functions for regwidth=%d and buswidth=%d\n",
			 display->regwidth, display->buswidth);

	/* write_vmem() functions */
	if (display->buswidth == 8)
		par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
	else if (display->buswidth == 9)
		par->fbtftops.write_vmem = fbtft_write_vmem16_bus9;
	else if (display->buswidth == 16)
		par->fbtftops.write_vmem = fbtft_write_vmem16_bus16;

	/* GPIO write() functions */
	if (par->pdev) {
		if (display->buswidth == 8)
			par->fbtftops.write = fbtft_write_gpio8_wr;
		else if (display->buswidth == 16)
			par->fbtftops.write = fbtft_write_gpio16_wr;
	}

	/* 9-bit SPI setup */
	if (par->spi && display->buswidth == 9) {
		if (par->spi->master->bits_per_word_mask & SPI_BPW_MASK(9)) {
			par->spi->bits_per_word = 9;
		} else {
			dev_warn(&par->spi->dev,
				 "9-bit SPI not available, emulating using 8-bit.\n");
			/* allocate buffer with room for dc bits */
			par->extra = devm_kzalloc(par->info->device,
						  par->txbuf.len +
						  (par->txbuf.len / 8) + 8,
						  GFP_KERNEL);
			if (!par->extra) {
				ret = -ENOMEM;
				goto out_release;
			}
			par->fbtftops.write = fbtft_write_spi_emulate_9;
		}
	}

	if (!par->fbtftops.verify_gpios)
		par->fbtftops.verify_gpios = fbtft_verify_gpios;

	/* make sure we still use the driver provided functions */
	fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops);
从各显示屏设备文件中获取并覆盖原有的操作函数。
	/* use init_sequence if provided */
	if (par->init_sequence)
		par->fbtftops.init_display = fbtft_init_display;

	/* use platform_data provided functions above all */
	fbtft_merge_fbtftops(&par->fbtftops, &pdata->display.fbtftops);
从fbtft_device.c中获取并覆盖原有的操作函数。(实际上没有定义,这句无用)
	ret = fbtft_register_framebuffer(info);注册SPI设备,注册到用户空间,并且开始初始化,
	if (ret < 0)
		goto out_release;

	return 0;

out_release:
	fbtft_framebuffer_release(info);

	return ret;
}
EXPORT_SYMBOL(fbtft_probe_common);

这函数作用是,提取并储存之前fbtft_device.c里设置的变量,然后定义默认的操作函数,通过fbtft_merge_fbtftops覆盖原有的操作函数,最后在fbtft_register_framebuffer(info);注册SPI设备,注册到用户空间,并且开始初始化

接着再找找

#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display)                \
									   \
static int fbtft_driver_probe_spi(struct spi_device *spi)                  \
{                                                                          \
	return fbtft_probe_common(_display, spi, NULL);                    \
}                                                                          \
									   \
static int fbtft_driver_remove_spi(struct spi_device *spi)                 \
{                                                                          \
	struct fb_info *info = spi_get_drvdata(spi);                       \
									   \
	return fbtft_remove_common(&spi->dev, info);                       \
}                                                                          \
									   \
static int fbtft_driver_probe_pdev(struct platform_device *pdev)           \
{                                                                          \
	return fbtft_probe_common(_display, NULL, pdev);                   \
}                                                                          \
									   \
static int fbtft_driver_remove_pdev(struct platform_device *pdev)          \
{                                                                          \
	struct fb_info *info = platform_get_drvdata(pdev);                 \
									   \
	return fbtft_remove_common(&pdev->dev, info);                      \
}                                                                          \
									   \
static const struct of_device_id dt_ids[] = {                              \
	{ .compatible = _compatible },                                     \
	{},                                                                \
};                                                                         \
									   \
MODULE_DEVICE_TABLE(of, dt_ids);                                           \
									   \
									   \
static struct spi_driver fbtft_driver_spi_driver = {                       \
	.driver = {                                                        \
		.name   = _name,                                           \
		.of_match_table = of_match_ptr(dt_ids),                    \
	},                                                                 \
	.probe  = fbtft_driver_probe_spi,                                  \
	.remove = fbtft_driver_remove_spi,                                 \
};                                                                         \
									   \
static struct platform_driver fbtft_driver_platform_driver = {             \
	.driver = {                                                        \
		.name   = _name,                                           \
		.owner  = THIS_MODULE,                                     \
		.of_match_table = of_match_ptr(dt_ids),                    \
	},                                                                 \
	.probe  = fbtft_driver_probe_pdev,                                 \
	.remove = fbtft_driver_remove_pdev,                                \
};                                                                         \
									   \
static int __init fbtft_driver_module_init(void)                           \
{                                                                          \
	int ret;                                                           \
									   \
	ret = spi_register_driver(&fbtft_driver_spi_driver);               \
	if (ret < 0)                                                       \
		return ret;                                                \
	return platform_driver_register(&fbtft_driver_platform_driver);    \
}                                                                          \
									   \
static void __exit fbtft_driver_module_exit(void)                          \
{                                                                          \
	spi_unregister_driver(&fbtft_driver_spi_driver);                   \
	platform_driver_unregister(&fbtft_driver_platform_driver);         \
}                                                                          \
									   \
module_init(fbtft_driver_module_init);                                     \
module_exit(fbtft_driver_module_exit);

这个就比较简单了,生成一系列模块加载的模板

总结一下,fbtft_device先会调用fbtft_device_init,解析fbtft_device.c中的fbtft_device_display displays[]中的参数,同时也接受模块加载时用户指定的参数
如:modprobe fbtft_device name=admatec_c-berry28 speed=32000000 debug=7
最重要的是,将这些数据存进platform_data中。
然后在fbtft_probe_common()中,取出这些数据,用于设置fb_info,然后注册fb_info,以及spi写入等函数。
总体上来看,fb_tft的源码简单,逻辑清晰。
这里没有进一步深入分析fb_tft模块内底层控制SPI的和FB的函数,因为展开实在是太多了。fb_tft模块的逻辑很清晰,有兴趣的可以期待我第二批FBTFT源码分析,我会在下一篇编写"FBTFT"最小单元,实现FB到SPI的映射,从底层分析FBTFT的FB和SPI的控制函数。

你可能感兴趣的:(全志H3踩坑之旅,linux,arm,嵌入式)