Linux 驱动分析--s3c6410 的SDIO驱动分析

发布者:PositiveEnergy最新更新时间:2024-11-05 来源: cnblogs关键字:Linux  驱动分析  s3c6410  SDIO 手机看文章 扫描二维码
随时随地手机看文章

    正在研究mw8686 的Linux SDIO驱动,编译好后在s3c6410运行,发现未能出现网络接口设备。一查之下,它使用sdio总线进行操作驱动和设备,但是在 /sys/bus/sdio/devices 没有看到任何设备。因此推理是这个导致WiFi无法使用SDIO的原因。因为sdio驱动的初始化是放在probe当中,而probe是在sdio设备与sdio driver的match的过程中执行中。没有设备,意味着无法进行SDIO初始化。
   我用的是Linux 2.6.28的版本,在网络上找到几个其它版本,主要Linux 2.6.21的,利用下午上课时间,进行一下课堂实验。发现这两个版本的实现差别很大,实际上两个分水岭。刚开始没明白这个道理,被两个版本的的源码搞得很混乱,因此为了解决问题,对这个两版本的SDIO实现进行分析
  关于mw8686的模块分析,参见我的博文  <> http://blogold.chinaunix.net/u3/105675/showart_2536780.html  首先根据档和源码来看三星发了几个关健的BSP,一个是针对linux 2.6.21.另外一个针对 linux 2.6.28的。这两个对SDIO的驱动采用不同的实际,有一篇官方文档可以看看,里面对Linux 2.6.21 SDIO实现分析得详细。    <>,但是网上只能找到这一个 如果你对Linux 2.6的驱动模型相当了解,实际也能很快分析清楚。SDIO总线   首先mw8686的if_sdio.c直接使用了sdio 总线。这个虚拟总线是由 driver/mmc/core/sdio_bus.c实现,在两个版本,这个基本是变化不大的地方。要注意,这里的SDIO和MMC是两个兼容的接口,因此在源码中两个术语经常互换.    sdio bus是一个标准的Linux 的总线,因此它需要有标准 bus device 和标准bus driver来注册到系统中。     这是 sdio_bus.c的总线定义

static struct bus_type sdio_bus_type = {
 .name  = 'sdio',
 .dev_attrs = sdio_dev_attrs,
 .match  = sdio_bus_match,
 .uevent  = sdio_bus_uevent,
 .probe  = sdio_bus_probe,
 .remove  = sdio_bus_remove,
};

int sdio_register_bus(void)
{
 return bus_register(&sdio_bus_type);
}

void sdio_unregister_bus(void)
{
 bus_unregister(&sdio_bus_type);
}

而对应总线驱动struct device_driver 是 struct sdio_driver

/*
 * SDIO function device driver
 */
struct sdio_driver {
 char *name;
 const struct sdio_device_id *id_table;

 int (*probe)(struct sdio_func *, const struct sdio_device_id *);
 void (*remove)(struct sdio_func *);

 struct device_driver drv;
};

它使用 如下两个函数来注册和销毁sdio_driver.extern int sdio_register_driver(struct sdio_driver *);
extern void sdio_unregister_driver(struct sdio_driver *);    而对应总线设备的就是 struct device  是 struct sdio_func,这个名字与device差别太大了,因此我一开没有太在意。   

/*
 * SDIO function devices
 */
struct sdio_func {
 struct mmc_card  *card;  /* the card this device belongs to */
 struct device  dev;  /* the device */
 sdio_irq_handler_t *irq_handler; /* IRQ callback */
 unsigned int  num;  /* function number */

 unsigned char  class;  /* standard interface class */
 unsigned short  vendor;  /* vendor id */
 unsigned short  device;  /* device id */

 unsigned  max_blksize; /* maximum block size */
 unsigned  cur_blksize; /* current block size */

 unsigned  enable_timeout; /* max enable timeout in msec */

 unsigned int  state;  /* function state */
#define SDIO_STATE_PRESENT (1<<0)  /* present in sysfs */

 u8   tmpbuf[4]; /* DMA:able scratch buffer */

 unsigned  num_info; /* number of info strings */
 const char  **info;  /* info strings */

 struct sdio_func_tuple *tuples;
};

  对于sdio_func操作  int sdio_add_func(struct sdio_func *func);
  void sdio_remove_func(struct sdio_func *func); 在drivers/net/wireless/libertas/if_sdio.c 它定义了如下的 sdio_driver

static struct sdio_driver if_sdio_driver = {
 .name  = 'libertas_sdio',
 .id_table = if_sdio_ids,
 .probe  = if_sdio_probe,
 .remove  = if_sdio_remove,
};

static int __init if_sdio_init_module(void)  
{                                            
 int ret = 0;                               
 ret = sdio_register_driver(&if_sdio_driver);
 return ret;                                
}                                            
                                             
static void __exit if_sdio_exit_module(void) 
{                                            
 sdio_unregister_driver(&if_sdio_driver);   
}                                            

 SDIO采用的与MMC兼容的命令接口,因此对于mmc的操作,LINUX又封装一层,使用数据结构 mmc_host 

struct mmc_host {
 struct device  *parent;
 struct device  class_dev;
 int   index;
 const struct mmc_host_ops *ops;
 unsigned int  f_min;
 unsigned int  f_max;
 u32   ocr_avail;
 unsigned long  caps;  /* Host capabilities */
 /* host specific block data */
 unsigned int  max_seg_size; /* see blk_queue_max_segment_size */
 unsigned short  max_hw_segs; /* see blk_queue_max_hw_segments */
 unsigned short  max_phys_segs; /* see blk_queue_max_phys_segments */
 unsigned short  unused;
 unsigned int  max_req_size; /* maximum number of bytes in one req */
 unsigned int  max_blk_size; /* maximum size of one mmc block */
 unsigned int  max_blk_count; /* maximum number of blocks in one req */

 /* private data */
 spinlock_t  lock;  /* lock for claim and bus ops */

 struct mmc_ios  ios;  /* current io bus settings */
 u32   ocr;  /* the current OCR setting */

 /* group bitfields together to minimize padding */
 unsigned int  use_spi_crc:1;
 unsigned int  claimed:1; /* host exclusively claimed */
 unsigned int  bus_dead:1; /* bus has been released */
#ifdef CONFIG_MMC_DEBUG
 unsigned int  removed:1; /* host is being removed */
#endif

 struct mmc_card  *card;  /* device attached to this host */

 wait_queue_head_t wq;

 struct delayed_work detect;

 const struct mmc_bus_ops *bus_ops; /* current bus driver */
 unsigned int  bus_refs; /* reference counter */

 unsigned int  sdio_irqs;
 struct task_struct *sdio_irq_thread;
 atomic_t  sdio_irq_thread_abort;

#ifdef CONFIG_LEDS_TRIGGERS
 struct led_trigger *led;  /* activity led */
#endif

 struct dentry  *debugfs_root;

 unsigned long  private[0] ____cacheline_aligned;
};

 而mmc_host是一个特殊内核类 mmc_host,它会在 /sys/class/ 建立一个mmc_host类.

//drivers/mmc/core/host.c

static struct class mmc_host_class = {
 .name  = 'mmc_host',
 .dev_release = mmc_host_classdev_release,
};

int mmc_register_host_class(void)
{
 return class_register(&mmc_host_class);
}

void mmc_unregister_host_class(void)
{
 class_unregister(&mmc_host_class);
}

 mmc_host用于描述MMC接口 CPU一侧的设备,它可以看成是class device的特例,而插入的SDIO设备,如SD卡则封装成数据结构,如果mmc_host发送命令和数据是通过 struct mmc_host_ops 操作

struct mmc_host_ops {                                                 
 void (*request)(struct mmc_host *host, struct mmc_request *req);   
 void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);       
 int (*get_ro)(struct mmc_host *host);                               
 int (*get_cd)(struct mmc_host *host);                               
                                                                      
 void (*enable_sdio_irq)(struct mmc_host *host, int enable);        
};

 如果SDIO设备操作,直接采用如下定义

static struct mmc_host_ops s3c_hsmmc_ops = {
 .request = s3c_hsmmc_request,
 .set_ios = s3c_hsmmc_set_ios,
};

 mmc_card /mmc_bus如果SD卡的之存储设备进行块设备操作,则需要另一个额外的mmc bus总线,并且需要定义mmc_card结构,对应(device).并且进行存储的块设备操作定义在mmc_driver类。 如果SDIO设备本身不需要这个总线 在mmc又单独定义一个 mmc总线, 

[1] [2] [3]
关键字:Linux  驱动分析  s3c6410  SDIO 引用地址:Linux 驱动分析--s3c6410 的SDIO驱动分析

上一篇:s3c6410 TVout 测试
下一篇:gsm库(libgsm)在ARM-Linux下的移植

推荐阅读最新更新时间:2024-11-13 10:26

单片机成长之路(51基础篇) - 006 在Linux下搭建开发烧写环境
在Linux下没有像keli那样好用的IDE来开发51单片机,开发环境只能自己搭建了。 第一步:安装交叉编译工具 a) 安装SDCC sudo apt-get install sdcc b)测试SDCC是否可用,这是个网上找的简单的流水灯代码 test.c, 用来测试 1 #include 8051.h 2 3 #define uint unsigned int 4 #define uchar unsigned char 5 uchar tab = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; 6 7 void Delay(uint xms){ 8 uin
[单片机]
单片机成长之路(51基础篇) - 006 在<font color='red'>Linux</font>下搭建开发烧写环境
[初级教程]arm-linux裸机开发之-bootstrap.bin的实现
1.前言 我们知道,在Linux平台下编写的程序要想在arm平台上运行,我们就得使用交叉的编译器,我们用arm-linux-none-gnueabi-gcc 或者arm-linux-gcc也罢,这些编译器编译产生的程序能够直接运行在arm的平台上,那我们的bootstrap.bin自己来实现,都需要具备哪些文件呢?众所周知,在引导程序中当今做大的最大的莫过于U-Boot这个组织,今天,我们就模仿U-Boot来实现一个简易的引导程序,我们称之为Bootstrap.bin。实现该bin文件我们模仿U-Boot的工程模版,写出几个实现文件: start.S 我们知道汇编指令的代码在机器上执行的速度比较快,那些短小精悍的程序往往运行在
[单片机]
[初级教程]arm-<font color='red'>linux</font>裸机开发之-bootstrap.bin的实现
linux 下arm汇编语法
第一部分 Linux下ARM汇编语法 尽管在Linux下使用C或C++编写程序很方便,但汇编源程序用于系统最基本的初始化,如初始化堆栈指针、设置页表、操作ARM的协处理器等。初始化完成后就可以跳转到C代码执行。需要注意的是,GNU的汇编器遵循AT&T的汇编语法,可以从GNU的站点(www.gnu.org)上下载有关规范。 一. Linux汇编行结构 任何汇编行都是如下结构: ]] 每一个段以段名为开始, 以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与armasm中的AREA相同)。 下面是ELF格式允许的段标志 标志 含义 a 允许段 w 可写段 x 执行段 定义段
[单片机]
基于ARM-Linux的无线气象数据通信系统的设计与实现
自动气象站数据采集器一般基于单片机或PC/104总线控制器设计,具有与PC兼容性好、功耗低、体积紧凑等特点,然而如何设计出功能强大,网络传输功能强的自动气象站数据采集器,满足现代气象检测的要求,是一个值得研究的课题。 文中基于ARM微处理器和Linux操作系统平台,借助前端无线传感器网络的数据输入,利用嵌入式Qt的开发优势并设计数据通信格式,完成无线气象数据通信系统的设计,实现了数据的可靠传输。为天气预报、科学研究、气象灾害预警等提供实时的气象观测数据。 1 无线气象数据通信系统的基本组成 如图1所示,无线气象数据通信系统主要由无线传感器网络节点、协调器、数据通信器(数据通信器以S3C2440AL为核心)、远程服务器等组成,
[单片机]
基于ARM-<font color='red'>Linux</font>的无线气象数据通信系统的设计与实现
linux USB 摄像头 驱动 移植,使用
1、USB摄像头的配置 UVC,全称为:USB video class 或USB video device class,是Microsoft与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标准,目前已成为USB org标准之一。 如今的主流操作系统(如Windows XP SP2 and later, Linux 2.4.6 and later, MacOS 10.5 and later)都已提供UVC设备驱动,因此符合UVC规格的硬件设备在不需要安装任何的驱动程序下即可在主机中正常使用。使用UVC技术的包括摄像头、数码相机、类比影像转换器、电视棒及静态影像相机等设备 下面就开始配置UVC的linux驱动。
[单片机]
OK6410A 开发板 (八) 68 linux-5.11 OK6410A linux 内核同步机制 atomic 的实现
解决的问题是什么 所有竞态原因 实现 32bit // 下面为 atomic_add 的定义 arch/arm/include/asm/atomic.h 36 #define ATOMIC_OP(op, c_op, asm_op) 37 static inline void atomic_##op(int i, atomic_t *v) 38 { 39 unsigned long tmp; 40
[单片机]
基于S3C6410的ARM11学习(十二) 代码拷贝及led测试输入日志
之前已经将ddr进行初始化了,这样就可以使用ddr了。首先就要将代码从stepping stone拷贝到ddr中。最后在ddr中运行程序。如果外部nandflash还有剩余的程序,还要将剩下程序拷贝到ddr中。 Stepping stone的起始地址是0x0c000000,DDR的起始地址是0x50000000。在上电的时候,CPU会自动把NANDFLASH的前8K代码拷贝到stepping stone中。但是现在写的代码是比较小的,还没有超过4K。所以这里就设定拷贝的代码是前4K代码。 这样,代码就比较好写了。 R0保存的是stepping stone的起始地址,r1保存的是要拷贝的ddr的地址,这里地址是0x
[单片机]
基于<font color='red'>S3C6410</font>的ARM11学习(十二) 代码拷贝及led测试输入日志
移植 Linux 2.6.32.2 到 mini2440
先介绍一下此次移植的主要目标对象: 平台:Windows 7 旗舰版 And Fedora 9 目标板:mini2440 目标系统: linux-2.6.32.2 交叉编译链: arm-liunux-gcc 4.4.3 busybox版本: busy.1.13.3 yaffs2版本: yaffs2-20100330(友善那坑爹的文档说光盘有这个压缩包……我有你妹啊……这个是我从官网下载的) 本来以为吧,有友善的移植文档作为参考,只要一步一步来,应该会比较顺利的……不过很快我发现我真是太天真了……友善那坑爹的移植文档实在是让我火大……一个简单的移植过程,在有参考文档的前提下,足足搞了哥4天时间,期间因为按部就班地按照友善的移植文档而
[单片机]
移植 <font color='red'>Linux</font> 2.6.32.2 到 mini2440
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved