openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 }