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 (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 }