Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | /* * * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. * * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> * * Version: 1.64 2002/06/10 * */ #include "matroxfb_base.h" #include <linux/proc_fs.h> static struct proc_dir_entry* mga_pde; struct procinfo { struct matrox_fb_info* info; struct proc_dir_entry* pde; }; static inline void remove_pde(struct proc_dir_entry* pde) { if (pde) { remove_proc_entry(pde->name, pde->parent); } } #ifndef CONFIG_PROC_FS static int bios_read_proc(char* buffer, char** start, off_t offset, int size, int *eof, void *data) { return 0; } static int pins_read_proc(char* buffer, char** start, off_t offset, int size, int *eof, void *data) { return 0; } #else /* This macro frees the machine specific function from bounds checking and * this like that... */ #define PRINT_PROC(fmt,args...) \ do { \ len += sprintf(buffer+len, fmt, ##args ); \ if (begin + len > offset + size) \ break; \ if (begin + len < offset) { \ begin += len; \ len = 0; \ } \ } while(0) static int bios_read_proc(char* buffer, char** start, off_t offset, int size, int *eof, void *data) { int len = 0; off_t begin = 0; struct matrox_bios* bd = data; do { *eof = 0; if (bd->bios_valid) { PRINT_PROC("BIOS: %u.%u.%u\n", bd->version.vMaj, bd->version.vMin, bd->version.vRev); PRINT_PROC("Output: 0x%02X\n", bd->output.state); PRINT_PROC("TVOut: %s\n", bd->output.tvout?"yes":"no"); PRINT_PROC("PINS: %s\n", bd->pins_len ? "found" : "not found"); PRINT_PROC("Info: %p\n", bd); } else { PRINT_PROC("BIOS: Invalid\n"); } *eof = 1; } while (0); if (offset >= begin + len) return 0; *start = buffer + (offset - begin); return size < begin + len - offset ? size : begin + len - offset; } static int pins_read_proc(char* buffer, char** start, off_t offset, int size, int *eof, void *data) { struct matrox_bios* bd = data; if (offset >= bd->pins_len) { *eof = 1; return 0; } if (offset + size >= bd->pins_len) { size = bd->pins_len - offset; *eof = 1; } memcpy(buffer, bd->pins + offset, size); *start = buffer; return size; } #endif /* CONFIG_PROC_FS */ static void* matroxfb_proc_probe(struct matrox_fb_info* minfo) { struct procinfo* binfo; char b[10]; binfo = (struct procinfo*)kmalloc(sizeof(*binfo), GFP_KERNEL); if (!binfo) { printk(KERN_ERR "matroxfb_proc: Not enough memory for /proc control structs\n"); return NULL; } binfo->info = minfo; sprintf(b, "fb%u", GET_FB_IDX(minfo->fbcon.node)); binfo->pde = proc_mkdir(b, mga_pde); if (binfo->pde) { create_proc_read_entry("bios", 0, binfo->pde, bios_read_proc, &minfo->bios); if (minfo->bios.pins_len) { struct proc_dir_entry* p = create_proc_read_entry("pins", 0, binfo->pde, pins_read_proc, &minfo->bios); if (p) { p->size = minfo->bios.pins_len; } } } return binfo; } static void matroxfb_proc_remove(struct matrox_fb_info* minfo, void* binfoI) { struct procinfo* binfo = binfoI; if (binfo->pde) { remove_proc_entry("pins", binfo->pde); remove_proc_entry("bios", binfo->pde); remove_pde(binfo->pde); } kfree(binfo); } static struct matroxfb_driver procfn = { .name = "Matrox /proc driver", .probe = matroxfb_proc_probe, .remove = matroxfb_proc_remove }; static int matroxfb_proc_init(void) { mga_pde = proc_mkdir("driver/mga", NULL); matroxfb_register_driver(&procfn); return 0; } static void matroxfb_proc_exit(void) { matroxfb_unregister_driver(&procfn); remove_pde(mga_pde); } MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); MODULE_DESCRIPTION("Matrox /proc driver"); MODULE_LICENSE("GPL"); module_init(matroxfb_proc_init); module_exit(matroxfb_proc_exit); /* we do not have __setup() */ |