?? fbmem.c
字號:
struct fb_fix_screeninfo fix; struct fb_con2fbmap con2fb; int i; if (! fb) return -ENODEV;
switch (cmd) { case FBIOGET_VSCREENINFO: if ((i = fb->fb_get_var(&var, PROC_CONSOLE(info), info))) return i; return copy_to_user((void *) arg, &var, sizeof(var)) ? -EFAULT : 0; case FBIOPUT_VSCREENINFO: if (copy_from_user(&var, (void *) arg, sizeof(var))) return -EFAULT; i = var.activate & FB_ACTIVATE_ALL ? set_all_vcs(fbidx, fb, &var, info) : fb->fb_set_var(&var, PROC_CONSOLE(info), info); if (i) return i; if (copy_to_user((void *) arg, &var, sizeof(var))) return -EFAULT; return 0; case FBIOGET_FSCREENINFO: if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(info), info))) return i; return copy_to_user((void *) arg, &fix, sizeof(fix)) ? -EFAULT : 0; case FBIOPUTCMAP: if (copy_from_user(&cmap, (void *) arg, sizeof(cmap))) return -EFAULT; return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE(info), info)); case FBIOGETCMAP: if (copy_from_user(&cmap, (void *) arg, sizeof(cmap))) return -EFAULT; return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE(info), info)); case FBIOPAN_DISPLAY: if (copy_from_user(&var, (void *) arg, sizeof(var))) return -EFAULT; if (fb->fb_pan_display == NULL) return (var.xoffset || var.yoffset) ? -EINVAL : 0; if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(info), info))) return i; if (copy_to_user((void *) arg, &var, sizeof(var))) return -EFAULT; return i; case FBIOGET_CON2FBMAP: if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb))) return -EFAULT; if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; con2fb.framebuffer = con2fb_map[con2fb.console-1]; return copy_to_user((void *)arg, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; case FBIOPUT_CON2FBMAP: if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb))) return - EFAULT; if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) return -EINVAL;#ifdef CONFIG_KMOD if (!registered_fb[con2fb.framebuffer]) try_to_load(con2fb.framebuffer);#endif /* CONFIG_KMOD */ if (!registered_fb[con2fb.framebuffer]) return -EINVAL; if (con2fb.console != 0) set_con2fb_map(con2fb.console-1, con2fb.framebuffer); else /* set them all */ for (i = 0; i < MAX_NR_CONSOLES; i++) set_con2fb_map(i, con2fb.framebuffer); return 0; case FBIOBLANK: if (info->blank == 0) return -EINVAL; (*info->blank)(arg, info); return 0; default: if (fb->fb_ioctl == NULL) return -EINVAL; return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(info), info); }}static int fb_mmap(struct file *file, struct vm_area_struct * vma){ int fbidx = GET_FB_IDX(file->f_dentry->d_inode->i_rdev); struct fb_info *info = registered_fb[fbidx]; struct fb_ops *fb = info->fbops; unsigned long off;#if !defined(__sparc__) || defined(__sparc_v9__) struct fb_fix_screeninfo fix; struct fb_var_screeninfo var; unsigned long start; u32 len;#endif if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; if (!fb) return -ENODEV; if (fb->fb_mmap) { int res; lock_kernel(); res = fb->fb_mmap(info, file, vma); unlock_kernel(); /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO; return res; }#if defined(__sparc__) && !defined(__sparc_v9__) /* Should never get here, all fb drivers should have their own mmap routines */ return -EINVAL;#else /* !sparc32... */ lock_kernel(); fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); /* frame buffer memory */ start = fix.smem_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len); if (off >= len) { /* memory mapped io */ off -= len; fb->fb_get_var(&var, PROC_CONSOLE(info), info); if (var.accel_flags) { unlock_kernel(); return -EINVAL; } start = fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); } unlock_kernel(); start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; off += start; vma->vm_pgoff = off >> PAGE_SHIFT; /* This is an IO map - tell maydump to skip this VMA */ vma->vm_flags |= VM_IO;#if defined(__sparc_v9__) vma->vm_flags |= (VM_SHM | VM_LOCKED); if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot, 0)) return -EAGAIN;#else#if defined(__mc68000__)#if defined(CONFIG_SUN3) pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;#else if (CPU_IS_020_OR_030) pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; if (CPU_IS_040_OR_060) { pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; /* Use no-cache mode, serialized */ pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; }#endif#elif defined(__powerpc__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;#elif defined(__alpha__) /* Caching is off in the I/O space quadrant by design. */#elif defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;#elif defined(__arm__) || defined(__mips__) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);#elif defined(__sh__) pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;#elif defined(__hppa__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #elif defined(__ia64__) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);#elif defined(__hppa__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #else#warning What do we have to do here??#endif if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN;#endif /* !__sparc_v9__ */ return 0;#endif /* !sparc32 */}#if 1 /* to go away in 2.5.0 */int GET_FB_IDX(kdev_t rdev){ int fbidx = MINOR(rdev); if (fbidx >= 32) { int newfbidx = fbidx >> 5; static int warned; if (!(warned & (1<<newfbidx))) { warned |= 1<<newfbidx; printk("Warning: Remapping obsolete /dev/fb* minor %d to %d\n", fbidx, newfbidx); } fbidx = newfbidx; } return fbidx;}#endifstatic intfb_open(struct inode *inode, struct file *file){ int fbidx = GET_FB_IDX(inode->i_rdev); struct fb_info *info; int res = 0;#ifdef CONFIG_KMOD if (!(info = registered_fb[fbidx])) try_to_load(fbidx);#endif /* CONFIG_KMOD */ if (!(info = registered_fb[fbidx])) return -ENODEV; if (info->fbops->owner) __MOD_INC_USE_COUNT(info->fbops->owner); if (info->fbops->fb_open) { res = info->fbops->fb_open(info,1); if (res && info->fbops->owner) __MOD_DEC_USE_COUNT(info->fbops->owner); } return res;}static int fb_release(struct inode *inode, struct file *file){ int fbidx = GET_FB_IDX(inode->i_rdev); struct fb_info *info; lock_kernel(); info = registered_fb[fbidx]; if (info->fbops->fb_release) info->fbops->fb_release(info,1); if (info->fbops->owner) __MOD_DEC_USE_COUNT(info->fbops->owner); unlock_kernel(); return 0;}static struct file_operations fb_fops = { owner: THIS_MODULE, read: fb_read, write: fb_write, ioctl: fb_ioctl, mmap: fb_mmap, open: fb_open, release: fb_release,#ifdef HAVE_ARCH_FB_UNMAPPED_AREA get_unmapped_area: get_fb_unmapped_area,#endif};static devfs_handle_t devfs_handle;/** * register_framebuffer - registers a frame buffer device * @fb_info: frame buffer info structure * * Registers a frame buffer device @fb_info. * * Returns negative errno on error, or zero for success. * */intregister_framebuffer(struct fb_info *fb_info){ int i, j; char name_buf[8]; static int fb_ever_opened[FB_MAX]; static int first = 1; //若登記的設備已達到最大數目,返回
if (num_registered_fb == FB_MAX) return -ENXIO; num_registered_fb++;
//查找登記表中未使用的位置,作為該設備的登記位置 for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break;
//分配次設備號 fb_info->node = MKDEV(FB_MAJOR, i);
//注冊該設備 registered_fb[i] = fb_info;
//設備未打開 if (!fb_ever_opened[i]) { struct module *owner = fb_info->fbops->owner; /* * We assume initial frame buffer devices can be opened this * many times */ for (j = 0; j < MAX_NR_CONSOLES; j++) if (con2fb_map[j] == i) { if (owner) __MOD_INC_USE_COUNT(owner); if (!fb_info->fbops->fb_open) continue; if (!fb_info->fbops->fb_open(fb_info,0)) continue; if (owner) __MOD_DEC_USE_COUNT(owner); } fb_ever_opened[i] = 1;//設置設備為打開狀態 } if (first) { first = 0; take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); } sprintf (name_buf, "%d", i); fb_info->devfs_handle = devfs_register (devfs_handle, name_buf, DEVFS_FL_DEFAULT, FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO, &fb_fops, NULL); return 0;}/** * unregister_framebuffer - releases a frame buffer device * @fb_info: frame buffer info structure * * Unregisters a frame buffer device @fb_info. * * Returns negative errno on error, or zero for success. * */intunregister_framebuffer(struct fb_info *fb_info){ int i, j; i = GET_FB_IDX(fb_info->node);//獲取對應的設備號 //查詢設備是否空閑
for (j = 0; j < MAX_NR_CONSOLES; j++) if (con2fb_map[j] == i) return -EBUSY;
//若設備未登記,返回 if (!registered_fb[i]) return -EINVAL;
devfs_unregister (fb_info->devfs_handle); fb_info->devfs_handle = NULL; devfs_unregister (fb_info->devfs_lhandle); fb_info->devfs_lhandle = NULL;
//將該設備從FB登記表中清除 registered_fb[i]=NULL; num_registered_fb--; return 0;}/** * fbmem_init - init frame buffer subsystem * * Initialize the frame buffer subsystem. * * NOTE: This function is _only_ to be called by drivers/char/mem.c. * */void __init fbmem_init(void){ int i; create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL); devfs_handle = devfs_mk_dir (NULL, "fb", NULL); if (devfs_register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR);#ifdef CONFIG_FB_OF if (ofonly) { offb_init(); return; }#endif /* * Probe for all builtin frame buffer devices */ for (i = 0; i < num_pref_init_funcs; i++) pref_init_funcs[i](); for (i = 0; i < NUM_FB_DRIVERS; i++) if (fb_drivers[i].init) fb_drivers[i].init();}/** * video_setup - process command line options * @options: string of options * * Process command line options for frame buffer subsystem. * * NOTE: This function is a __setup and __init function. * * Returns zero. * */int __init video_setup(char *options){ int i, j; if (!options || !*options) return 0; if (!strncmp(options, "scrollback:", 11)) { options += 11; if (*options) { fbcon_softback_size = simple_strtoul(options, &options, 0); if (*options == 'k' || *options == 'K') { fbcon_softback_size *= 1024; options++; } if (*options != ',') return 0; options++; } else return 0; } if (!strncmp(options, "map:", 4)) { options += 4; if (*options) for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) { if (!options[j]) j = 0; con2fb_map[i] = (options[j++]-'0') % FB_MAX; } return 0; } if (!strncmp(options, "vc:", 3)) { options += 3; if (*options) first_fb_vc = simple_strtoul(options, &options, 10) - 1; if (first_fb_vc < 0) first_fb_vc = 0; if (*options++ == '-') last_fb_vc = simple_strtoul(options, &options, 10) - 1; fbcon_is_default = 0; }#ifdef CONFIG_FB_OF if (!strcmp(options, "ofonly")) { ofonly = 1; return 0; }#endif if (num_pref_init_funcs == FB_MAX) return 0; for (i = 0; i < NUM_FB_DRIVERS; i++) { j = strlen(fb_drivers[i].name); if (!strncmp(options, fb_drivers[i].name, j) && options[j] == ':') { if (!strcmp(options+j+1, "off")) fb_drivers[i].init = NULL; else { if (fb_drivers[i].init) { pref_init_funcs[num_pref_init_funcs++] = fb_drivers[i].init; fb_drivers[i].init = NULL; } if (fb_drivers[i].setup) fb_drivers[i].setup(options+j+1); } return 0; } } /* * If we get here no fb was specified. * We consider the argument to be a global video mode option. */ global_mode_option = options; return 0;}__setup("video=", video_setup); /* * Visible symbols for modules */EXPORT_SYMBOL(register_framebuffer);EXPORT_SYMBOL(unregister_framebuffer);EXPORT_SYMBOL(registered_fb);EXPORT_SYMBOL(num_registered_fb);#if 1 /* to go away in 2.5.0 */EXPORT_SYMBOL(GET_FB_IDX);#endifMODULE_LICENSE("GPL");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -