平台总线(三)

平台总线:用于平台升级的
三星: 
s3c2410  --------------- s3c6410 ----------- s5pv210
gpio控制器            gpio控制器 gpio控制器
 uart 
 i2c
 spi

控制逻辑方法相同:1,配置gpio寄存器
    2.读写数据

地址会不同


三元素:
总线: 开机的时候就已经创建了,不需要我们创建
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};


device对象:
struct platform_device {//是一个名字,描述设备属性
const char * name; //用于匹配
int id;
struct device dev; //继承父类
u32 num_resources;
struct resource * resource; // 描述设备的资源---地址和中断
};


struct resource {
resource_size_t start; //起始位置
resource_size_t end; //结束位置
const char *name; //自定义
unsigned long flags;//区分是地址还是中断资源:IORESOURCE_IRQ, IORESOURCE_MEM
}


driver对象
struct platform_driver {
int (*probe)(struct platform_device *);//表示匹配成功之后被调用
int (*remove)(struct platform_device *);
struct device_driver driver;//继承父类
const struct platform_device_id *id_table;//用于匹配
};


pdrv中获取资源:
/**
* 参数1: pdev
* 参数2: 获取的是中断资源还是内存资源 
* 参数3: 同种资源中第几个
*/
struct resource * platform_get_resource(struct platform_device * dev,unsigned int type,unsigned int num)


在probe方法中:
1,申请主设备号  register_chrdev_region (与内核相关)
2,注册字符设备驱动 cdev_alloc  cdev_init  cdev_add (与内核相关)
3,利用udev/mdev机制创建设备文件(节点) class_create, device_create (与内核相关)
4,实现操作硬件方法  xxx_open,xxx_read,xxxx_write...(与硬件相关)
5,硬件初始化
最重要的:

获取到资源,利用资源进行硬件初始化

/* led_test.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void)
{
	int fd;
	int on;
	fd = open("/dev/led0", O_RDWR);

	while (1) {
		on = 1;
		write(fd,&on, 4);
		sleep(1);
	
		on = 0;
		write(fd,&on, 4);
		sleep(1);
	}
	
	close(fd);

	return 0;
}

/* plat_led_dev.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#define GPC0CON 0xE0200060
#define GPC_SIZE 24

//用于演示,没有实际设备对应
#define GPA0CON 0xE0200000
#define GPA_SIZE 24

struct resource led_res[] = {

	/*实际所用到的*/
	[0] = {
		.start = GPC0CON,
		.end = GPC0CON + GPC_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},

	/*假如有其他的资源,比如有中断*/
	[1] = {
		.start = 888,
		.end = 1212,
		.flags = IORESOURCE_IRQ,
	},
	
	[2] = {
		.start = GPA0CON,
		.end = GPA0CON + GPC_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},
};

struct platform_device led_pdev = {
	.name = "s5pv210_led",
	.id = -1,
	.num_resources = ARRAY_SIZE(led_res),
	.resource = led_res,
};

static int __init plat_led_dev_init(void)
{
	/*注册一个平台设备*/ 	
	printk("------*_^%s--------\n",__FUNCTION__);

    return platform_device_register(&led_pdev);
}

static void __exit plat_led_dev_exit(void)
{
	/*注销平台设备*/
	platform_device_unregister(&led_pdev);
    printk("------*_^%s--------\n",__FUNCTION__);
}

module_init(plat_led_dev_init);
module_exit(plat_led_dev_exit);
		
MODULE_LICENSE("GPL");

/* plat_led_drv.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/slab.h>

#include <asm/uaccess.h>
#include <asm/io.h>

/*设计一个对象,表示一个全局的设备对象*/
struct samsung_led{
	int dev_major;
	struct class *cls;
	struct device *dev;
	struct resource *res;
	void *reg_addr; //虚拟地址
};

struct samsung_led * led_dev;

int led_pdrv_open(struct inode *inode, struct file *filp)
{
	printk("-------^_*  %s-----------\n", __FUNCTION__);
	return 0;
}

ssize_t led_pdrv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	int value;
	int ret;
	
	ret  = copy_from_user(&value, buf, count);
	if (ret > 0) {
		printk("copy_from_user error\n");
		return -EFAULT;
	}

	if (value) {
		//点灯
		__raw_writel(__raw_readl(led_dev->reg_addr + 4) | (0x3<<3), led_dev->reg_addr + 4);
		
	}else{
		__raw_writel(__raw_readl(led_dev->reg_addr + 4) & ~(0x3<<3), led_dev->reg_addr + 4);
	}

	return count;
}

int led_pdrv_close(struct inode *inode, struct file *filp)
{
	printk("-------^_*  %s-----------\n", __FUNCTION__);
	return 0;
}

struct file_operations led_fops = {
	.open = led_pdrv_open,
	.write = led_pdrv_write,
	.release = led_pdrv_close,
};

int led_pdrv_probe(struct platform_device *pdev)
{
	/*需要向应用空间提供接口
	1,申请设备号
	2,创建文件
	*/
	printk("-------^_*  %s-----------\n", __FUNCTION__);

	/*申请空间*/
	led_dev = kzalloc(sizeof(struct samsung_led), GFP_KERNEL); 

	/*动态申请设备*/
	led_dev->dev_major = register_chrdev(0, "led_drv", &led_fops);

	/*创建设备类*/
	led_dev->cls = class_create(THIS_MODULE, "led_cls");

	/*创建字符设备*/
	led_dev->dev = device_create(led_dev->cls,NULL, MKDEV(led_dev->dev_major, 0), NULL, "led%d", 0);
	led_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	//可以进行映射
	led_dev->reg_addr = ioremap(led_dev->res->start, resource_size(led_dev->res));

	//获取中断
	int irqno = platform_get_irq(pdev, 0);
	printk("irqno  = %d\n", irqno );

	// 配置gpio为输出
	unsigned int temp = __raw_readl(led_dev->reg_addr);
	temp &= ~(0xff<<12);
	temp |= (0x11<<12);
	__raw_writel(temp,led_dev->reg_addr);

	return 0;
}

int led_pdrv_remove(struct platform_device *pdev)
{
	iounmap(led_dev->reg_addr);
	device_destroy(led_dev->cls,MKDEV(led_dev->dev_major, 0));
	class_destroy(led_dev->cls);
	unregister_chrdev(led_dev->dev_major,"led_drv");
	kfree(led_dev);
	
	return 0;
}

/*用于匹配*/		
const struct platform_device_id led_id_table[] = {
	{"s3c2410_led", 1111},
	{"s3c6410_led", 2222},
	{"s5pv210_led", 3333},
};

struct platform_driver led_drv = {
	.probe = led_pdrv_probe,
	.remove = led_pdrv_remove,
	.driver = {
		.name = "s5pv210_led"	// 随便写,用于匹配,/sys/bus/platform/drivers/samsung_led_drv
	},
	.id_table = led_id_table,//优先匹配列表中的名字,如果没有列表,就匹配父类中name

};

static int __init plat_led_drv_init(void)
{
	/*注册一个平台驱动*/ 	
	printk("------*_^%s--------\n",__FUNCTION__);

    return platform_driver_register(&led_drv);
}

static void __exit plat_led_drv_exit(void)
{
	/*注销平台驱动*/
	platform_driver_unregister(&led_drv);

	printk("------*_^%s--------\n",__FUNCTION__);
}

module_init(plat_led_drv_init);
module_exit(plat_led_drv_exit);
		
MODULE_LICENSE("GPL");

# Makefile
ROOTFS_DIR = /opt/filesystem
MODULE_NAME = plat_led_dev
MODULE_NAME2 = plat_led_drv

APP_NAME = led_test
CROSS_COMPILE = arm-cortex_a8-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc

ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /home/linux-3.0.8
CUR_DIR = $(shell pwd)
all :	
	make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
	$(CC) $(APP_NAME).c -o $(APP_NAME)
clean :	
	make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
	rm -rf $(APP_NAME)
	
install:	
	cp -raf *.ko  $(APP_NAME) $(ROOTFS_DIR)/drv_module
else

obj-m = $(MODULE_NAME).o
obj-m += $(MODULE_NAME2).o

endif


### 总线结构的概念 总线结构是一种经典的设计方法,用于连接计算机系统的主要组件[^1]。这种设计通过种不同的总线来实现功能分离:数据总线负责传输实际的数据信息;地址总线则专门用于指定内存或外设的物理位置;而控制总线则是为了协调各部件的操作并传递必要的同步和命令信号。 在具体实现上,总线结构有助于提升系统的模块化水平以及整体性能表现。由于每种总线专注于特定的任务领域,因此可以减少干扰并优化资源分配效率。例如,在多任务处理环境中,独立运行的数据流管理机制允许更高效地调度读写操作而不影响其他进程的状态更新需求。 对于现代计算环境而言,尽管存在更多复杂形式的互连网络替代传统意义上的简单根平行线路布局方式,但其基本原理仍然沿用了这一基础框架下的设计理念[^3]。 ### 实现细节分析 当构建基于总线模型的实际硬件平台时,工程师们会考虑以下几个方面: #### 数据总线宽度 数据总线决定了每次能同时传输多少比特数目的能力大小。如果定义为n位,则理论上最大吞吐量将达到 n/8 字节每周期[^4] 。常见的标准有8-bit、16-bit直到最新的64-bit甚至更高规格版本可供选择取决于目标应用场景的具体要求。 #### 地址范围扩展 地址总线的数量直接影响可寻址空间上限值。比如拥有m条引脚组成的此类链路所能覆盖的最大区域等于 \(2^{m}\) Byte 的规模。这对于支持大容量存储器访问至关重要尤其是在高性能服务器或者图形工作站等领域应用广泛。 #### 控制协议制定 最后关于控制层面的内容涉及到了如何有效地传达各类指令集给相应的目标单元完成预定动作序列的过程描述。这可能包括但不限于中断请求(IR),直接内存存取(DMA)等功能选项的支持情况介绍[^5]。 ```python class BusSystem: def __init__(self, data_width=32, addr_width=32): self.data_bus = ["0"] * int(data_width / 8) # 假定按字节划分 self.addr_bus = [False] * addr_width # 每一位表示一个地址线状态 self.control_signals = {} # 存储各种控制信号及其当前值 def send_data(self, value): """模拟向数据总线上发送数值""" byte_list = list(value.to_bytes(len(self.data_bus), 'big')) for i in range(len(byte_list)): self.data_bus[i] = chr(byte_list[i]) def set_address(self, address): """设置地址总线上的值""" binary_addr = bin(address)[2:].zfill(len(self.addr_bus)) for idx, bit in enumerate(binary_addr): self.addr_bus[idx] = bool(int(bit)) # 示例初始化与使用 bus_system = BusSystem() bus_system.send_data(0xAABBCCDD) bus_system.set_address(0x7FFFFFFF) ``` 上述代码片段展示了一个简化版的总线系统类 `BusSystem` ,其中包含了数据总线、地址总线的基础属性设定,并提供了简单的数据发送及地址配置的方法演示^。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值