gmodule.c (8082B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Generic Linux Module Framework 8 * 9 * Hooks up your driver to the kernel 10 */ 11 12 #include <lkm.h> 13 #include <gmodule.h> 14 #include <linux/init.h> 15 #include <linux/seq_file.h> 16 17 /* Module Vector Table */ 18 static gmodule_t* _gmodule = NULL; 19 20 21 /* Allow DEVFS Support on 2.4 Kernels */ 22 #if defined(LKM_2_4) && defined(CONFIG_DEVFS_FS) 23 #define GMODULE_CONFIG_DEVFS_FS 24 #endif 25 26 27 #ifdef GMODULE_CONFIG_DEVFS_FS 28 devfs_handle_t devfs_handle = NULL; 29 #endif 30 31 32 33 static int _dbg_enable = 0; 34 35 static int 36 gvprintk(const char* fmt, va_list args) 37 __attribute__ ((format (printf, 1, 0))); 38 39 static int 40 gvprintk(const char* fmt, va_list args) 41 { 42 static char _buf[256]; 43 44 strcpy(_buf, ""); 45 sprintf(_buf, "%s (%d): ", _gmodule->name, current->pid); 46 vsprintf(_buf+strlen(_buf), fmt, args); 47 printk("%s",_buf); 48 49 return 0; 50 } 51 52 int 53 gprintk(const char* fmt, ...) 54 { 55 int rv; 56 57 va_list args; 58 va_start(args, fmt); 59 rv = gvprintk(fmt, args); 60 va_end(args); 61 return rv; 62 } 63 64 int 65 gdbg(const char* fmt, ...) 66 { 67 int rv = 0; 68 69 va_list args; 70 va_start(args, fmt); 71 if(_dbg_enable) { 72 rv = gvprintk(fmt, args); 73 } 74 va_end(args); 75 return rv; 76 } 77 78 79 /* 80 * Proc FS Utilities 81 */ 82 #if PROC_INTERFACE_KERN_VER_3_10 83 static struct seq_file* _proc_buf = NULL; 84 85 int 86 pprintf(const char* fmt, ...) 87 { 88 va_list args; 89 va_start(args, fmt); 90 seq_vprintf(_proc_buf, fmt, args); 91 va_end(args); 92 return 0; 93 } 94 95 static int _gmodule_proc_show(struct seq_file *m, void *v){ 96 _proc_buf = m; 97 _gmodule->pprint(); 98 return 0; 99 } 100 101 static int 102 _gmodule_proc_open(struct inode * inode, struct file * file) { 103 if(_gmodule->open) { 104 _gmodule->open(); 105 } 106 107 return single_open(file, _gmodule_proc_show, NULL); 108 } 109 110 static ssize_t 111 _gmodule_proc_write(struct file *file, const char *buffer, 112 size_t count, loff_t *loff) 113 { 114 /* Workaround to toggle debugging */ 115 if(count > 2) { 116 if(buffer[0] == 'd') { 117 _dbg_enable = buffer[1] - '0'; 118 GDBG("Debugging Enabled"); 119 } 120 } 121 return count; 122 } 123 124 static int _gmodule_proc_release(struct inode * inode, struct file * file) { 125 if(_gmodule->close) { 126 _gmodule->close(); 127 } 128 129 return single_release(inode, file); 130 } 131 132 struct file_operations _gmodule_proc_fops = { 133 owner: THIS_MODULE, 134 open: _gmodule_proc_open, 135 read: seq_read, 136 llseek: seq_lseek, 137 write: _gmodule_proc_write, 138 release: _gmodule_proc_release, 139 }; 140 #else 141 int 142 gmodule_vpprintf(char** page_ptr, const char* fmt, va_list args) 143 { 144 *page_ptr += vsprintf(*page_ptr, fmt, args); 145 return 0; 146 } 147 148 int 149 gmodule_pprintf(char** page_ptr, const char* fmt, ...) 150 { 151 int rv; 152 153 va_list args; 154 va_start(args, fmt); 155 rv = gmodule_vpprintf(page_ptr, fmt, args); 156 va_end(args); 157 return rv; 158 } 159 160 static char* _proc_buf = NULL; 161 162 int 163 pprintf(const char* fmt, ...) 164 { 165 int rv; 166 167 va_list args; 168 va_start(args, fmt); 169 rv = gmodule_vpprintf(&_proc_buf, fmt, args); 170 va_end(args); 171 return rv; 172 } 173 174 #define PSTART(b) _proc_buf = b 175 #define PPRINT proc_print 176 #define PEND(b) (_proc_buf-b) 177 178 static int 179 _gmodule_pprint(char* buf) 180 { 181 PSTART(buf); 182 _gmodule->pprint(); 183 return PEND(buf); 184 } 185 186 static int 187 _gmodule_read_proc(char *page, char **start, off_t off, 188 int count, int *eof, void *data) 189 { 190 *eof = 1; 191 return _gmodule_pprint(page); 192 } 193 194 static int 195 _gmodule_write_proc(struct file *file, const char *buffer, 196 unsigned long count, void *data) 197 { 198 /* Workaround to toggle debugging */ 199 if(count > 2) { 200 if(buffer[0] == 'd') { 201 _dbg_enable = buffer[1] - '0'; 202 GDBG("Debugging Enabled"); 203 } 204 } 205 return count; 206 } 207 #endif 208 209 static int 210 _gmodule_create_proc(void) 211 { 212 struct proc_dir_entry* ent; 213 #if PROC_INTERFACE_KERN_VER_3_10 214 if((ent = proc_create(_gmodule->name, 215 S_IRUGO | S_IWUGO, 216 NULL, 217 &_gmodule_proc_fops)) != NULL) { 218 return 0; 219 } 220 #else 221 if((ent = create_proc_entry(_gmodule->name, S_IRUGO | S_IWUGO, NULL)) != NULL) { 222 ent->read_proc = _gmodule_read_proc; 223 ent->write_proc = _gmodule_write_proc; 224 return 0; 225 } 226 #endif 227 return -1; 228 } 229 230 static void 231 _gmodule_remove_proc(void) 232 { 233 remove_proc_entry(_gmodule->name, NULL); 234 } 235 236 static int 237 _gmodule_open(struct inode *inode, struct file *filp) 238 { 239 if(_gmodule->open) { 240 _gmodule->open(); 241 } 242 return 0; 243 } 244 245 static int 246 _gmodule_release(struct inode *inode, struct file *filp) 247 { 248 if(_gmodule->close) { 249 _gmodule->close(); 250 } 251 return 0; 252 } 253 254 #ifdef HAVE_UNLOCKED_IOCTL 255 static long 256 _gmodule_unlocked_ioctl(struct file *filp, 257 unsigned int cmd, unsigned long arg) 258 { 259 if(_gmodule->ioctl) { 260 return _gmodule->ioctl(cmd, arg); 261 } else { 262 return -1; 263 } 264 } 265 #else 266 static int 267 _gmodule_ioctl(struct inode *inode, struct file *filp, 268 unsigned int cmd, unsigned long arg) 269 { 270 if(_gmodule->ioctl) { 271 return _gmodule->ioctl(cmd, arg); 272 } else { 273 return -1; 274 } 275 } 276 #endif 277 278 #ifdef HAVE_COMPAT_IOCTL 279 static long 280 _gmodule_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 281 { 282 if(_gmodule->ioctl) { 283 return _gmodule->ioctl(cmd, arg); 284 } else { 285 return -1; 286 } 287 } 288 #endif 289 290 291 static int 292 _gmodule_mmap(struct file *filp, struct vm_area_struct *vma) 293 { 294 if (_gmodule->mmap) { 295 return _gmodule->mmap(filp, vma); 296 } 297 #ifdef BCM_PLX9656_LOCAL_BUS 298 vma->vm_flags |= VM_RESERVED | VM_IO; 299 pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED; 300 301 if (io_remap_pfn_range( vma, 302 vma->vm_start, 303 vma->vm_pgoff, 304 vma->vm_end - vma->vm_start, 305 vma->vm_page_prot)) { 306 return (-EAGAIN); 307 } 308 return (0); 309 #else/* BCM_PLX9656_LOCAL_BUS */ 310 return -EPERM; 311 #endif/* BCM_PLX9656_LOCAL_BUS */ 312 } 313 314 /* FILE OPERATIONS */ 315 316 struct file_operations _gmodule_fops = { 317 #ifdef HAVE_UNLOCKED_IOCTL 318 unlocked_ioctl: _gmodule_unlocked_ioctl, 319 #else 320 ioctl: _gmodule_ioctl, 321 #endif 322 open: _gmodule_open, 323 release: _gmodule_release, 324 mmap: _gmodule_mmap, 325 #ifdef HAVE_COMPAT_IOCTL 326 compat_ioctl: _gmodule_compat_ioctl, 327 #endif 328 }; 329 330 331 void __exit 332 cleanup_module(void) 333 { 334 if(!_gmodule) return; 335 336 /* Specific Cleanup */ 337 if(_gmodule->cleanup) { 338 _gmodule->cleanup(); 339 } 340 341 /* Remove any proc entries */ 342 if(_gmodule->pprint) { 343 _gmodule_remove_proc(); 344 } 345 346 /* Finally, remove ourselves from the universe */ 347 #ifdef GMODULE_CONFIG_DEVFS_FS 348 if(devfs_handle) devfs_unregister(devfs_handle); 349 #else 350 unregister_chrdev(_gmodule->major, _gmodule->name); 351 #endif 352 } 353 354 int __init 355 init_module(void) 356 { 357 int rc; 358 359 /* Get our definition */ 360 _gmodule = gmodule_get(); 361 if(!_gmodule) return -ENODEV; 362 363 364 /* Register ourselves */ 365 #ifdef GMODULE_CONFIG_DEVFS_FS 366 devfs_handle = devfs_register(NULL, 367 _gmodule->name, 368 DEVFS_FL_NONE, 369 _gmodule->major, 370 _gmodule->minor, 371 S_IFCHR | S_IRUGO | S_IWUGO, 372 &_gmodule_fops, 373 NULL); 374 if(!devfs_handle) { 375 printk(KERN_WARNING "%s: can't register device with devfs", 376 _gmodule->name); 377 } 378 rc = 0; 379 #else 380 rc = register_chrdev(_gmodule->major, 381 _gmodule->name, 382 &_gmodule_fops); 383 if (rc < 0) { 384 printk(KERN_WARNING "%s: can't get major %d", 385 _gmodule->name, _gmodule->major); 386 return rc; 387 } 388 389 if(_gmodule->major == 0) { 390 _gmodule->major = rc; 391 } 392 #endif 393 394 /* Specific module Initialization */ 395 if(_gmodule->init) { 396 int rc; 397 if((rc = _gmodule->init()) < 0) { 398 #ifdef GMODULE_CONFIG_DEVFS_FS 399 if(devfs_handle) devfs_unregister(devfs_handle); 400 #else 401 unregister_chrdev(_gmodule->major, _gmodule->name); 402 #endif 403 return rc; 404 } 405 } 406 407 /* Add a /proc entry, if valid */ 408 if(_gmodule->pprint) { 409 _gmodule_create_proc(); 410 } 411 412 return 0; /* succeed */ 413 }