前面的probe函数已经分析完了,但是我们还是不明白帧缓冲设备到底是一个什么样的设备,这一节我们将得到答案。
1657 /**
1658 * fbmem_init - init frame buffer subsystem
1659 *
1660 * Initialize the frame buffer subsystem.
1661 *
1662 * NOTE: This function is _only_ to be called by drivers/char/mem.c.
1663 *
1664 */
1665
1666 static int __init
1667 fbmem_init(void)
1668 {
1669 proc_create("fb", 0, NULL, &fb_proc_fops);
1670
1671 if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
1672 printk("unable to get major %d for fb devs\n", FB_MAJOR);
1673
1674 fb_class = class_create(THIS_MODULE, "graphics");
1675 if (IS_ERR(fb_class)) {
1676 printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
1677 fb_class = NULL;
1678 }
1679 return 0;
1680 }
fbmem_init中注册了一个字符设备,并且创建了一个class。
1685 fbmem_exit(void)
1686 {
1687 remove_proc_entry("fb", NULL);
1688 class_destroy(fb_class);
1689 unregister_chrdev(FB_MAJOR, "fb");
1690 }
那么在它的注销函数中当然是做了相反的工作,释放这个class和注销这个字符设备。
既然这里注册了一个字符设备,那我们就去看看这个字符设备相关定义。
1. major
FB_MAJOR定义在inclue/linux/major.h中。
56 #define FB_MAJOR 29 /* /dev/fb* framebuffers */
说明这个字符设备的主设备号为29。
2. file_operations
1424 static const struct file_operations fb_fops = {
1425 .owner = THIS_MODULE,
1426 .read = fb_read,
1427 .write = fb_write,
1428 .unlocked_ioctl = fb_ioctl,
1429 #ifdef CONFIG_COMPAT
1430 .compat_ioctl = fb_compat_ioctl,
1431 #endif
1432 .mmap = fb_mmap,
1433 .open = fb_open,
1434 .release = fb_release,
1435 #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
1436 .get_unmapped_area = get_fb_unmapped_area,
1437 #endif
1438 #ifdef CONFIG_FB_DEFERRED_IO
1439 .fsync = fb_deferred_io_fsync,
1440 #endif
1441 };
再看看我们调用register_framebuffer注册一个帧缓冲设备时发生了什么事情。
1481 /**
1482 * register_framebuffer - registers a frame buffer device
1483 * @fb_info: frame buffer info structure
1484 *
1485 * Registers a frame buffer device @fb_info.
1486 *
1487 * Returns negative errno on error, or zero for success.
1488 *
1489 */
1490
1491 int
1492 register_framebuffer(struct fb_info *fb_info)
1493 {
1494 int i;
1495 struct fb_event event;
1496 struct fb_videomode mode;
1497
1498 if (num_registered_fb == FB_MAX)
1499 return -ENXIO;
1500
1501 if (fb_check_foreignness(fb_info))
1502 return -ENOSYS;
1503
1504 /* check all firmware fbs and kick off if the base addr overlaps */
1505 for (i = 0 ; i < FB_MAX; i++) {
1506 if (!registered_fb[i])
1507 continue;
1508
1509 if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
1510 if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
1511 printk(KERN_ERR "fb: conflicting fb hw usage "
1512 "%s vs %s - removing generic driver\n",
1513 fb_info->fix.id,
1514 registered_fb[i]->fix.id);
1515 unregister_framebuffer(registered_fb[i]);
1516 break;
1517 }
1518 }
1519 }
1520
1521 num_registered_fb++;
1522 for (i = 0 ; i < FB_MAX; i++)
1523 if (!registered_fb[i])
1524 break;
1525 fb_info->node = i;
1526 mutex_init(&fb_info->lock);
1527 mutex_init(&fb_info->mm_lock);
1528
1529 fb_info->dev = device_create(fb_class, fb_info->device,
1530 MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
1531 if (IS_ERR(fb_info->dev)) {
1532 /* Not fatal */
1533 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR _ERR(fb_info->dev));
1534 fb_info->dev = NULL;
1535 } else
1536 fb_init_device(fb_info);
1537
1538 if (fb_info->pixmap.addr == NULL) {
1539 fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
1540 if (fb_info->pixmap.addr) {
1541 fb_info->pixmap.size = FBPIXMAPSIZE;
1542 fb_info->pixmap.buf_align = 1;
1543 fb_info->pixmap.scan_align = 1;
1544 fb_info->pixmap.access_align = 32;
1545 fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
1546 }
1547 }
1548 fb_info->pixmap.offset = 0;
1549
1550 if (!fb_info->pixmap.blit_x)
1551 fb_info->pixmap.blit_x = ~(u32)0;
1552
1553 if (!fb_info->pixmap.blit_y)
1554 fb_info->pixmap.blit_y = ~(u32)0;
1555
1556 if (!fb_info->modelist.prev || !fb_info->modelist.next)
1557 INIT_LIST_HEAD(&fb_info->modelist);
1558
1559 fb_var_to_videomode(&mode, &fb_info->var);
1560 fb_add_videomode(&mode, &fb_info->modelist);
1561 registered_fb[i] = fb_info;
1562
1563 event.info = fb_info;
1564 if (!lock_fb_info(fb_info))
1565 return -ENODEV;
1566 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1567 unlock_fb_info(fb_info);
1568 return 0;
1569 }
直接到for循环。
1504 /* check all firmware fbs and kick off if the base addr overlaps */
1505 for (i = 0 ; i < FB_MAX; i++) {
1506 if (!registered_fb[i])
1507 continue;
1508
1509 if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
1510 if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
1511 printk(KERN_ERR "fb: conflicting fb hw usage "
1512 "%s vs %s - removing generic driver\n",
1513 fb_info->fix.id,
1514 registered_fb[i]->fix.id);
1515 unregister_framebuffer(registered_fb[i]);
1516 break;
1517 }
1518 }
1519 }
registered_fb它是一个数组,它的类型就是struct fb_info,它用于保存我们调用register_framebuffer传进来的struct fb_info。
num_registered_fb代表注册帧缓冲设备的个数。
1522 for (i = 0 ; i < FB_MAX; i++)
1523 if (!registered_fb[i])
1524 break;
1525 fb_info->node = i;
找到一个空的次设备号。
1529 fb_info->dev = device_create(fb_class, fb_info->device,
1530 MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
在dev下创建设备节点。
然后对struct fb_info做了一些初始化。
最后将我们这个struct fb_info添加到registered_fb数组里面。
从这里我们可以理解到,其实帧缓冲设备它就是一个字符设备,它也有相关的file_operations操作。从这里我们也能大致明白帧缓冲设备的应用程序该如何编写,肯定也是先调用open打开这个字符设备,最后调用close关闭这个字符设备,至于是如何往显存里写数据将在以后介绍。像linux下GUI程序都是这样实现的,只不过它向上封装了API,供更上一级的应用程序开发者调用。