1421}
1422
1423 module_init(pxafb_init);
注意函数体的最后一行,它调用的是platform_driver_register这个函数。这个函数定义于driver/base/platform.c中,定义如下:
// drivers/base/platform.c
439
443int platform_driver_register(struct platform_driver *drv)
444{
445 drv->driver.bus = &platform_bus_type;
446 if (drv->probe)
447 drv->driver.probe = platform_drv_probe;
448 if (drv->remove)
449 drv->driver.remove = platform_drv_remove;
450 if (drv->shutdown)
451 drv->driver.shutdown = platform_drv_shutdown;
452 if (drv->suspend)
453 drv->driver.suspend = platform_drv_suspend;
454 if (drv->resume)
455 drv->driver.resume = platform_drv_resume;
456 if (drv->pm)
457 drv->driver.pm = &drv->pm->base;
458 return driver_register(&drv->driver);
459}
460EXPORT_SYMBOL_GPL(platform_driver_register);
由上可知,它的功能先是为上面提到的plarform_driver中的driver这个结构中的probe、remove这些变量指定功能函数,最后调用driver_register()进行设备驱动的注册。在注册驱动的时候,这个函数会以上面提到的name成员的值为搜索内容,搜索系统中注册的device中有没有与这个name值相一致的device,如果有的话,那么接着就会执行platform_driver 里probe函数。
到目前为止,内核就已经知道了有这么一个驱动模块。内核启动的时候,就会调用与该驱动相关的probe函数。我们来看一下probe函数实现了什么功能。
probe函数的原型为
int xxx_probe(struct platform_device *pdev)
即它的返回类型为int,接收一个platform_device类型的指针作为参数。返回类型就是我们熟悉的错误代码了,而接收的这个参数呢,我们上面已经说过,驱动程序为设备服务,就需要知道设备的信息。而这个参数,就包含了与设备相关的信息。
probe函数接收到plarform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供的 platform_get_resource和platform_get_irq等函数来获得相关信息。如通过 platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。
在完成了上面这些工作和一些其他必须的初始化操作后,就可以向系统注册我们在/dev目录下能看在的设备文件了。举一个例子,在音频芯片的驱动中,就可以调用register_sound_dsp来注册一个dsp设备文件,lcd的驱动中就可以调用register_framebuffer来注册fb设备文件。这个工作完成以后,系统中就有我们需要的设备文件了。而和设备文件相关的操作都是通过一个file_operations 来实现的。在调用register_sound_dsp等函数的时候,就需要传递一个file_operations 类型的指针。这个指针就提供了可以供用户空间调用的write、read等函数。file_operations结构的定义位于 include/linux/fs.h中,列出如下:
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};
到目前为止,probe函数的功能就完成了。
当用户打开一个设备,并调用其read、write等函数的时候,就可以通过上面的file_operations来找到相关的函数。所以,用户驱动程序还需要实现这些函数,具体实现和相关的设备有密切的关系,这里就不再介绍了。
关于我们所使用的LCD设备的xxx_probe()函数的分析可查看** <<pxafb驱动程序分析>>
下面看我们所使用的LCD设备的 probe() 函数:
// drivers/video/pxafb.c:
1271int __init pxafb_probe(struct platform_device *dev)
1272{
1273 struct pxafb_info *fbi;
1274 struct pxafb_mach_info *inf;
1275 int ret;
1276
1277 dev_dbg(dev, "pxafb_probe\n");
1278
1279 inf = dev->dev.platform_data;
1280 ret = -ENOMEM;
1281 fbi = NULL;
1282 if (!inf)
1283 goto failed;
1284
1285#ifdef CONFIG_FB_PXA_PARAMETERS
1286 ret = pxafb_parse_options(&dev->dev, g_options);
1287 if (ret < 0)
1288 goto failed;
1289#endif
1290
1291#ifdef DEBUG_VAR
1292
1294
1295 if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
1296 dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: x\n",
1297 inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
1298 if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
1299 dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: x\n",
1300 inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
1301 if (inf->lccr0 & LCCR0_DPD &&
1302 ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
1303 (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
1304 (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
1305 dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
1306 " single panel mode\n");
1307 if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
1308 (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
1309 dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
1310 if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
1311 (inf->upper_margin || inf->lower_margin))
1312 dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
1313#endif
1314
1315 dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
1316 if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
1317 dev_err(&dev->dev, "Invalid resolution or bit depth\n");
1318 ret = -EINVAL;
1319 goto failed;
1320 }
1321 pxafb_backlight_power = inf->pxafb_backlight_power;
1322 pxafb_lcd_power = inf->pxafb_lcd_power;
1323 fbi = pxafb_init_fbinfo(&dev->dev);
1324 if (!fbi) {
1325 dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
1326 ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
1327 goto failed;
1328 }
1329
1330
1331 ret = pxafb_map_video_memory(fbi);
1332 if (ret) {
1333 dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
1334 ret = -ENOMEM;
1335 goto failed;
1336 }
1337
1338 ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
1339 if (ret) {
1340 dev_err(&dev->dev, "request_irq failed: %d\n", ret);
1341 ret = -EBUSY;
1342 goto failed;
1343 }
1344
1345
1349 pxafb_check_var(&fbi->fb.var, &fbi->fb);
1350 pxafb_set_par(&fbi->fb);
1351
1352 platform_set_drvdata(dev, fbi);
1353
1354 ret = register_framebuffer(&fbi->fb);
1355 if (ret < 0) {
1356 dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret);
1357 goto failed;
1358 }
1359
1360#ifdef CONFIG_PM
1361 // TODO
1362#endif
1363
1364#ifdef CONFIG_CPU_FREQ
1365 fbi->freq_transition.notifier_call = pxafb_freq_transition;
1366 fbi->freq_policy.notifier_call = pxafb_freq_policy;
1367 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
1368 cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
1369#endif
1370
1371
1374 set_ctrlr_state(fbi, C_ENABLE);
1375
1376 return 0;
1377
1378failed:
1379 platform_set_drvdata(dev, NULL);
1380 kfree(fbi);
1381 return ret;
1382} |