随笔-118  评论-133  文章-4  trackbacks-0
 
第一、什么是ubifs?

由IBM、nokia工程师Thomas Gleixner,Artem Bityutskiy等人于2006年发起,致力于开发性能卓越、扩展性高的FLASH专用文件系统,以解决当前嵌入式环境下以FLASH作为MTD设备使用时的技术瓶颈。

关键字:
UBI:一种类似于LVM的逻辑卷管理层。主要实现损益均衡,逻辑擦除块、卷管理,坏块管理等。
UBIFS:基于UBI的FLASH日志文件系统。

有关ubifs的详细介绍,请参考:
http://www.linux-mtd.infradead.org/doc/ubi.html
http://www.linux-mtd.infradead.org/doc/ubifs.html


第二、为何使用ubifs?


第三、如何得到ubifs?
2.6.22以后,ubifs活跃于git管理工程中:
git://git.infradead.org/ubi-2.6.git

2.6.27以后,ubifs被整合进内核树中,用户只需下载最新内核即可获取ubifs支持。

第四、如何使用ubifs?

软件环境:
linux-2.6.28
arm-linux-gcc 3.4.5

硬件环境:
s3c2410
k9f1208

一、准备


1、内核
配置的时候选上
1)Device Drivers  --->Memory Technology Device (MTD) support  --->UBI - Unsorted block images  --->Enable UBI
2)File systems  --->Miscellaneous filesystems  --->UBIFS file system support

2、mtd-utils工具(flash_eraseall、ubiattach、ubimkvol)准备
1)下载(mtd-utils、zlib、lzo)源码
wget http://debian.mirror.inra.fr/debian/pool/main/m/mtd-utils/mtd-utils_20080508.orig.tar.gz
wget http://www.zlib.net/zlib-1.2.3.tar.gz
wget http://www.oberhumer.com/opensource/lzo/download/lzo-2.03.tar.gz

2)编译安装zlib
tar xzvf zlib-1.2.3.tar.gz
cd zlib-1.2.3
CC=arm-linux-gcc ./configure --shared --prefix=/usr/local/arm/3.4.5/arm-linux
make
make install
cd ..

3)编译安装lzo
tar xzvf lzo-2.03.tar.gz
cd lzo-2.03
CC=arm-linux-gcc ./configure --host=arm-linux --prefix=/usr/local/arm/3.4.5/arm-linux
make
make install
cd ..

4)编译mtd-utils
tar xzvf mtd-utils_20080508.orig.tar.gz
cd mtd-utils-20080508

修改Makefile文件:
#CROSS=arm-linux-
修改为  CROSS=arm-linux-
BUILDDIR := $(CROSS:-=)
修改为  BUILDDIR := .

修改ubi-utils/Makefile文件:
添加    CROSS=arm-linux-

修改    ubi-utils/new-utils/Makefile文件:
添加    CROSS=arm-linux-

make WITHOUT_XATTR=1

ubi-utils子目录下生成我们需要的ubiattach、ubimkvol等文件(请确保是交叉编译所得)

3、mtd-utils工具(mkfs.ubifs、ubinize)准备
git-clone git://git.infradead.org/mtd-utils.git
cd mtd-utils/
make

mkfs.ubifs子目录下生成我们需要的mkfs.ubifs工具
ubi-utils/new-utils子目录下生成我们需要的ubinize工具


二、使用


1、使用ramfs或nfs启动系统,执行以下命令挂载ubifs:
1)flash_eraseall /dev/mtd4
2)ubiattach /dev/ubi_ctrl -m 4
3)ubimkvol /dev/ubi0 -N rootfs -s 50MiB
4)mount -t ubifs ubi0_0 /mnt或mount -t ubifs ubi0:rootfs /mnt

2、如果你想使用ubifs为rootfs,把文件系统内容解压到ubifs挂载目录下,并修改内核启动参数为:
console=ttySAC0 ubi.mtd=4 root=ubi0:rootfs rootfstype=ubifs

3、如果你想直接在bootloader下烧写ubifs映像,使用以下命令制作ubi烧写映像:
mkfs.ubifs -r rootfs -m 512 -e 15872 -c 3303 -o ubifs.img
ubinize -o ubi.img -m 512 -p 16KiB -s 256 ubinize.cfg

其中:
1)以上命令的参数可从ubifs挂载信息中提取:
UBI: attaching mtd4 to ubi0                                                    
UBI: physical eraseblock size:   16384 bytes (16 KiB)                          
UBI: logical eraseblock size:    15872 bytes                                   
UBI: smallest flash I/O unit:    512                                           
UBI: sub-page size:              256                                           
UBI: VID header offset:          256 (aligned 256)                             
UBI: data offset:                512                                           
UBI: attached mtd4 to ubi0             

2)配置文件ubinize.cfg的内容为:
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=50MiB
vol_type=dynamic
vol_name=rootfs
vol_flags=autoresize

注:
    其他nand flash下ubifs的使用方法类似(参数不同)。





posted @ 2009-03-11 01:00 lfc 阅读(24499) | 评论 (6)编辑 收藏
     摘要: 第十四章  Linux终端设备驱动 本章导读 在Linux系统中,终端设备非常重要,没有终端设备,系统将无法向用户反馈信息,Linux中包含控制台、串口和伪终端3类终端设备。 14.1节阐述了终端设备的概念及分类,14.2节给出了Linux终端设备驱动的框架结构,重点描述tty_driver结构体及其成员。14.3~14.5节在14.2节的基础上,分别给出了Linux终端设备驱动模块...  阅读全文
posted @ 2008-10-07 11:50 lfc 阅读(5645) | 评论 (1)编辑 收藏
了解了i2c总线的主要结构成员及适配器、设备驱动的注册后,现在我们从上而下的来研究一下i2c总线的使用(仍然以i2c-dev.c为例):

1、这是面向用户的虚拟字符设备所提供的所有i2c总线操作接口函数:
static const struct file_operations i2cdev_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
        .read           = i2cdev_read,
        .write          = i2cdev_write,
        .ioctl          = i2cdev_ioctl,
        .open           = i2cdev_open,
        .release        = i2cdev_release,
};

1)drivers/i2c/i2c-dev.c
static int i2cdev_open(struct inode *inode, struct file *file)
{
        unsigned int minor = iminor(inode);
        struct i2c_client *client;
        struct i2c_adapter *adap;
        struct i2c_dev *i2c_dev;

        i2c_dev = i2c_dev_get_by_minor(minor);    //通过设备文件的从设备号查找对应的i2c_dev
        if (!i2c_dev)
                return -ENODEV;

        adap = i2c_get_adapter(i2c_dev->adap->nr);    //查找对于的adap
        if (!adap)
                return -ENODEV;

        client = kzalloc(sizeof(*client), GFP_KERNEL);    //i2c从设备描述结构体
        if (!client) {
                i2c_put_adapter(adap);
                return -ENOMEM;
        }
        snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
        client->driver = &i2cdev_driver;

        /* registered with adapter, passed as client to user */
        client->adapter = adap;
        file->private_data = client;

        return 0;
}

注:
    i2cdev_open的主要作用是构建并初始化用于描述i2c从设备的结构体struct i2c_client。

2)drivers/i2c/i2c-dev.c
i2cdev_read
    -> i2c_master_recv
        -> i2c_transfer
            -> adap->algo->master_xfer(s3c24xx_i2c_xfer)

3)drivers/i2c/i2c-dev.c
i2cdev_write
    -> i2c_master_send
        -> i2c_transfer
            -> adap->algo->master_xfer(s3c24xx_i2c_xfer)



7)drivers/i2c/busses/i2c-s3c2410.c
s3c24xx_i2c_xfer
    -> s3c24xx_i2c_doxfer(wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5)) <----|
        -> s3c24xx_i2c_irq                                                               |   
            -> i2s_s3c_irq_nextbyte                                                      |   
                -> s3c24xx_i2c_stop                                                      |
                    -> s3c24xx_i2c_master_complete(wake_up(&i2c->wait))------------------|


posted @ 2008-10-05 23:44 lfc 阅读(3756) | 评论 (0)编辑 收藏
1、总线适配器注册:
1)drivers/i2c/i2c-core.c
int i2c_add_adapter(struct i2c_adapter *adapter)
{
        int     id, res = 0;

retry:
        if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
                return -ENOMEM;

        mutex_lock(&core_lists);
        /* "above" here means "above or equal to", sigh */
        res = idr_get_new_above(&i2c_adapter_idr, adapter,
                                __i2c_first_dynamic_bus_num, &id);
        mutex_unlock(&core_lists);

        if (res < 0) {
                if (res == -EAGAIN)
                        goto retry;
                return res;
        }

        adapter->nr = id;            //使用动态的总线号来标识总线适配器。
        return i2c_register_adapter(adapter);
}
EXPORT_SYMBOL(i2c_add_adapter);

2)drivers/i2c/i2c-core.c
static int i2c_register_adapter(struct i2c_adapter *adap)
{
        int res = 0;
        struct list_head   *item;
        struct i2c_driver  *driver;

        mutex_init(&adap->bus_lock);        //初始化总线访问控制变量(总线上数据传输时使用)
        mutex_init(&adap->clist_lock);        //初始化客户端访问控制变量(操作客户端结构时使用)
        INIT_LIST_HEAD(&adap->clients);        //初始化客户端链表头

        mutex_lock(&core_lists);
        list_add_tail(&adap->list, &adapters);    //添加到总线适配器链表中

        /* Add the adapter to the driver core.
         * If the parent pointer is not set up,
         * we add this adapter to the host bus.
         */
        if (adap->dev.parent == NULL) {       
                adap->dev.parent = &platform_bus;
                pr_debug("I2C adapter driver [%s] forgot to specify "
                         "physical device\n", adap->name);
        }
        sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
        adap->dev.release = &i2c_adapter_dev_release;
        adap->dev.class = &i2c_adapter_class;
        res = device_register(&adap->dev);    //注册设备
        if (res)
                goto out_list;

        dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

        /* create pre-declared device nodes for new-style drivers */
        if (adap->nr < __i2c_first_dynamic_bus_num)
                i2c_scan_static_board_info(adap);

        /* let legacy drivers scan this bus for matching devices */
        list_for_each(item,&drivers) {        //搜索总线上的所有设备驱动,通过调用其attach_adapter接口函数,查找匹配的设备。
                driver = list_entry(item, struct i2c_driver, list);
                if (driver->attach_adapter)
                        /* We ignore the return code; if it fails, too bad */
                        driver->attach_adapter(adap);
        }

out_unlock:
        mutex_unlock(&core_lists);
        return res;

out_list:
        list_del(&adap->list);
        idr_remove(&i2c_adapter_idr, adap->nr);
        goto out_unlock;
}

2、设备驱动注册(以i2c-dev.c为例):
1)include/linux/i2c.h
static inline int i2c_add_driver(struct i2c_driver *driver)
{
        return i2c_register_driver(THIS_MODULE, driver);
}

2)drivers/i2c/i2c-core.c
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
        int res;

        /* new style driver methods can't mix with legacy ones */
        if (is_newstyle_driver(driver)) {
                if (driver->attach_adapter || driver->detach_adapter
                                || driver->detach_client) {
                        printk(KERN_WARNING
                                        "i2c-core: driver [%s] is confused\n",
                                        driver->driver.name);
                        return -EINVAL;
                }
        }

        /* add the driver to the list of i2c drivers in the driver core */
        driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;

        /* for new style drivers, when registration returns the driver core
         * will have called probe() for all matching-but-unbound devices.
         */
        res = driver_register(&driver->driver);    //注册驱动
        if (res)
                return res;

        mutex_lock(&core_lists);

        list_add_tail(&driver->list,&drivers);    //添加到设备驱动链表中
        pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

        /* legacy drivers scan i2c busses directly */
        if (driver->attach_adapter) {
                struct i2c_adapter *adapter;

                list_for_each_entry(adapter, &adapters, list) {    //让设备驱动搜索匹配的适配器(通过调用其attach_adapter接口)
                        driver->attach_adapter(adapter);
                }
        }

        mutex_unlock(&core_lists);
        return 0;
}
EXPORT_SYMBOL(i2c_register_driver);

3)drivers/i2c/i2c-dev.c
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
        struct i2c_dev *i2c_dev;
        int res;

        i2c_dev = get_free_i2c_dev(adap);    //创建并初始化i2c_dev结构
        if (IS_ERR(i2c_dev))
                return PTR_ERR(i2c_dev);

        /* register this i2c device with the driver core */
        i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,        //注意,这里使用的次设备号为adap->nr,便于以后获取adap结构。
                                     MKDEV(I2C_MAJOR, adap->nr),
                                     "i2c-%d", adap->nr);
        if (IS_ERR(i2c_dev->dev)) {
                res = PTR_ERR(i2c_dev->dev);
                goto error;
        }
        res = device_create_file(i2c_dev->dev, &dev_attr_name);        //创建设备文件
        if (res)
                goto error_destroy;

        pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
                 adap->name, adap->nr);
        return 0;
error_destroy:
        device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
        return_i2c_dev(i2c_dev);
        return res;
}

总结:
    一个适配器对应一个i2c控制器。


posted @ 2008-10-05 23:43 lfc 阅读(3800) | 评论 (1)编辑 收藏
1、总线配置结构体:
struct s3c2410_platform_i2c {
        unsigned int    flags;
        unsigned int    slave_addr;     /* slave address for controller */
        unsigned long   bus_freq;       /* standard bus frequency */
        unsigned long   max_freq;       /* max frequency for the bus */
        unsigned long   min_freq;       /* min frequency for the bus */
        unsigned int    sda_delay;      /* pclks (s3c2440 only) */
};

2、总线描述结构体:
struct s3c24xx_i2c {
        spinlock_t              lock;        //自选锁(防止总线资源被并发访问)
        wait_queue_head_t       wait;        //等待队列(当有数据需要收/发时启动总线,然后守候在等待队列,直到数据收/发结束后被唤醒返回)

        struct i2c_msg          *msg;        //i2c信息指针
        unsigned int            msg_num;    //需要传输的i2c msg数
        unsigned int            msg_idx;    //成功传输的i2c msg数
        unsigned int            msg_ptr;    //当前i2c msg内指针

        unsigned int            tx_setup;    //延时值(保证总线启动时数据已经传输到总线上)

        enum s3c24xx_i2c_state  state;        //i2c总线状态

        void __iomem            *regs;:
        struct clk              *clk;
        struct device           *dev;
        struct resource         *irq;
        struct resource         *ioarea;
        struct i2c_adapter      adap;        //总线适配器(个人觉得它更像设备驱动中的设备而非驱动)
};

3、总线适配器:
struct i2c_adapter {
        struct module *owner;
        unsigned int id;
        unsigned int class;
        const struct i2c_algorithm *algo;             //i2c总线访问算法
        void *algo_data;                    //用来保存struct s3c24xx_i2c结构指针

        /* --- administration stuff. */
        int (*client_register)(struct i2c_client *);
        int (*client_unregister)(struct i2c_client *);

        /* data fields that are valid for all devices   */
        u8 level;                                   //nesting level for lockdep
        struct mutex bus_lock;
        struct mutex clist_lock;

        int timeout;
        int retries;
        struct device dev;                          //the adapter device

        int nr;
        struct list_head clients;
        struct list_head list;
        char name[48];
        struct completion dev_released;
};

4、总线访问算法:
struct i2c_algorithm {
        /* If an adapter algorithm can't do I2C-level access, set master_xfer
           to NULL. If an adapter algorithm can do SMBus access, set
           smbus_xfer. If set to NULL, the SMBus protocol is simulated
           using common I2C messages */
        /* master_xfer should return the number of messages successfully
           processed, or a negative value on error */
        int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,    //i2c msg发送函数
                           int num);
        int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
                           unsigned short flags, char read_write,
                           u8 command, int size, union i2c_smbus_data * data);

        /* --- ioctl like call to set div. parameters. */
        int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);

        /* To determine what the adapter supports */
        u32 (*functionality) (struct i2c_adapter *);                //标志i2c适配器所支持的功能
};

struct i2c_msg {
        __u16 addr;     /* slave address                        */
        __u16 flags;
#define I2C_M_TEN       0x10    /* we have a ten bit chip address       */
#define I2C_M_RD        0x01
#define I2C_M_NOSTART   0x4000
#define I2C_M_REV_DIR_ADDR      0x2000
#define I2C_M_IGNORE_NAK        0x1000
#define I2C_M_NO_RD_ACK         0x0800
#define I2C_M_RECV_LEN          0x0400 /* length will be first received byte */
        __u16 len;              /* msg length                           */
        __u8 *buf;              /* pointer to msg data                  */
};

这里有我画的简单i2c重要结构体分析图:
http://www.cnitblog.com/Files/luofuchong/i2c%E9%87%8D%E8%A6%81%E7%BB%93%E6%9E%84%E4%BD%93.rar
posted @ 2008-09-15 23:38 lfc 阅读(2673) | 评论 (0)编辑 收藏
最近在看Linux 2.6.21内核的I2C驱动,也在网上查了一下资料,有错也有对,有些心得,记录下来吧。里面认识或许多有不当之处,还恳请指正。
 
1. I2C 协议
 
 1.1  I2C总线工作原理
      I2C总线是由数据线SDA和时钟SCL构成的串行总线,各种被控制器件均并联在这条总线上,每个器件都有一个唯一的地址识别,可以作为总线上的一个发送器件或接收器件(具体由器件的功能决定)
1.2  I2C总线的几种信号状态

      1.  空闲状态:SDASCL都为高电平。

      2.  开始条件(S)SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。

      3.  结束条件(P)SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。

      4.  数据有效:在SCL的高电平期间, SDA保持稳定,数据有效。SDA的改变只能发生在SCL的底电平期间。 

      5.  ACK信号: 数据传输的过程中,接收器件每接收一个字节数据要产生一个ACK信号,向发送器件发出特定的低电平脉冲,表示已经收到数据。

1.3  I2C总线基本操作

      I2C总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL),同时控制总线的传输方向,并产生开始和停止条件。

      数据传输中,首先主器件产生开始条件,随后是器件的控制字节(前七位是从器件的地址,最后一位为读写位 )。接下来是读写操作的数据,以及 ACK响应信号。数据传输结束时,主器件产生停止条件

 

2. Linux I2C 结构分析

2.1 层次分析

1. I2C Core

 I2C Core用于维护Linux的I2C核心部分,其中维护了两个静态的List,分别记录系统中的I2C driver结构和I2C adapter结构。

static LIST_HEAD(adapters);

static LIST_HEAD(drivers);

I2C core提供接口函数,允许一个I2C adatperI2C driverI2C client初始化时在I2C core中进行注册,以及退出时进行注销。具体可以参见i2c_core.c代码。

同时还提供了I2C总线读写访问的一般接口(具体的实现在与I2C控制器相关的I2C adapter中实现),主要应用在I2C设备驱动中。

常用的主要是

i2c_master_send()

i2c_master_recv()

i2c_transfer()

 

2. I2C bus driver

总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。但是总线驱动本身并不会进行任何的通讯,它只是存在在那里,等待设备驱动调用其函数。

在系统开机时,首先装载的是I2C总线驱动。一个总线驱动用于支持一条特定的I2C总线的读写。一个总线驱动通常需要两个模块,一个struct i2c_adapter和一个struct i2c_algorithm来描述:

在 buses目录下的i2c-pxa.c中实现了PXA的I2C总线适配器,I2C adapter 构造一个对I2C core层接口的数据结构,并通过接口函数向I2C core注册一个控制器。I2C adapter主要实现对I2C总线访问的算法,iic_xfer() 函数就是I2C adapter底层对I2C总线读写方法的实现。同时I2C adpter 中还实现了对I2C控制器中断的处理函数。

1) i2c-pxa.c定义了i2c_algorithm,并且实现了master的发送函数i2c_pxa_xfer(),以及设备查询总线的模式的函数i2c_pxa_functionality()

static const struct i2c_algorithm i2c_pxa_algorithm = {
 .master_xfer = i2c_pxa_xfer,
 .functionality = i2c_pxa_functionality,
};

2) i2c-pxa.c中,实现了i2c_adapter,主要是在定义pxa-i2c时进行初始化,并且i2c_pxa_probe()中进行填充parent指针,并且调用

ret = i2c_add_adapter(&i2c->adap);

进行添加。

static struct pxa_i2c i2c_pxa = {
 .lock = SPIN_LOCK_UNLOCKED,
 .adap = {
  .owner  = THIS_MODULE,
  .algo  = &i2c_pxa_algorithm,
  .name  = "pxa2xx-i2c.0",
  .retries = 5,
 },
};

总的来说,在i2c-pxa中,使用platform驱动模型,完成了i2c的总线两种模块struct i2c_adapterstruct i2c_algorithm

 

3. I2C device driver

I2C只有总线驱动是不够的,必须有设备才能工作。这就是I2C device driver的必要性。I2C的device是有两个模块来描述的,struct i2c_driverstruct i2c_client

在介绍chips目录下的device driver前有必要介绍一下i2c-dev.c文件。

      i2c-dev.c中提供了一个通用的I2C设备的驱动程序,实现了字符类 型设备的访问接口,对设备的具体访问是通过I2C adapter来实现的。构造一个对I2C core层接口的数据结构,通过接口函数向 I2C Core注册一个I2C设备驱动。同时构造一个对用户层接口的数据结构,并通过接口函数向内核注册为一个主设备号为89的字符类型设备。

static struct i2c_driver i2cdev_driver = {
 .driver = {
  .name = "dev_driver",
 },
 .id  = I2C_DRIVERID_I2CDEV,
 .attach_adapter = i2cdev_attach_adapter,
 .detach_adapter = i2cdev_detach_adapter,
 .detach_client = i2cdev_detach_client,
};

struct i2c_dev {
 struct list_head list;
 struct i2c_adapter *adap;
 struct device *dev;
};

该 文件提供了用户层对I2C设备的访问,包括open,read,write,ioctl,release等常规文件操作,我们可以通过open函数打开 I2C的设备文件,通过ioctl函数设定要访问从设备的地址,然后就可以通过 read和write函数完成对I2C设备的读写操作。

static const struct file_operations i2cdev_fops = {
 .owner  = THIS_MODULE,
 .llseek  = no_llseek,
 .read  = i2cdev_read,
 .write  = i2cdev_write,
 .ioctl  = i2cdev_ioctl,
 .open  = i2cdev_open,
 .release = i2cdev_release,
};

      注:通过I2C driver提供的通用方法可以访问任何一个I2C的设备,但是其中实现的read,write及ioctl等功能完全是基于一般设备的实现,所有的操作 数据都是基于字节流,没有明确的格式和意义。为了更方便和有效地使用I2C设备,我们可以为一个具体的I2C设备开发特定的I2C设备驱动程序,在驱动中 完成对特定的数据格式的解释以及实现一些专用的功能。

在chips目录下包含着各种device 的driver,完成各种从设备的注册。作为一般的I2C设备,使用i2c-dev.c里的操作足够完成操作了。

当然如果不能完成,则需要独立完成该驱动,这就是chips目录下的代码。 因为i2c-dev.c已经实现了I2C设备的文件操作接口,所以只要实现struct i2c_driver就可以了。对于某些特殊的操作,可以使用command接口进行控制。 当然,对于i2接口的fm芯片,则将struct i2c_driver放在i2c的chips目录下,而将另外fm操作相关的代码放在了/media/radio目录下了。在这个目录下需要完成读写接口 的完成,这个大部分使用V4L2架构。

继续分析中……

posted @ 2008-08-23 11:01 lfc 阅读(9016) | 评论 (3)编辑 收藏
kernel:linux-2.6.22

发现linux下字符驱动用的越来越少了,感觉就剩key、led、rtc还在用了(内核下都有现成的~_~),而且都是因为ioctl的缘故而保留的。
记得曾经在一本书上看到介绍说ioctl机制不好,在以后的内核中会被逐渐摒弃之类的。
如果真是这样的话,那需要用到字符驱动的机会就越来越少了(个人意见,有误的话欢迎指正^_^)

ioctl机制虽然不好,可是发现新版本的内核下字符驱动有了新的应用,重新焕发出生气来:
象spi、i2c这些总线驱动,都会提供一些api接口函数,供设备驱动程序调用以操作总线。
按照这种思路,如果要操作spi、i2c总线的话,有且只能通过驱动来实现。
也就是说:需要编写相应的设备驱动程序来实现。
然而,一些基于spi、i2c的设备驱动具有相当的共通性,所以内核下提供了这么一个通用的spi、i2c字符设备驱动供用户直接调用以操作总线,达到操作设备的目的。

posted @ 2008-08-17 10:48 lfc 阅读(604) | 评论 (0)编辑 收藏
Using the initial RAM disk (initrd)
===================================

Written 1996,2000 by Werner Almesberger <werner.almesberger@epfl.ch> and
Hans Lermen <lermen@fgan.de>


initrd provides the capability to load a RAM disk by the boot loader.
This RAM disk can then be mounted as the root file system and programs
can be run from it. Afterwards, a new root file system can be mounted
from a different device. The previous root (from initrd) is then moved
to a directory and can be subsequently unmounted.

initrd is mainly designed to allow system startup to occur in two phases,
where the kernel comes up with a minimum set of compiled-in drivers, and
where additional modules are loaded from initrd.

This document gives a brief overview of the use of initrd. A more detailed
discussion of the boot process can be found in [1].


Operation
---------

When using initrd, the system typically boots as follows:

1) the boot loader loads the kernel and the initial RAM disk
2) the kernel converts initrd into a "normal" RAM disk and
frees the memory used by initrd
3) if the root device is not /dev/ram0, the old (deprecated)
change_root procedure is followed. see the "Obsolete root change
mechanism" section below.
4) root device is mounted. if it is /dev/ram0, the initrd image is
then mounted as root
5) /sbin/init is executed (this can be any valid executable, including
shell scripts; it is run with uid 0 and can do basically everything
init can do).
6) init mounts the "real" root file system
7) init places the root file system at the root directory using the
pivot_root system call
8) init execs the /sbin/init on the new root filesystem, performing
the usual boot sequence
9) the initrd file system is removed

Note that changing the root directory does not involve unmounting it.
It is therefore possible to leave processes running on initrd during that
procedure. Also note that file systems mounted under initrd continue to
be accessible.


Boot command-line options
-------------------------

initrd adds the following new options:

initrd=<path> (e.g. LOADLIN)

Loads the specified file as the initial RAM disk. When using LILO, you
have to specify the RAM disk image file in /etc/lilo.conf, using the
INITRD configuration variable.

noinitrd

initrd data is preserved but it is not converted to a RAM disk and
the "normal" root file system is mounted. initrd data can be read
from /dev/initrd. Note that the data in initrd can have any structure
in this case and doesn't necessarily have to be a file system image.
This option is used mainly for debugging.

Note: /dev/initrd is read-only and it can only be used once. As soon
as the last process has closed it, all data is freed and /dev/initrd
can't be opened anymore.

root=/dev/ram0

initrd is mounted as root, and the normal boot procedure is followed,
with the RAM disk mounted as root.

Compressed cpio images
----------------------

Recent kernels have support for populating a ramdisk from a compressed cpio
archive. On such systems, the creation of a ramdisk image doesn't need to
involve special block devices or loopbacks; you merely create a directory on
disk with the desired initrd content, cd to that directory, and run (as an
example):

find . | cpio --quiet -H newc -o | gzip -9 -n > /boot/imagefile.img

Examining the contents of an existing image file is just as simple:

mkdir /tmp/imagefile
cd /tmp/imagefile
gzip -cd /boot/imagefile.img | cpio -imd --quiet

Installation
------------

First, a directory for the initrd file system has to be created on the
"normal" root file system, e.g.

# mkdir /initrd

The name is not relevant. More details can be found on the pivot_root(2)
man page.

If the root file system is created during the boot procedure (i.e. if
you're building an install floppy), the root file system creation
procedure should create the /initrd directory.

If initrd will not be mounted in some cases, its content is still
accessible if the following device has been created:

# mknod /dev/initrd b 1 250
# chmod 400 /dev/initrd

Second, the kernel has to be compiled with RAM disk support and with
support for the initial RAM disk enabled. Also, at least all components
needed to execute programs from initrd (e.g. executable format and file
system) must be compiled into the kernel.

Third, you have to create the RAM disk image. This is done by creating a
file system on a block device, copying files to it as needed, and then
copying the content of the block device to the initrd file. With recent
kernels, at least three types of devices are suitable for that:

- a floppy disk (works everywhere but it's painfully slow)
- a RAM disk (fast, but allocates physical memory)
- a loopback device (the most elegant solution)

We'll describe the loopback device method:

1) make sure loopback block devices are configured into the kernel
2) create an empty file system of the appropriate size, e.g.
# dd if=/dev/zero of=initrd bs=300k count=1
# mke2fs -F -m0 initrd
(if space is critical, you may want to use the Minix FS instead of Ext2)
3) mount the file system, e.g.
# mount -t ext2 -o loop initrd /mnt
4) create the console device:
# mkdir /mnt/dev
# mknod /mnt/dev/console c 5 1
5) copy all the files that are needed to properly use the initrd
environment. Don't forget the most important file, /sbin/init
Note that /sbin/init's permissions must include "x" (execute).
6) correct operation the initrd environment can frequently be tested
even without rebooting with the command
# chroot /mnt /sbin/init
This is of course limited to initrds that do not interfere with the
general system state (e.g. by reconfiguring network interfaces,
overwriting mounted devices, trying to start already running demons,
etc. Note however that it is usually possible to use pivot_root in
such a chroot'ed initrd environment.)
7) unmount the file system
# umount /mnt
8) the initrd is now in the file "initrd". Optionally, it can now be
compressed
# gzip -9 initrd

For experimenting with initrd, you may want to take a rescue floppy and
only add a symbolic link from /sbin/init to /bin/sh. Alternatively, you
can try the experimental newlib environment [2] to create a small
initrd.

Finally, you have to boot the kernel and load initrd. Almost all Linux
boot loaders support initrd. Since the boot process is still compatible
with an older mechanism, the following boot command line parameters
have to be given:

root=/dev/ram0 rw

(rw is only necessary if writing to the initrd file system.)

With LOADLIN, you simply execute

LOADLIN <kernel> initrd=<disk_image>
e.g. LOADLIN C:\LINUX\BZIMAGE initrd=C:\LINUX\INITRD.GZ root=/dev/ram0 rw

With LILO, you add the option INITRD=<path> to either the global section
or to the section of the respective kernel in /etc/lilo.conf, and pass
the options using APPEND, e.g.

image = /bzImage
initrd = /boot/initrd.gz
append = "root=/dev/ram0 rw"

and run /sbin/lilo

For other boot loaders, please refer to the respective documentation.

Now you can boot and enjoy using initrd.


Changing the root device
------------------------

When finished with its duties, init typically changes the root device
and proceeds with starting the Linux system on the "real" root device.

The procedure involves the following steps:
- mounting the new root file system
- turning it into the root file system
- removing all accesses to the old (initrd) root file system
- unmounting the initrd file system and de-allocating the RAM disk

Mounting the new root file system is easy: it just needs to be mounted on
a directory under the current root. Example:

# mkdir /new-root
# mount -o ro /dev/hda1 /new-root

The root change is accomplished with the pivot_root system call, which
is also available via the pivot_root utility (see pivot_root(8) man
page; pivot_root is distributed with util-linux version 2.10h or higher
[3]). pivot_root moves the current root to a directory under the new
root, and puts the new root at its place. The directory for the old root
must exist before calling pivot_root. Example:

# cd /new-root
# mkdir initrd
# pivot_root . initrd

Now, the init process may still access the old root via its
executable, shared libraries, standard input/output/error, and its
current root directory. All these references are dropped by the
following command:

# exec chroot . what-follows <dev/console >dev/console 2>&1

Where what-follows is a program under the new root, e.g. /sbin/init
If the new root file system will be used with udev and has no valid
/dev directory, udev must be initialized before invoking chroot in order
to provide /dev/console.

Note: implementation details of pivot_root may change with time. In order
to ensure compatibility, the following points should be observed:

- before calling pivot_root, the current directory of the invoking
process should point to the new root directory
- use . as the first argument, and the _relative_ path of the directory
for the old root as the second argument
- a chroot program must be available under the old and the new root
- chroot to the new root afterwards
- use relative paths for dev/console in the exec command

Now, the initrd can be unmounted and the memory allocated by the RAM
disk can be freed:

# umount /initrd
# blockdev --flushbufs /dev/ram0

It is also possible to use initrd with an NFS-mounted root, see the
pivot_root(8) man page for details.


Usage scenarios
---------------

The main motivation for implementing initrd was to allow for modular
kernel configuration at system installation. The procedure would work
as follows:

1) system boots from floppy or other media with a minimal kernel
(e.g. support for RAM disks, initrd, a.out, and the Ext2 FS) and
loads initrd
2) /sbin/init determines what is needed to (1) mount the "real" root FS
(i.e. device type, device drivers, file system) and (2) the
distribution media (e.g. CD-ROM, network, tape, ...). This can be
done by asking the user, by auto-probing, or by using a hybrid
approach.
3) /sbin/init loads the necessary kernel modules
4) /sbin/init creates and populates the root file system (this doesn't
have to be a very usable system yet)
5) /sbin/init invokes pivot_root to change the root file system and
execs - via chroot - a program that continues the installation
6) the boot loader is installed
7) the boot loader is configured to load an initrd with the set of
modules that was used to bring up the system (e.g. /initrd can be
modified, then unmounted, and finally, the image is written from
/dev/ram0 or /dev/rd/0 to a file)
8) now the system is bootable and additional installation tasks can be
performed

The key role of initrd here is to re-use the configuration data during
normal system operation without requiring the use of a bloated "generic"
kernel or re-compiling or re-linking the kernel.

A second scenario is for installations where Linux runs on systems with
different hardware configurations in a single administrative domain. In
such cases, it is desirable to generate only a small set of kernels
(ideally only one) and to keep the system-specific part of configuration
information as small as possible. In this case, a common initrd could be
generated with all the necessary modules. Then, only /sbin/init or a file
read by it would have to be different.

A third scenario is more convenient recovery disks, because information
like the location of the root FS partition doesn't have to be provided at
boot time, but the system loaded from initrd can invoke a user-friendly
dialog and it can also perform some sanity checks (or even some form of
auto-detection).

Last not least, CD-ROM distributors may use it for better installation
from CD, e.g. by using a boot floppy and bootstrapping a bigger RAM disk
via initrd from CD; or by booting via a loader like LOADLIN or directly
from the CD-ROM, and loading the RAM disk from CD without need of
floppies.


Obsolete root change mechanism
------------------------------

The following mechanism was used before the introduction of pivot_root.
Current kernels still support it, but you should _not_ rely on its
continued availability.

It works by mounting the "real" root device (i.e. the one set with rdev
in the kernel image or with root=... at the boot command line) as the
root file system when linuxrc exits. The initrd file system is then
unmounted, or, if it is still busy, moved to a directory /initrd, if
such a directory exists on the new root file system.

In order to use this mechanism, you do not have to specify the boot
command options root, init, or rw. (If specified, they will affect
the real root file system, not the initrd environment.)

If /proc is mounted, the "real" root device can be changed from within
linuxrc by writing the number of the new root FS device to the special
file /proc/sys/kernel/real-root-dev, e.g.

# echo 0x301 >/proc/sys/kernel/real-root-dev

Note that the mechanism is incompatible with NFS and similar file
systems.

This old, deprecated mechanism is commonly called "change_root", while
the new, supported mechanism is called "pivot_root".


Mixed change_root and pivot_root mechanism
------------------------------------------

In case you did not want to use root=/dev/ram0 to trigger the pivot_root
mechanism, you may create both /linuxrc and /sbin/init in your initrd image.

/linuxrc would contain only the following:

#! /bin/sh
mount -n -t proc proc /proc
echo 0x0100 >/proc/sys/kernel/real-root-dev
umount -n /proc

Once linuxrc exited, the kernel would mount again your initrd as root,
this time executing /sbin/init. Again, it would be the duty of this init
to build the right environment (maybe using the root= device passed on
the cmdline) before the final execution of the real /sbin/init.


Resources
---------

[1] Almesberger, Werner; "Booting Linux: The History and the Future"
http://www.almesberger.net/cv/papers/ols2k-9.ps.gz
[2] newlib package (experimental), with initrd example
http://sources.redhat.com/newlib/
[3] Brouwer, Andries; "util-linux: Miscellaneous utilities for Linux"
ftp://ftp.win.tue.nl/pub/linux-local/utils/util-linux/
posted @ 2008-05-28 11:40 lfc 阅读(2048) | 评论 (4)编辑 收藏
【引】prayaya:
        一个非常有意思的可移动linux发行版,很多地方值得去研究:
        http://www.inlsd.org/

【转】shell十三问:
       http://www.cnitblog.com/Files/luofuchong/shell%E5%8D%81%E4%B8%89%E9%97%AE.rar

【转】shell经典教程:
       http://www.cnitblog.com/Files/luofuchong/shell%E6%95%99%E7%A8%8B.rar

【转】yaffs2源代码情景分析:
       http://www.cnitblog.com/luofuchong/articles/43334.html

【转】基于Video4Linux的USB摄像头图像采集实现:
                      http://www.cnitblog.com/Files/luofuchong/%E5%9F%BA%E4%BA%8EVideo4Linux%E7%9A%84USB%E6%91%84%E5%83%8F%E5%A4%B4%E5%9B%BE%E5%83%8F%E9%87%87%E9%9B%86%E5%AE%9E%E7%8E%B0.rar

注:
    之前忘记添加转帖注明,引起不必要的误会,不好意思哦^_^
  
posted @ 2008-04-27 02:12 lfc 阅读(470) | 评论 (0)编辑 收藏
注:
    今天发现这东西不好找了,还是转一下吧^_^

1:文件系统中/lib有

[root@hjembed /]# ls lib
ld-2.3.2.so            libm.so                libresolv.so
ld-linux.so.2          libm.so.6              libresolv.so.2
libc-2.3.2.so          libnss_dns-2.3.2.so    librt-2.3.2.so
libc.so                libnss_dns.so          librt.so
libc.so.6              libnss_dns.so.2        librt.so.1
libcrypt-2.3.2.so      libnss_files-2.3.2.so  libstdc++.so
libcrypt.so            libnss_files.so        libstdc++.so.6
libcrypt.so.1          libnss_files.so.2      libstdc++.so.6.0.1
libdl-2.3.2.so         libpng.a               libutil-2.3.2.so
libdl.so               libpng.so              libutil.so
libdl.so.2             libpng.so.3            libutil.so.1
libgcc_s.so            libpng.so.3.1.2.15     libuuid.so.1
libgcc_s.so.1          libpthread-0.10.so     libuuid.so.1.2
libjpeg.so             libpthread.so          libz.so
libjpeg.so.62          libpthread.so.0        libz.so.1
libjpeg.so.62.0.0      libpthread.so_orig     libz.so.1.2.3
libm-2.3.2.so          libresolv-2.3.2.so    
上面与此相关的是libnss*  libresolv*

2: 四个文件
[root@hjembed /]# cat /etc/hosts
127.0.0.1  localhost
59.69.74.87 hujunlinux     #为我开发的host 机器

[root@hjembed /]# cat /etc/resolve.conf
nameserver  XXXXXX          #设置DNS服务器                                                                          
[root@hjembed /]# cat /etc/host.conf
order hosts,bind

还有一个nsswitch.conf , 我是直接从host machine: FC2  下考出来的

[root@hjembed /]#  cat /etc/nsswitch.conf
#
# /etc/nsswitch.conf
#
# An example Name Service Switch config file. This file should be
# sorted with the most-used services at the beginning.
#
# The entry '[NOTFOUND=return]' means that the search for an
# entry should stop if the search in the previous entry turned
# up nothing. Note that if the search failed due to some other reason
# (like no NIS server responding) then the search continues with the
# next entry.
#
# Legal entries are:
#
#       nisplus or nis+         Use NIS+ (NIS version 3)
#       nis or yp               Use NIS (NIS version 2), also called YP
#       dns                     Use DNS (Domain Name Service)
#       files                   Use the local files
#       db                      Use the local database (.db) files
#       compat                  Use NIS on compat mode
#       hesiod                  Use Hesiod for user lookups
#       [NOTFOUND=return]       Stop searching if not found so far
#
                                                                               
# To use db, put the "db" in front of "files" for entries you want to be
# looked up first in the databases
#
# Example:
#passwd:    db files nisplus nis
#shadow:    db files nisplus nis
#group:     db files nisplus nis
                                                                               
passwd:     files
shadow:     files
group:      files
                                                                               
#hosts:     db files nisplus nis dns
hosts:      files dns
                                                                               
# Example - obey only what nisplus tells us...
#services:   nisplus [NOTFOUND=return] files
#networks:   nisplus [NOTFOUND=return] files
#protocols:  nisplus [NOTFOUND=return] files
#rpc:        nisplus [NOTFOUND=return] files
#ethers:     nisplus [NOTFOUND=return] files
#netmasks:   nisplus [NOTFOUND=return] files
                                                                               
bootparams: nisplus [NOTFOUND=return] files
                                                                               
ethers:     files
netmasks:   files
networks:   files
protocols:  files
rpc:        files
services:   files
                                                                               
netgroup:   files
                                                                               
publickey:  nisplus
                                                                               
automount:  files
aliases:    files nisplus
 
3:试验:                                                                            

[root@hjembed /]# ping www.baidu.com
PING www.a.shifen.com (211.94.144.100): 56 data bytes
                                                                               
--- www.a.shifen.com ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

[root@hjembed /]# ping hujunlinux       (主机名)
PING hujunlinux (59.69.74.87): 56 data bytes
64 bytes from 59.69.74.87: icmp_seq=0 ttl=64 time=0.5 ms
64 bytes from 59.69.74.87: icmp_seq=1 ttl=64 time=0.5 ms
64 bytes from 59.69.74.87: icmp_seq=2 ttl=64 time=0.5 ms
64 bytes from 59.69.74.87: icmp_seq=3 ttl=64 time=0.5 ms
64 bytes from 59.69.74.87: icmp_seq=4 ttl=64 time=0.5 ms
                                                                               
--- hujunlinux ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.5/0.5/0.5 ms


ok!



posted @ 2008-04-24 17:01 lfc 阅读(1572) | 评论 (1)编辑 收藏
仅列出标题
共12页: First 4 5 6 7 8 9 10 11 12