所谓技术

-----simple,sometimes naive!
posts - 11, comments - 0, trackbacks - 0, articles - 0
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2008年5月28日

这是2.6.15以前某个版本,2.6.15已经略有不同,但总体思想还是差不多

输入子系统大致实现方法:

   底层驱动层(input_dev)-----<通过结构体input_handle关联>-----输入事件处理层类接口(input_handler)-----<输入核心层input.c>-----应用层

-----------------------------------------------------
struct input_handle { //用于关联底层驱动层input_dev和事件处理层input_handler

 void *private;

 int open;

 struct input_dev *dev;
 struct input_handler *handler;

 struct input_handle *dnext;
 struct input_handle *hnext;
};
-----------------------------------------------------
void input_register_device(struct input_dev *dev)
{
 struct input_handler *handler = input_handler;
 struct input_handle *handle;

/*
 * Initialize repeat timer to default values.
 */

 init_timer(&dev->timer);
 dev->timer.data = (long) dev;
 dev->timer.function = input_repeat_key;
 dev->rep[REP_DELAY] = HZ/4;
 dev->rep[REP_PERIOD] = HZ/33;

/*
 * Add the device.
 */

 if (input_number >= INPUT_DEVICES) {
  printk(KERN_WARNING "input: ran out of input device numbers!\n");
  dev->number = input_number;
 } else {
  dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
  set_bit(dev->number, input_devices);     //编号此输入设备
 }       //input_devices[8],8*32(BITS_PER_LONG)=256b,256 minor for each major
  
 dev->next = input_dev;    //插入到单链表首 
 input_dev = dev;
 input_number++;

/*
 * Notify handlers.
 */

 while (handler) {     //故应先通过input_register_handler注册handler到单链表中,即输入子系统的第二层:事件处理层
        //事件处理层是类通用的,如endev,tsdev,mousedev等
        //且某个具体的驱动层设备可以关联多个事件处理层接口,生成多个节点
        //用户程序根据打开的节点判断调用某一类事件处理层接口,进而关联驱动层
  if ((handle = handler->connect(handler, dev)))
   input_link_handle(handle);
                                                  -------------------------------
                                                  static void input_link_handle(struct input_handle *handle)
                                                  {
                                                    handle->dnext = handle->dev->handle;
                                                    handle->hnext = handle->handler->handle;
                                                    handle->dev->handle = handle;
                                                    handle->handler->handle = handle;
                                                  }
                                                  -------------------------------
  handler = handler->next;
 }
}


------------------------------------------------
以endev为例:


static struct input_handler evdev_handler = {
 event:  evdev_event,
 connect: evdev_connect,
 disconnect: evdev_disconnect,
 fops:  &evdev_fops,
 minor:  EVDEV_MINOR_BASE,
};

static struct file_operations evdev_fops = {
 owner:  THIS_MODULE,
 read:  evdev_read,
 write:  evdev_write,
 poll:  evdev_poll,
 open:  evdev_open,
 release: evdev_release,
 ioctl:  evdev_ioctl,
 fasync:  evdev_fasync,
};


-------------------------------------

void input_register_handler(struct input_handler *handler)
{
 struct input_dev *dev = input_dev;
 struct input_handle *handle;

/*
 * Add minors if needed.
 */

 if (handler->fops != NULL)
  input_table[handler->minor >> 5] = handler;

/*
 * Add the handler.
 */

 handler->next = input_handler;   //插入到单链表首
 input_handler = handler;
 
/*
 * Notify it about all existing devices.
 */

 while (dev) {
  if ((handle = handler->connect(handler, dev)))  
   input_link_handle(handle);
  dev = dev->next;
 }
}


----------------------------------------
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
{
 struct evdev *evdev;
 int minor;

 for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); //evdev_table记录endev的个数
 if (minor == EVDEV_MINORS) {
  printk(KERN_ERR "evdev: no more free evdev devices\n");
  return NULL;
 }

 if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))           //申请一个新的endev
  return NULL;
 memset(evdev, 0, sizeof(struct evdev));

 init_waitqueue_head(&evdev->wait);

 evdev->minor = minor;
 evdev_table[minor] = evdev;       //添加到evdev_table

 evdev->handle.dev = dev;       //实现驱动层和事件处理层的关联
 evdev->handle.handler = handler;
 evdev->handle.private = evdev;

 evdev->exist = 1;

 evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);

// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);

 return &evdev->handle;
}
------------------------------------------
devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
{
 char devfs_name[16];
 sprintf(devfs_name, name, minor);     //创建设备节点:INPUT_MAJOR=13,
          //minor_base+minor:
          //       EVDEV_MINOR_BASE(64)+(0-31);
          //       MOUSEDEV_MINOR_BASE(32)+(0-31);
          //       JOYDEV_MINOR_BASE(0)+(0-31);
          //       TSDEV_MINOR_BASE(128)+(0-31);
          //input_devfs_handle=devfs_mk_dir(NULL, "input", NULL);
          //在/dev/input/下可看到相关的input设备节点

 return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
  S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL);
}
-----------------------------------------
static int __init input_init(void)
{
 if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
  printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
  return -EBUSY;
 }
 input_devfs_handle = devfs_mk_dir(NULL, "input", NULL);
 return 0;
}


----------------------------------------
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
 struct input_handle *handle = dev->handle;

/*
 * Filter non-events, and bad input values out.
 */

 if (type > EV_MAX || !test_bit(type, dev->evbit))
  return;

 switch (type) {

  case EV_KEY:

   if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
    return;

   if (value == 2) break;

   change_bit(code, dev->key);

   if (test_bit(EV_REP, dev->evbit) && dev->timer.function) {
    if (value) {
     mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]);
     dev->repeat_key = code;
     break;
    }
    if (dev->repeat_key == code)
     del_timer(&dev->timer);
   }

   break;
  
  case EV_ABS:

   if (code > ABS_MAX || !test_bit(code, dev->absbit))
    return;

   if (dev->absfuzz[code]) {
    if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
        (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
     return;

    if ((value > dev->abs[code] - dev->absfuzz[code]) &&
        (value < dev->abs[code] + dev->absfuzz[code]))
     value = (dev->abs[code] * 3 + value) >> 2;

    if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
        (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
     value = (dev->abs[code] + value) >> 1;
   }

   if (dev->abs[code] == value)
    return;

   dev->abs[code] = value;
   break;

  case EV_REL:

   if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
    return;

   break;

  case EV_MSC:

   if (code > MSC_MAX || !test_bit(code, dev->mscbit))
    return;
 
   break;

  case EV_LED:
 
   if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
    return;

   change_bit(code, dev->led);
   if (dev->event) dev->event(dev, type, code, value); 
 
   break;

  case EV_SND:
 
   if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value)
    return;

   change_bit(code, dev->snd);
   if (dev->event) dev->event(dev, type, code, value); 
 
   break;

  case EV_REP:

   if (code > REP_MAX || dev->rep[code] == value) return;

   dev->rep[code] = value;
   if (dev->event) dev->event(dev, type, code, value);

   break;

  case EV_FF:
   if (dev->event) dev->event(dev, type, code, value);
   break;
 }

/*
 * Distribute the event to handler modules.
 */

 while (handle) {
                 //遍历每个打开的handle
  if (handle->open)
          //when open a input device,record it once time
          //in function input_open_device,handle->open++; 
   handle->handler->event(handle, type, code, value);
  handle = handle->dnext;
 }
}
-----------------------------------
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
 struct evdev *evdev = handle->private;
 struct evdev_list *list = evdev->list;

 while (list) {

  do_gettimeofday(&list->buffer[list->head].time);
  list->buffer[list->head].type = type;
  list->buffer[list->head].code = code;
  list->buffer[list->head].value = value;
  list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);

  kill_fasync(&list->fasync, SIGIO, POLL_IN);

  list = list->next;
 }

 wake_up_interruptible(&evdev->wait);   //填充数据结构,并唤醒相关的等待进程。
}
-----------------------------------

 

至于何时打开:
static struct file_operations input_fops = {
 owner: THIS_MODULE,
 open: input_open_file,
};
-----------------------------------
static int input_open_file(struct inode *inode, struct file *file)
{
 struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];  //LINUX最多8类事件处理层接口,各32个节点
             //打开某个设备时,根据节点大小选择事件处理层接口
 struct file_operations *old_fops, *new_fops = NULL;
 int err;

 /* No load-on-demand here? */
 if (!handler || !(new_fops = fops_get(handler->fops)))               //得到相应的事件处理层接口的操作接口
  return -ENODEV;

 /*
  * That's _really_ odd. Usually NULL ->open means "nothing special",
  * not "no device". Oh, well...
  */
 if (!new_fops->open) {
  fops_put(new_fops);
  return -ENODEV;
 }
 old_fops = file->f_op;
 file->f_op = new_fops;

 lock_kernel();
 err = new_fops->open(inode, file);                   //进一步调用
 unlock_kernel();

 if (err) {
  fops_put(file->f_op);
  file->f_op = fops_get(old_fops);
 }
 fops_put(old_fops);
 return err;
}
---------------------------------------
static int evdev_open(struct inode * inode, struct file * file)
{
 struct evdev_list *list;
 int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;         

 if (i >= EVDEV_MINORS || !evdev_table[i])
  return -ENODEV;

 if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
  return -ENOMEM;
 memset(list, 0, sizeof(struct evdev_list));

 list->evdev = evdev_table[i];                           //得到底层驱动层
 list->next = evdev_table[i]->list;
 evdev_table[i]->list = list;

 file->private_data = list;

 if (!list->evdev->open++)     //若未打开,则调用input_open_device并标识为打开
  if (list->evdev->exist)
   input_open_device(&list->evdev->handle);

 return 0;
}
--------------------------------------
int input_open_device(struct input_handle *handle)
{
 handle->open++;      //打开handle实现
 if (handle->dev->open)
  return handle->dev->open(handle->dev);  //驱动层若有open,进一步实现
 return 0;
}

posted @ 2008-05-28 21:28 vsolo 阅读(1468) | 评论 (0)编辑 收藏

2008年5月20日

AT91SAM9261中内部ROM有32K,可惜启动代码只用了不到8K的空间,目前看来还是有浪费之嫌的(想想当年51就寒碜)
上电启动代码的反汇编,只走了第一个S文件:

ROM:00400000                 AREA ROM, CODE, READWRITE, ALIGN=0
ROM:00400000                 ; ORG 0x400000
ROM:00400000                 CODE32
ROM:00400000                 B       loc_400020    //Reset
ROM:00400000 ; --------------------------------------------------------------------------------
ROM:00400004                 DCB 0xFE ;       //Other Exception vectors
ROM:00400005                 DCB 0xFF
ROM:00400006                 DCB 0xFF
ROM:00400007                 DCB 0xEA ;
ROM:00400008                 DCB 0x2F ;
ROM:00400009                 DCB    0
ROM:0040000A                 DCB    0
ROM:0040000B                 DCB 0xEA ;
ROM:0040000C                 DCB 0xFE ;
ROM:0040000D                 DCB 0xFF
ROM:0040000E                 DCB 0xFF
ROM:0040000F                 DCB 0xEA ;
ROM:00400010                 DCB 0xFE ;
ROM:00400011                 DCB 0xFF
ROM:00400012                 DCB 0xFF
ROM:00400013                 DCB 0xEA ;
ROM:00400014                 DCB 0xFE ;
ROM:00400015                 DCB 0xFF
ROM:00400016                 DCB 0xFF
ROM:00400017                 DCB 0xEA ;
ROM:00400018                 DCB 0xFE ;
ROM:00400019                 DCB 0xFF
ROM:0040001A                 DCB 0xFF
ROM:0040001B                 DCB 0xEA ;
ROM:0040001C                 DCB 0xFE ;
ROM:0040001D                 DCB 0xFF
ROM:0040001E                 DCB 0xFF
ROM:0040001F                 DCB 0xEA ;
ROM:00400020 ; --------------------------------------------------------------------------------
ROM:00400020
ROM:00400020 loc_400020                             
ROM:00400020                 MOV     SP, #0x328000   //stack setup
ROM:00400024                 LDR     R1, =0xFFFFFC00   //即LDR  R1, =AT91C_PMC_SCER ;(PMC) System Clock Enable Register
ROM:00400028                 LDR     R0, =0x4001
ROM:0040002C                 STR     R0, [R1,#0x20]   //即STR  R0, [R1,#MOR] ;(PMC) Main Oscillator Register
ROM:00400030                 MOV     R4, #1
ROM:00400034
ROM:00400034 loc_400034                             
ROM:00400034                 LDR     R3, [R1,#0x68]   //即LDR   R3, [R1,#SR] ;(PMC) Status Register
ROM:00400038                 AND     R3, R4, R3
ROM:0040003C                 CMP     R3, #1
ROM:00400040                 BNE     loc_400034    //等待主时钟振荡器稳定
ROM:00400044                 MOV     R0, #1
ROM:00400048                 STR     R0, [R1,#0x30]   //即STR   R0, [R1,#MCKR] ;(PMC) Master Clock Register
ROM:0040004C                 MOV     R4, #8
ROM:00400050
ROM:00400050 loc_400050                             
ROM:00400050                 LDR     R3, [R1,#0x68]   //读取PMC状态
ROM:00400054                 AND     R3, R4, R3
ROM:00400058                 CMP     R3, #8
ROM:0040005C                 BNE     loc_400050
ROM:00400060                 ADR     R2, off_400094   //等待芯片时钟稳定
ROM:00400064                 LDMIA   R2, {R0,R1,R3,R4}
ROM:00400068                 CMP     R0, R1
ROM:0040006C                 BEQ     loc_400080
ROM:00400070
ROM:00400070 loc_400070                             
ROM:00400070                 CMP     R1, R3    //copy RW section to IRAM
ROM:00400074                 LDRCC   R2, [R0],#4
ROM:00400078                 STRCC   R2, [R1],#4
ROM:0040007C                 BCC     loc_400070
ROM:00400080
ROM:00400080 loc_400080                             
ROM:00400080                 MOV     R2, #0
ROM:00400084
ROM:00400084 loc_400084                            
ROM:00400084                 CMP     R3, R4    //copy ZI section to IRAM and Zero init
ROM:00400088                 STRCC   R2, [R3],#4
ROM:0040008C                 BCC     loc_400084
ROM:00400090                 B       loc_4000A4
ROM:00400090 ; --------------------------------------------------------------------------------
ROM:00400094 off_400094      DCD 0x401E9C     //|Image$$RO$$Limit|
ROM:00400098                 DCB    0     //|Image$$RW$$Base|
ROM:00400099                 DCB 0x70 ; p     
ROM:0040009A                 DCB 0x32 ; 2
ROM:0040009B                 DCB    0     
ROM:0040009C                 DCB 0x10     //|Image$$ZI$$Base|
ROM:0040009D                 DCB 0x70 ; p
ROM:0040009E                 DCB 0x32 ; 2
ROM:0040009F                 DCB    0     
ROM:004000A0                 DCB 0x88 ; ?     //|Image$$ZI$$Limit|
ROM:004000A1                 DCB 0x70 ; p
ROM:004000A2                 DCB 0x32 ; 2
ROM:004000A3                 DCB    0
ROM:004000A4 ; --------------------------------------------------------------------------------
ROM:004000A4
ROM:004000A4 loc_4000A4                             
ROM:004000A4                 LDR     R0, =sub_401690
ROM:004000A8                 MOV     LR, PC
ROM:004000AC                 BX      R0
ROM:004000B0                 LDR     R0, =sub_40066C
ROM:004000B4                 MOV     LR, PC
ROM:004000B8                 BX      R0
ROM:004000BC                 MRC     p15, 0, R5,c1,c0
ROM:004000C0                 MOV     R6, #0x1000
ROM:004000C4                 ORR     R5, R5, R6
ROM:004000C8                 MCR     p15, 0, R5,c1,c0
ROM:004000CC
ROM:004000CC loc_4000CC                             
ROM:004000CC                 LDR     R0, =sub_401338
ROM:004000D0                 MOV     LR, PC
ROM:004000D4                 BX      R0     //Jump to main Function
ROM:004000D8
ROM:004000D8 loc_4000D8                             
ROM:004000D8                 B       loc_4000D8    //Normally, never occur.

posted @ 2008-05-20 22:24 vsolo 阅读(1416) | 评论 (0)编辑 收藏

2008年4月26日

(1)  系统启动初始化时iotable_init()
-----------------------------
MACHINE_START(AT91SAM9261EK, "ATMEL AT91SAM9261")
············································
        .map_io         = at91sam9261_map_io,
············································
MACHINE_END
--------------------------------------
void __init at91sam9261_map_io(void)
{
 iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
}
--------------------------------------
/*
 * System peripheral registers mapped at virtual address.
 */

static struct map_desc at91sam9261_io_desc[] __initdata = {
 {
  .virtual = AT91C_VA_BASE_SYS,
  .pfn = __phys_to_pfn(AT91C_BASE_AIC),
  .length = SZ_4K,
  .type = MT_DEVICE
 },
 {
  .virtual = AT91C_VA_BASE_EBI,
  .pfn = __phys_to_pfn(AT91C_BASE_EBI),
  .length = SZ_4K,
  .type = MT_DEVICE
 },
     ··············································
};

<./linux/include/asm-arm/map.h>-----------------------
struct map_desc {
 unsigned long virtual;
 unsigned long pfn;
 unsigned long length;
 unsigned int type;   //标志位:domain、read、write、cache、buffer
};

#define __phys_to_pfn(paddr)             ((paddr) >> PAGE_SHIFT)
#define __pfn_to_phys(pfn)                 ((pfn) << PAGE_SHIFT)
--------------------------------------
    iotable_init()函数<./arch/arm/mm/mm-armv.c>循环调用create_mapping()函数完成IO的虚拟地址到物理地址的映射。


(2)  系统启动后,在驱动中ioremap()
--------------------------------------
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,    //片上的各个设备
&s3c_device_lcd,    //下面以s3c_device_lcd为例
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};
--------------------------------------
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",  //此处设备的命名应和相应驱动程序命名一致以实现driver bind
.id = -1,                        //-1表示不支持同类多个设备
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};

-------------------------------------
/* LCD Controller */
static struct resource s3c_lcd_resource[] = {   //LCD的两个资源
[0] = {
.start = S3C2410_PA_LCD,
.end = S3C2410_PA_LCD + S3C2410_SZ_LCD,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}

};
------------------------------------
/* -------Resource type -------- */
#define IORESOURCE_IO                 0x00000100       
#define IORESOURCE_MEM                 0x00000200
#define IORESOURCE_IRQ                 0x00000400
#define IORESOURCE_DMA                 0x00000800
------------------------------------

-----s3c_device_lcd的resource中硬件地址---------------

#define S3C2410_LCDREG(x) (x)

/* LCD control registers */
#define S3C2410_LCDCON1     S3C2410_LCDREG(0x00)
#define S3C2410_LCDCON2     S3C2410_LCDREG(0x04)
#define S3C2410_LCDCON3     S3C2410_LCDREG(0x08)
#define S3C2410_LCDCON4     S3C2410_LCDREG(0x0C)
#define S3C2410_LCDCON5     S3C2410_LCDREG(0x10)

/* LCD controller */
#define S3C2410_PA_LCD    (0x4D000000)
#define S3C24XX_SZ_LCD    SZ_1M
-----------------------------------
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*
*/
int platform_device_register(struct platform_device * pdev)
{
device_initialize(&pdev->dev);        //初始化设备结构
return platform_device_add(pdev); //添加一个片上的设备到设备层
}
------------------------------------------
/**
 * platform_device_add - add a platform device to device hierarchy
 * @pdev: platform device we're adding
 *
 * This is part 2 of platform_device_register(), though may be called
 * separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
 int i, ret = 0;
 if (!pdev)
  return -EINVAL;

 if (!pdev->dev.parent)
  pdev->dev.parent = &platform_bus;
 pdev->dev.bus = &platform_bus_type;

 if (pdev->id != -1)
  snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
                 /* 若支持同类多个设备,则用pdev->name和pdev->id在总线上标识该设备  */
 else
  strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
                /*               否则,用pdev->name(即"s3c2410-lcd")在总线上标识该设备               */

 for (i = 0; i < pdev->num_resources; i++) {
                /*           遍历资源数,并为各自在总线地址空间请求分配            */
  struct resource *p, *r = &pdev->resource[i];

  if (r->name == NULL)
   r->name = pdev->dev.bus_id;

  p = r->parent;
  if (!p) {
   if (r->flags & IORESOURCE_MEM)
      p = &iomem_resource; 
                                          /*    LCD寄存器地址作为IO内存资源分配   */
                                                      ----------------
                                                      struct resource iomem_resource = {
                                                              .name   = "PCI mem",
                                                              .start  = 0UL,
                                                              .end    = ~0UL,
                                                              .flags  = IORESOURCE_MEM,
                                                               };
                                                      ----------------
   else if (r->flags & IORESOURCE_IO)
      p = &ioport_resource;
  }
                      
  if (p && insert_resource(p, r)) {
                              /*   将LCD寄存器地址插入到IO内存空间  */
   printk(KERN_ERR
          "%s: failed to claim resource %d\n",
          pdev->dev.bus_id, i);
   ret = -EBUSY;
   goto failed;
  }
 }

 pr_debug("Registering platform device '%s'. Parent at %s\n",
   pdev->dev.bus_id, pdev->dev.parent->bus_id);

 ret = device_add(&pdev->dev);
 if (ret == 0)
  return ret;

 failed:
 while (--i >= 0)
  if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
   release_resource(&pdev->resource[i]);
 return ret;
}
-----------------------------------------


static struct platform_driver s3c2410fb_driver = {
 .probe  = s3c2410fb_probe,
 .remove  = s3c2410fb_remove,
 .suspend = s3c2410fb_suspend,
 .resume  = s3c2410fb_resume,
 .driver  = {
  .name = "s3c2410-lcd",
  .owner = THIS_MODULE,
 },
};

platform_driver_register(&s3c2410fb_driver)----->
driver_register(&drv->driver)----->
bus_add_driver(drv)----->
driver_attach(drv)----->
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)----->
__driver_attach(struct device * dev, void * data)----->
driver_probe_device(drv, dev)----->
really_probe(dev, drv)----->

在really_probe()中:
            为设备指派管理该设备的驱动:dev->driver = drv
            调用s3c2410fb_probe()初始化设备:drv->probe(dev)

---------------------------------
static int __init s3c2410fb_probe(struct platform_device *pdev)
{
 ·····························
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                /*          取得LCD控制寄存器的物理地址           */

 size = (res->end - res->start)+1;
 info->mem = request_mem_region(res->start, size, pdev->name);
               /* 个人理解:设备注册时已经分配区域,驱动这里应该不是必须的*/

 info->io = ioremap(res->start, size);
               /*      此时驱动便可以用指针info->io  读写LCD控制寄存器了    */
               /*              eg: readl(info->io + S3C2410_LCDCON1)              */
 ····························
}

--------------------------------
以下是AT91SAM9261EK的IOMEM:

root@ebd9261:~# cat /proc/iomem
00500000-005fffff : usb-ohci.0
  00500000-005fffff : ohci_hcd
00600000-00600fff : sidsa-lcdc.0     //支持同类多个设备,在驱动中未分配I/O内存区域
20000000-23ffffff : System RAM
  20022000-20225e47 : Kernel text
  20226000-2028da23 : Kernel data
30000000-30000003 : dm9000.0   
  30000000-30000003 : dm9000   
30000044-300000ff : dm9000.0
  30000044-300000ff : dm9000
fffa4000-fffa7fff : at91_udc            //不支持同类多个设备,在驱动中也分配I/O内存区域
  fffa4000-fffa7fff : at91_udc
fffb0000-fffb3fff : usart.1
fffb4000-fffb7fff : usart.2
fffc8000-fffcbfff : spi.0
fffff200-fffff3ff : usart.0

posted @ 2008-04-26 16:02 vsolo 阅读(3301) | 评论 (0)编辑 收藏

2008年4月25日

(1)系统启动时注册中断:
-----------------------------------
#define IRQ_BATT_FLT   S3C2410_IRQ(7)
······························
#define IRQ_LCD        S3C2410_IRQ(16)     /* 32 */
······························
#define IRQ_ADCPARENT  S3C2410_IRQ(31)

/* interrupts generated from the external interrupts sources */
#define IRQ_EINT4      S3C2410_IRQ(32)    /* 48 */
#define IRQ_EINT5      S3C2410_IRQ(33)


----------------------------------
MACHINE_START(SMDK2410, "SMDK2410")
··································
 .init_irq = smdk2410_init_irq,   //中断初始化函数
··································
MACHINE_END
----------------------------------
/*
 * Set of macros to define architecture features.  This is built into
 * a table by the linker.
 */
#define MACHINE_START(_type,_name)   \
static const struct machine_desc __mach_desc_##_type \
 __attribute_used__     \
 __attribute__((__section__(".arch.info.init"))) = { \
 .nr  = MACH_TYPE_##_type,  \
 .name  = _name,

#define MACHINE_END    \
};

----------------------------------

函数smdk2410_init_irq()的调用过程
<./linux/arch/arm/kernel/head.S>---------------------
/*
 * Lookup machine architecture in the linker-build list of architectures.
 * Note that we can't use the absolute addresses for the __arch_info
 * lists since we aren't running with the MMU on (and therefore, we are
 * not in the correct address space).  We have to calculate the offset.
 *
 *  r1 = machine architecture number
 * Returns:
 *  r3, r4, r6 corrupted
 *  r5 = mach_info pointer in physical address space
 */
 .type __lookup_machine_type, %function
__lookup_machine_type:
 adr r3, 3b
 ldmia r3, {r4, r5, r6}
 sub r3, r3, r4   @ get offset between virt&phys
 add r5, r5, r3   @ convert virt addresses to
 add r6, r6, r3   @ physical address space
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
 teq r3, r1    @ matches loader number?
 beq 2f    @ found
 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
 cmp r5, r6
 blo 1b
 mov r5, #0    @ unknown machine
2: mov pc, lr

/*
 * This provides a C-API version of the above function.
 */
ENTRY(lookup_machine_type)
 stmfd sp!, {r4 - r6, lr}
 mov r1, r0
 bl __lookup_machine_type
 mov r0, r5
 ldmfd sp!, {r4 - r6, pc}
--------------------------------

在start_kernel()中:

        setup_arch(&command_line):
                            mdesc = setup_machine(machine_arch_type);
                              // 此函数将调用head.S中的lookup_machine_type得到对应
                              // machine_arch_type的machine_desc
                            init_arch_irq = mdesc->init_irq;  //指向smdk2410_init_irq

        init_IRQ():
                            init_arch_irq(); //执行smdk2410_init_irq()
                                                    //完成中断初始化

--------------------------------
static void __init smdk2410_init_irq(void)
{
 s3c24xx_init_irq();
}
--------------------------------
void __init s3c24xx_init_irq(void)
{
·····················
 /* register the main interrupts */

 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");

 for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {
  /* set all the s3c2410 internal irqs */

  switch (irqno) {
   /* deal with the special IRQs (cascaded) */

  case IRQ_UART0:
  case IRQ_UART1:
  case IRQ_UART2:
  case IRQ_ADCPARENT:
   set_irq_chip(irqno, &s3c_irq_level_chip);
   set_irq_handler(irqno, do_level_IRQ);
   break;

  case IRQ_RESERVED6:
  case IRQ_RESERVED24:
   /* no IRQ here */
   break;

  default:/*        非级联中断的中断例程相同        */
   //irqdbf("registering irq %d (s3c irq)\n", irqno);
   set_irq_chip(irqno, &s3c_irq_chip);
   set_irq_handler(irqno, do_edge_IRQ);
   set_irq_flags(irqno, IRQF_VALID);
  }
 }

 /* setup the cascade irq handlers */
               /*              级联中断有各自的中断例程           */
 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);


 /* external interrupts */

 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
  irqdbf("registering irq %d (ext int)\n", irqno);
  set_irq_chip(irqno, &s3c_irq_eint0t4);
  set_irq_handler(irqno, do_edge_IRQ);
  set_irq_flags(irqno, IRQF_VALID);
 }

 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
  irqdbf("registering irq %d (extended s3c irq)\n", irqno);
  set_irq_chip(irqno, &s3c_irqext_chip);
  set_irq_handler(irqno, do_edge_IRQ);
  set_irq_flags(irqno, IRQF_VALID);
 }
······················

}
        其中中断例程do_edge_IRQ()  ->  __do_irq() 中ret = action->handler(irq, action->dev_id, regs)
完成驱动中的中断处理例程s3c2410fb_irq的调用。
-------------------------------------

(2)驱动申请中断:
        ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
其中irq即为IRQ_LCD;

-------------------------------------
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
   unsigned long irq_flags, const char * devname, void *dev_id)
{
 unsigned long retval;
 struct irqaction *action;

 if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
     (irq_flags & SA_SHIRQ && !dev_id))
  return -EINVAL;
               /*              检查中断号irq是否注册(有效)              */

 action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
 if (!action)
  return -ENOMEM;

 action->handler = handler;
 action->flags = irq_flags;
 cpus_clear(action->mask);
 action->name = devname;
 action->next = NULL;
 action->dev_id = dev_id;

 retval = setup_irq(irq, action);
               / * 关联中断处理例程到对应的中断描述结构体irqdesc */

 if (retval)
  kfree(action);
 return retval;
}
<./linux/include/asm-arm/mach/irq.h>------------------------
struct irqdesc {
 irq_handler_t handle;
 struct irqchip *chip;
 struct irqaction *action;
 struct list_head pend;
 void  *chipdata;
 void  *data;
 unsigned int disable_depth;

 unsigned int triggered: 1;  /* IRQ has occurred       */
 unsigned int running  : 1;  /* IRQ is running             */
 unsigned int pending  : 1;  /* IRQ is pending       */
 unsigned int probing  : 1;  /* IRQ in use for a probe     */
 unsigned int probe_ok : 1;  /* IRQ can be used for probe  */
 unsigned int valid    : 1;  /* IRQ claimable       */
 unsigned int noautoenable : 1; /* don't automatically enable IRQ */
 unsigned int unused   :25;

 struct proc_dir_entry *procdir;

#ifdef CONFIG_SMP
 cpumask_t affinity;
 unsigned int cpu;
#endif

 /*
  * IRQ lock detection
  */
 unsigned int lck_cnt;
 unsigned int lck_pc;
 unsigned int lck_jif;
};

posted @ 2008-04-25 16:42 vsolo 阅读(1390) | 评论 (0)编辑 收藏

2008年4月21日

       Uboot完成系统的引导并将Linux内核拷贝到内存之后,bootm -> do_bootm_linux()跳转到kernel的起始位置;
       压缩过的kernel入口在arch/arm/boot/compressed/head.S,它将调用函数decompress_kernel()<./arch/arm/boot/compressed/misc.c>解压,打印“Uncompressing Linux...”,调用gunzip(),打印"done, booting the kernel."
       然后call_kernel,执行解压后的kernel,经linux/arch/arm/kernel/head.S调用start_kernel转入体系结构无关的通用C代码,在start_kernel()中完成了一系列系统初始化,设备及驱动的注册即在此时完成:

<./init/main.c>-------------------------

asmlinkage void __init start_kernel(void)
{
 char * command_line;
 extern struct kernel_param __start___param[], __stop___param[];

···········································································
 printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);
                                                          //打印内核命令行
 parse_early_param();
 parse_args("Booting kernel", command_line, __start___param,
     __stop___param - __start___param,
     &unknown_bootoption);
                                                        //解析由BOOT传递的启动参数
···········································································

 /* Do the rest non-__init'ed, we're now alive */
 rest_init();
}

start_kernel()中的函数rest_init()将创建第一个核心线程kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND),调用init()函数:

static int init(void * unused)-------------------
{
                ·······················
                 do_basic_setup();
                ······················

 /*
  * We try each of these until one succeeds.
  *
  * The Bourne shell can be used instead of init if we are
  * trying to recover a really broken machine.
  */
 if (execute_command) { //判断在启动时是否指定了init参数
                                      //如果指定则执行用户init进程,成功将不会返回
  run_init_process(execute_command);
  printk(KERN_WARNING "Failed to execute %s.  Attempting "
     "defaults...\n", execute_command);
 }

               /*   如果没有指定init启动参数,则查找下面的目录init进程,成功将不会返回,否则打印出错信息   */
 run_init_process("/sbin/init");
 run_init_process("/etc/init");
 run_init_process("/bin/init");
 run_init_process("/bin/sh");

 panic("No init found.  Try passing init= option to kernel.");

}

继而调用函数do_basic_setup()(此时与体系结构相关的部分已经初始化完了,现在开始初始化设备了):

/*
 * Ok, the machine is now initialized. None of the devices
 * have been touched yet, but the CPU subsystem is up and
 * running, and memory and process management works.
 *
 * Now we can finally start doing some real work..
 */
static void __init do_basic_setup(void)-----------------
{
 /* drivers will send hotplug events */
 init_workqueues();
 usermodehelper_init();
 driver_init();     //建立设备模型子系统

#ifdef CONFIG_SYSCTL
 sysctl_init();
#endif

 /* Networking initialization needs a process context */
 sock_init();

 do_initcalls();   //系统初始化(包括设备,文件系统,内核模块等)
}
<./drivers/base/init.c>-------------------------
/**
 * driver_init - initialize driver model.
 *
 * Call the driver model init functions to initialize their
 * subsystems. Called early from init/main.c.
 */

void __init driver_init(void)
{
 /* These are the core pieces */
 devices_init();
                       <./drivers/base/core.c>-------------
                                  int __init devices_init(void)
                                  {
                   return subsystem_register(&devices_subsys);
                                  }
                        -----------------------
 buses_init();
 classes_init();
 firmware_init();

 /* These are also core pieces, but must come after the
  * core core pieces.
  */
 platform_bus_init();
 system_bus_init();
 cpu_dev_init();
 memory_dev_init();
 attribute_container_init();
}
---------------------------
extern initcall_t __initcall_start[], __initcall_end[];

static void __init do_initcalls(void)
{
 initcall_t *call;
 int count = preempt_count();

 for (call = __initcall_start; call < __initcall_end; call++) {
                ··················
                (*call)();     //调用一系列初始化函数
               ···················
}
---------------------------
      __initcall_start和__initcall_end界定了存放初始化函数指针区域的起始地址,即从__initcall_start开始到__initcall_end结束的区域中存放了指向各个初始化函数的函数指针。 由 (*call)()完成各个部分的初始化工作,且便于扩充。具体实现如下:
<./arch/arm/kernel/vmlinux.lds.S>-----------------
  __initcall_start = .;
   *(.initcall1.init)
   *(.initcall2.init)
   *(.initcall3.init)
   *(.initcall4.init)
   *(.initcall5.init)
   *(.initcall6.init)
   *(.initcall7.init)
  __initcall_end = .;

 <./include/linux/init.h>---------------------

#ifndef MODULE     /*    如果驱动模块静态编译进内核   */

  ···············································

/* initcalls are now grouped by functionality into separate
 * subsections. Ordering inside the subsections is determined
 * by link order.
 * For backwards compatibility, initcall() puts the call in
 * the device init subsection.
 */

#define __define_initcall(level,fn) \
 static initcall_t __initcall_##fn __attribute_used__ \
 __attribute__((__section__(".initcall" level ".init"))) = fn

#define core_initcall(fn)  __define_initcall("1",fn)
#define postcore_initcall(fn)  __define_initcall("2",fn)
#define arch_initcall(fn)  __define_initcall("3",fn)
                                            //此处初始化了设备
                                           /*----eg:arch_initcall(at91sam9261_device_init)---
                                               static int __init at91sam9261_device_init(void)
                                               {
                                                 at91_add_device_udc();
                                                 at91_add_device_dm9000();
                                                 armebs3_add_input_buttons();
                                                 return platform_add_devices(at91sam9261_devices, ARRAY_SIZE(at91sam9261_devices));
                                                }
                                        ------------------------*/

#define subsys_initcall(fn)  __define_initcall("4",fn)
#define fs_initcall(fn)  __define_initcall("5",fn)
#define device_initcall(fn)  __define_initcall("6",fn)
                                           //此处初始化了静态编译的驱动模块
#define late_initcall(fn)  __define_initcall("7",fn)

#define __initcall(fn) device_initcall(fn)


  /**
 * module_init() - driver initialization entry point
 * @x: function to be run at kernel boot time or module insertion
 *
 * module_init() will either be called during do_initcalls (if
 * builtin) or at module insertion time (if a module).  There can only
 * be one per module.
 */
#define module_init(x) __initcall(x);
                                       //静态编译的驱动模块作为device_initcall在内核启动就被do_initcalls

/**
 * module_exit() - driver exit entry point
 * @x: function to be run when driver is removed
 *
 * module_exit() will wrap the driver clean-up code
 * with cleanup_module() when used with rmmod when
 * the driver is a module.  If the driver is statically
 * compiled into the kernel, module_exit() has no effect.
 * There can only be one per module.
 */
#define module_exit(x) __exitcall(x);

#else /* MODULE    如果驱动模块动态加载入内核   */

  ···············································

/* Each module must use one module_init(), or one no_module_init */
#define module_init(initfn)     \
 static inline initcall_t __inittest(void)  \
 { return initfn; }     \
 int init_module(void) __attribute__((alias(#initfn)));
     //insmod 是通过系统调用sys_init_module(const char *name_user, struct module *mod_user)
     //将动态驱动模块载入到内核空间

/* This is only required if you want to be unloadable. */
#define module_exit(exitfn)     \
 static inline exitcall_t __exittest(void)  \
 { return exitfn; }     \
 void cleanup_module(void) __attribute__((alias(#exitfn)));

-----------------------------

posted @ 2008-04-21 21:21 vsolo 阅读(4955) | 评论 (0)编辑 收藏