linux设备驱动之平台总线实践环节(二)

1、上一节中,我们将初步的驱动代码写完后编译后,放入到rootfs中进行insmod时,在/sys/bus/platform/drvier/目录中能够看到why_led这个目录,但是进入后只有一些基本的东西,却没有能使用这个led驱动的关键性东西,那是因为我们没有提供platform_device,并且驱动代码中的probe函数remove函数的代码内容也不对。这一节课中,做另一半,就是platform_device这一部分。

2、做platform_device这一半

参考mach-mini2440.c中添加led的platform_device定义来自己进行做platform_device

(1)首先检查mach-x210.c中是否有led相关的platform_device

看下mach-x210.c中的platform_device结构体数组,这个结构体数组中包含的是x210开发板中所有的platform_device,代码如下

static struct platform_device *smdkc110_devices[] __initdata = {
#ifdef CONFIG_FIQ_DEBUGGER
	&s5pv210_device_fiqdbg_uart2,
#endif
#ifdef CONFIG_MTD_ONENAND
	&s5pc110_device_onenand,
#endif
#ifdef CONFIG_MTD_NAND
	&s3c_device_nand,
#endif
	&s5p_device_rtc,
#ifdef CONFIG_SND_S3C64XX_SOC_I2S_V4
	&s5pv210_device_iis0,
	&s5pv210_device_iis1,
#endif
#ifdef CONFIG_SND_S3C_SOC_AC97
	&s5pv210_device_ac97,
#endif
#ifdef CONFIG_SND_S3C_SOC_PCM
	&s5pv210_device_pcm0,
#endif
#ifdef CONFIG_SND_SOC_SPDIF
	&s5pv210_device_spdif,
#endif
	&s3c_device_wdt,

#ifdef CONFIG_FB_S3C
	&s3c_device_fb,
#endif
#ifdef CONFIG_DM9000
	&s5p_device_dm9000,
#endif

#ifdef CONFIG_VIDEO_MFC50
	&s3c_device_mfc,
#endif
#ifdef CONFIG_TOUCHSCREEN_S3C
	&s3c_device_ts,
#endif
	&s3c_device_keypad,
#ifdef CONFIG_S5P_ADC
	&s3c_device_adc,
#endif
#ifdef CONFIG_VIDEO_FIMC
	&s3c_device_fimc0,
	&s3c_device_fimc1,
	&s3c_device_fimc2,
#endif
#ifdef CONFIG_VIDEO_FIMC_MIPI
	&s3c_device_csis,
#endif
#ifdef CONFIG_VIDEO_JPEG_V2
	&s3c_device_jpeg,
#endif
#ifdef CONFIG_VIDEO_G2D
	&s3c_device_g2d,
#endif
#ifdef CONFIG_VIDEO_TV20
	&s5p_device_tvout,
	&s5p_device_cec,
	&s5p_device_hpd,
#endif

	&s3c_device_g3d,
	&s3c_device_lcd,

	&s3c_device_i2c0,
#ifdef CONFIG_S3C_DEV_I2C1
	&s3c_device_i2c1,
#endif
#ifdef CONFIG_S3C_DEV_I2C2
	&s3c_device_i2c2,
#endif

#ifdef CONFIG_USB_EHCI_HCD
	&s3c_device_usb_ehci,
#endif
#ifdef CONFIG_USB_OHCI_HCD
	&s3c_device_usb_ohci,
#endif

#ifdef CONFIG_USB_GADGET
	&s3c_device_usbgadget,
#endif
#ifdef CONFIG_USB_ANDROID
	&s3c_device_android_usb,
#ifdef CONFIG_USB_ANDROID_MASS_STORAGE
	&s3c_device_usb_mass_storage,
#endif
#ifdef CONFIG_USB_ANDROID_RNDIS
	&s3c_device_rndis,
#endif
#endif
#ifdef CONFIG_BATTERY_S3C
	&sec_device_battery,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC
	&s3c_device_hsmmc0,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC1
	&s3c_device_hsmmc1,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC2
	&s3c_device_hsmmc2,
#endif
#ifdef CONFIG_S3C_DEV_HSMMC3
	&s3c_device_hsmmc3,
#endif

#ifdef CONFIG_S3C64XX_DEV_SPI
	&s5pv210_device_spi0,
	&s5pv210_device_spi1,
#endif
#ifdef CONFIG_S5PV210_POWER_DOMAIN
	&s5pv210_pd_audio,
	&s5pv210_pd_cam,
	&s5pv210_pd_tv,
	&s5pv210_pd_lcd,
	&s5pv210_pd_g3d,
	&s5pv210_pd_mfc,
#endif

#ifdef CONFIG_HAVE_PWM
	&s3c_device_timer[0],
	&s3c_device_timer[1],
	&s3c_device_timer[2],
	&s3c_device_timer[3],
#endif

//	&timed_gpio_device,

	&headset_switch_device,
};

这个platform_device结构体数组中每个元素都是x210开发板中的platform_device,我们可以看下这个里面有没led的platform_device,这里面没有,说明九鼎做的led设备是用的另外一套机制,并不是用的platform_device可能。这个platform_device结构体数组肯定是要用platform的注册方法将这些设备注册到platform总线下的。注册到平台总线方法,九鼎用的是

platform_add_devices(smdkc110_devices, ARRAY_SIZE(smdkc110_devices));

函数,这个platform_add_devices函数就是将数组中的所有设备进行注册到平台总线下的,这个函数的详细内容为

int platform_add_devices(struct platform_device **devs, int num)
{
	int i, ret = 0;

	for (i = 0; i < num; i++) {
		ret = platform_device_register(devs[i]);
		if (ret) {
			while (--i >= 0)
				platform_device_unregister(devs[i]);
			break;
		}
	}

	return ret;
}

platform_add_devices函数中通过platform注册设备使用的专用函数platform_device_register进行注册,devs形参就是platform_device的结构体数组。从代码中可以看出九鼎的设计逻辑是将platform_device结构体数组中的所有设备进行注册到平台总线下,只要有一个设备注册到平台总线失败了,那么就会将已经注册的设备全部注销掉,可以知道这是九鼎的一个错误处理机制。

其中没有确实没有led的platform_device,也就是九鼎确使用的是另外一个机制,用的并不是platform_device,所以我们可以仿造mach-mini2440.c中led的platform_device来实现一个s5pv210的led的platform_device,下面说一下参照mach-mini2440.c中实现的led的platform_device来实现s5pv210的led的platform_device。

在mach-mini2440.c中一些其他的数据结构如

static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = {
	[0] = {	/* mini2440 + 3.5" TFT + touchscreen */
		_LCD_DECLARE(
			7,			/* The 3.5 is quite fast */
			240, 21, 38, 6, 	/* x timing */
			320, 4, 4, 2,		/* y timing */
			60),			/* refresh rate */
		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
				   S3C2410_LCDCON5_INVVLINE |
				   S3C2410_LCDCON5_INVVFRAME |
				   S3C2410_LCDCON5_INVVDEN |
				   S3C2410_LCDCON5_PWREN),
	},
	[1] = { /* mini2440 + 7" TFT + touchscreen */
		_LCD_DECLARE(
			10,			/* the 7" runs slower */
			800, 40, 40, 48, 	/* x timing */
			480, 29, 3, 3,		/* y timing */
			50),			/* refresh rate */
		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
				   S3C2410_LCDCON5_INVVLINE |
				   S3C2410_LCDCON5_INVVFRAME |
				   S3C2410_LCDCON5_PWREN),
	},
	/* The VGA shield can outout at several resolutions. All share 
	 * the same timings, however, anything smaller than 1024x768
	 * will only be displayed in the top left corner of a 1024x768
	 * XGA output unless you add optional dip switches to the shield.
	 * Therefore timings for other resolutions have been ommited here.
	 */
	[2] = {
		_LCD_DECLARE(
			10,
			1024, 1, 2, 2,		/* y timing */
			768, 200, 16, 16, 	/* x timing */
			24),	/* refresh rate, maximum stable,
				 tested with the FPGA shield */
		.lcdcon5	= (S3C2410_LCDCON5_FRM565 |
				   S3C2410_LCDCON5_HWSWP),
	},
};

static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
	.displays	 = &mini2440_lcd_cfg[0], /* not constant! see init */
	.num_displays	 = 1,
	.default_display = 0,

	/* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
	 * and disable the pull down resistors on pins we are using for LCD
	 * data. */

	.gpcup		= (0xf << 1) | (0x3f << 10),

	.gpccon		= (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |
			   S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
			   S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |
			   S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |
			   S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),

	.gpccon_mask	= (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |
			   S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |
			   S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
			   S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
			   S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),

	.gpdup		= (0x3f << 2) | (0x3f << 10),

	.gpdcon		= (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |
			   S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |
			   S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |
			   S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
			   S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
			   S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),

	.gpdcon_mask	= (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |
			   S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |
			   S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |
			   S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
			   S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
			   S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
};

static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = {
   .gpio_detect   = S3C2410_GPG(8),
   .gpio_wprotect = S3C2410_GPH(8),
   .set_power     = NULL,
   .ocr_avail     = MMC_VDD_32_33|MMC_VDD_33_34,
};

static struct mtd_partition mini2440_default_nand_part[] __initdata = {
	[0] = {
		.name	= "u-boot",
		.size	= SZ_256K,
		.offset	= 0,
	},
	[1] = {
		.name	= "u-boot-env",
		.size	= SZ_128K,
		.offset	= SZ_256K,
	},
	[2] = {
		.name	= "kernel",
		/* 5 megabytes, for a kernel with no modules
		 * or a uImage with a ramdisk attached */
		.size	= 0x00500000,
		.offset	= SZ_256K + SZ_128K,
	},
	[3] = {
		.name	= "root",
		.offset	= SZ_256K + SZ_128K + 0x00500000,
		.size	= MTDPART_SIZ_FULL,
	},
};

static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = {
	[0] = {
		.name		= "nand",
		.nr_chips	= 1,
		.nr_partitions	= ARRAY_SIZE(mini2440_default_nand_part),
		.partitions	= mini2440_default_nand_part,
		.flash_bbt 	= 1, /* we use u-boot to create a BBT */
	},
};

static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
	.tacls		= 0,
	.twrph0		= 25,
	.twrph1		= 15,
	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets),
	.sets		= mini2440_nand_sets,
	.ignore_unset_ecc = 1,
};

上面这些等等代码,都是mini2440这个开发板中的platform_device设备的数据部分,按照之前学的platform总线逻辑,这些platform_device的数据部分都会被绑定到platform_device结构体中的device结构体的platform_data成员中。

下面说正式的话题,参考mini-2440.c中led的platform_device移植s5pv210的led的platform_device

首先找到mach-mini2440.c中led的platform_device,代码如下

static struct platform_device mini2440_led1 = {
	.name		= "s3c24xx_led",
	.id		= 1,
	.dev		= {
		.platform_data	= &mini2440_led1_pdata,
	},
};

找到mach-mini2440.c中led的platform_device后,我们将这个led的platform_device的变量名改为x210名字,数据部分的platform_data改为我们x210_led_pdata,后面我们还要提供x210_led_pdata这个数据结构的实现,id为1来区分这个led为第一个led,如果id为-1,则是让内核来给我们板子上的led设备分配编号,其中.name成员要和我们驱动中实现的那个led的驱动代码中的数据结构体也就是platform_driver中的name一样,因为我的led的platform_driver结构体中name为why_led,所以这里led的platform_device数据结构体中的name也要为why_led,不然将设备和驱动进行匹配的时候,platform总线的match函数无法将总线下的设备和驱动进行匹配上,因为设备和驱动的匹配用的是名字来进行匹配的。

最后我们仿造mini2440的led的platform_device,将我们x210的led的platform_device,x210是核心板,s5pv210是SoC,改完led的platform_device结构体为

static struct platform_device x210_led1 = {
	.name		= "why_led",
	.id		= 1,
	.dev		= {
		.platform_data	= &x210_led1_pdata,
	},
};

接下来我们要提供x210_led1_pdata这个绑定到platform_device结构体中的device成员结构体中的platform_data的数据结构。我们可以仿造mini2440中为led设备提供的数据部分platform_data的数据结构mini2440_led1_pdata,来实现我们x210的led的设备数据部分platform_data的数据结构x210_led1_pdata,我们看下mini2440的led设备的数据部分platform_data的数据结构

static struct s3c24xx_led_platdata mini2440_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

我们仿造上面的,将变量名字改为x210_led1_pdata,成员中的gpio、flags、def_trigger都需要根据我们x210板子的硬件情况来进行更改,比如这个led1的gpio对应的是哪个,flags属性有没有,def_trigger这个led1作为什么用。我们先不管这个led1的gpio对应的是哪,也不管flags属性,也不管def_trigger,先把框架改完,其中涉及到的硬件后续在改,仿造mini2440的led的platform_device的platform_data,我们初步将x210的led设备platform_device的platform_data数据部分的数据结构改为

static struct s3c24xx_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

这个时候看下我们有了什么东西,这个时候我们有了x210的led的platform_device数据结构,并且也有了x210的led的platform_devoce数据结构中需要的led设备的数据部分platform_data,如下

static struct s3c24xx_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

static struct platform_device x210_led1 = {
	.name		= "why_led",
	.id		= 1,
	.dev		= {
		.platform_data	= &x210_led1_pdata,
	},
};

x210_led1为x210的led设备的platform_device结构体变量,成员.platform_data绑定的x210_led1_pdata数据结构为x210_led1这个led设备的数据部分,表示这个led的gpio引脚是哪个,属性是什么,这个led用来做什么,当然我们这里目前关于led设备的数据部分x210_led1_pdata填写的还不对.

在mach-mini2440.c中的struct s3c24xx_led_platdata这个结构体类型是被声明在内核源码目录下的/arch/arm/mach-s3c2410/include/mach/leds-gpio.h中的,因为我们是为x210的led设备加入设备的数据部分platform_data,所以我们不能要将platform_data要绑定的结构体类型定义在mach-s5pv210/include/mach/目录下,我们可以自己在mach-s5pv210/include/mach/目录下创建一个头文件leds-gpio.h,先将mach-mini2440/include/mach/leds-gpio.h中的内容拷贝到我们的mach-s5pv210/include/mach/目录下的led-gpio.h中,然后在做修改,mach-mini2440/include/mach/leds-gpio.h中的内容为

*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
*/

#ifndef __ASM_ARCH_LEDSGPIO_H
#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h"

#define S3C24XX_LEDF_ACTLOW	(1<<0)		/* LED is on when GPIO low */
#define S3C24XX_LEDF_TRISTATE	(1<<1)		/* tristate to turn off */

struct s3c24xx_led_platdata {
	unsigned int		 gpio;
	unsigned int		 flags;

	char			*name;
	char			*def_trigger;
};

#endif /* __ASM_ARCH_LEDSGPIO_H */

我们先将这个内容拷贝到我们的/arch/arm/mach-s5v210/include/mach/leds-gpio.h中,然后在做更改,我们将这个将来绑定到platform_data中的结构体名字改为x210名字,内容改完后如下

*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
*/

#ifndef __ASM_ARCH_LEDSGPIO_H
#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h"

#define S5PV210_LEDF_ACTLOW	(1<<0)		/* LED is on when GPIO low */
#define S5PV210_LEDF_TRISTATE	(1<<1)		/* tristate to turn off */

struct s5pv210_led_platdata {
	unsigned int		 gpio;
	unsigned int		 flags;

	char			*name;
	char			*def_trigger;
};

#endif /* __ASM_ARCH_LEDSGPIO_H */

这个时候因为我们将将来绑定到platform_data的数据结构的类型名变成s5pv210_led_platdata了,所以我们前面定义填充的x210的led的platform_data也要改成s5pv210_led_platdata,改动方法,将

static struct s3c24xx_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

改为

static struct s5pv210_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

这时我们的x210的led的platform_device和platform_data为

static struct s5pv210_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

static struct platform_device x210_led1 = {
	.name		= "why_led",
	.id		= 1,
	.dev		= {
		.platform_data	= &x210_led1_pdata,
	},
};

同时我们要在上面代码所在的文件中包含我们刚才创建的头文件

#include<mach/leds-gpio.h>

好啦,接下来我们将x210的led的设备数据部分platform_data也就是x210_led_pdata这个结构体中的内容按照x210的硬件实际情况进行修改,没有改动之前的x210的led的platform_data为

static struct s5pv210_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S3C2410_GPB(5),
	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
	.def_trigger	= "heartbeat",
};

我们将gpio进行更改为x210中这个led实际对应的引脚,引脚为S5PV210_GPJ0(3),flags是一种扩展属性,我们可以加上,也可以不加上,def_tigger是来表示我们这个led用来做什么的,我们可以先不考虑这个,将def_trigger赋值为空字符"",最后改完的x210的led的platform_device和platform_data为

static struct s5pv210_led_platdata x210_led1_pdata = {
	.name		= "led1",
	.gpio		= S5PV210_GPJ0(5),
	.flags		= S5PV210_LEDF_ACTLOW | S5PV210_LEDF_TRISTATE,
	.def_trigger	= "",
};

static struct platform_device x210_led1 = {
	.name		= "why_led",
	.id		= 1,
	.dev		= {
		.platform_data	= &x210_led1_pdata,
	},
};

之后,我们要将这个platform_device定义的x210_led1变量添加到最开始说的那个含有x210所有设备的platform_device结构体数据中,按照九鼎的注册platform的逻辑,会将这个platform_device结构体数组中的所有设备进行注册。加入后代码为,这里只贴一部分

static struct platform_device *smdkc110_devices[] __initdata = {
#ifdef CONFIG_FIQ_DEBUGGER
	&s5pv210_device_fiqdbg_uart2,
	&x210_led1,
	.
	.
	.
	.
	.
	.
	.
}

好了,这个时候我们在mach-s5pv210.c中加入了x210的led的platform_device,并且也提供了led相应的platform_data设备的数据部分x210_led1_pdata,并且在mach-s5pv210/include/mach/目录中的leds-gpio.h中也定义了我们这个led设备数据部分x210_led1_pdata结构体的类型,我们也在mach-s5pv210.c中将led的platform_device的变量x210_led1添加到了platform_device结构体数组中,在平台总线设备进行注册的时候,就会将我们添加的这个x210_led1设备进行注册。

这个时候我们编译内核,可以使用uboot中的tftp下载内核,运行内核,内核nfs挂载根文件系统,内核运行起来后,这个时候的内核情况是我们只添加了led的platform_device,但是我们并没有添加led的platform_driver,因为我们没有insmod上一节课中的led的platform_drvier,并且上一节课中的led的platform_driver在probe函数和remove函数中的代码还没有彻底修改。此时先观察内核只有led的platform_deivce的情况。

此时我们在根文件系统的/sys/bus/platform/device/目录下会看到有一个why_led.1这么一个文件目录,后面的1就是我们当时添加这个设备数据部分时的id的值,也就是代表led的编号。

进到这个/sys/bus/platform/device/why_led.1目录中,我们ls看到也没有什么东西,都是一些常规的东西,此时说明在我们的platform中的device中已经能够找到文件节点,但是缺陷是只有一些常规的东西。这个时候是我们只有led的platform_device,没有led的platform_driver的情况。

时间: 2024-10-08 20:56:46

linux设备驱动之平台总线实践环节(二)的相关文章

linux设备驱动之平台总线实践环节(三)

1.在平台总线的实践环节的一和二中,分别将led的platform_driver和platform_device初步完成,接下来看下platform_device和platform_driver同时存在时的效果,就是led的平台设备已经注册到内核中,并且在根文件系统中ismod加载上led的平台总线驱动.看一下platform_device和platform_driver两者相遇会怎么样,根据platform平台总线的逻辑,因为我们已经将led的platform_device注册到了内核中,这个

Linux设备驱动开发 - 平台设备驱动

Linux2.6的内核中引入了一种新的设备驱动模型-平台(platform)设备驱动,平台设备驱动分为平台设备(platform_device)和平台驱动(platform_driver),平台设备的引入使得Linux设备驱动更加便于移植. 一.平台设备平台设备结构体: 1 struct platform_device { 2 const char * name; /* 设备名 */ 3 int id; 4 struct device dev; /* 设备结构体 */ 5 u32 num_res

linux设备驱动模型之平台总线实践环节(一)

1.首先回顾下之前写的驱动和数据在一起的led驱动代码,代码如下: #include <linux/module.h> #include <linux/init.h> #include <linux/leds.h> #include <asm/io.h> //ioremap和iounmap的头文件 writel等 /**********************************静态映射虚拟地址的方法,用的是内核移植时的静态映射表************

linux设备驱动模型之平台总线实践环节(四)

//通过led_classdev类型的指针得到s5pv210_led_pladata类型的指针,这个s5pv210_led_pladata类型结构体是我们自己定义的设备数据部分. static inline struct s5pv210_gpio_led *to_gpio(struct led_classdev *led_cdev) { return container_of(led_cdev, struct s5pv210_gpio_led, cdev); } #define X210_LED

linux设备驱动之platform平台总线工作原理(二)

5.5.5.platform平台总线工作原理2 5.5.5.1.平台总线体系的工作流程 (1)第一步:linux内核系统启动时在bus系统中注册platform. 1.什么叫做bus系统,操作系统中有一套管理总线的体系,内核里有一个子系统,就叫做总线子系统.就是内核来管理总线的.bus系统在内核启动时建立起来,比platform建立的时间还要早,bus系统的是由内核编写的人提供的,我们将来分析代码的时候不需要去分析他.在bus系统起来以后,就需要在bus系统中注册这个platform平台总线的b

linux设备驱动那点事儿之平台设备理论篇

一:Platform总线 1.1概述 一个现实的linux设备驱动通常需要挂接在一种总线上,对于本身依附于PCI,USB,IIC,SPI等的设备而言,这自然不是问题,但是在嵌入式系统里面,SOC系统中集成的独立的外设控制器,挂接在SOC内存空间的外设等确不依附于此类总线.基于这一背景,linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver.Platform总线是linux2.6内核加的一种虚拟总线. 1.2

linux设备驱动归纳总结(九):1.platform总线的设备和驱动【转】

本文转载自:http://blog.chinaunix.net/uid-25014876-id-111745.html linux设备驱动归纳总结(九):1.platform总线的设备和驱动 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 这一节可以理解是第八章的延伸,从这节开始介绍platform设备驱动. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

乾坤合一~Linux设备驱动之I2C核心、总线以及设备驱动

我思念的城市已是黄昏 为何我总对你一往情深 曾经给我快乐 也给我创伤 曾经给我希望 也给我绝望 我在遥远的城市 陌生的人群 感觉着你遥远的忧伤 我的幻想 你的忧伤,像我的的绝望,那样漫长,,,,,这是今天的旋律,直入心底~~~~~~~~~~~~~~~~ 在Linux 系统中,I2C 驱动由3 部分组成,即I2C 核心.I2C 总线驱动和I2C 设备驱动,I2C 总线仅仅使用SCL.SDA 这两根信号线就实现了设备之间的数据交互,极大地简化了对硬件资源和PCB 板布线空间的占用 1 Linux的I

linux设备驱动第五篇:驱动中的并发与竟态

综述 在上一篇介绍了linux驱动的调试方法,这一篇介绍一下在驱动编程中会遇到的并发和竟态以及如何处理并发和竞争. 首先什么是并发与竟态呢?并发(concurrency)指的是多个执行单元同时.并行被执行.而并发的执行单元对共享资源(硬件资源和软件上的全局.静态变量)的访问则容易导致竞态(race conditions).可能导致并发和竟态的情况有: SMP(Symmetric Multi-Processing),对称多处理结构.SMP是一种紧耦合.共享存储的系统模型,它的特点是多个CPU使用共