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