#include <linux/kernel.h>
|
#include <linux/version.h>
|
#include <linux/module.h>
|
#include <linux/init.h>
|
#include <linux/fs.h>
|
#include <linux/cdev.h>
|
#include <linux/slab.h>
|
#include <linux/mutex.h>
|
#include <asm/uaccess.h>
|
#include <linux/uaccess.h>
|
|
#include "ip1811.h"
|
#include "ip1811fdat.h"
|
|
static struct cdev ip1811_cdev;
|
struct class *ip1811_class;
|
static DEFINE_MUTEX(ip1811_mutex);
|
u8 CPU_IF_SPEED_NORMAL;
|
|
#define IP1811_MAJOR 248
|
#define IP1811_NAME "ip1811_cdev"
|
|
//#define IP1811DEBUG
|
|
MODULE_LICENSE ("GPL");
|
|
static int ip1811_open(struct inode *inode, struct file *fs)
|
{
|
#ifdef IP1811DEBUG
|
printk("ip1811: open...\n");
|
#endif
|
try_module_get(THIS_MODULE);
|
|
return 0;
|
}
|
|
static int ip1811_release(struct inode *inode, struct file *file)
|
{
|
module_put(THIS_MODULE);
|
#ifdef IP1811DEBUG
|
printk("ip1811: release!\n");
|
#endif
|
return 0;
|
}
|
|
static ssize_t ip1811_read(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
|
{
|
// return simple_read_from_buffer(buffer, length, offset, msg, 200);
|
return 0;
|
}
|
|
static ssize_t ip1811_write(struct file *filp, const char __user *buff, size_t len, loff_t *off)
|
{
|
/* if (len > 199)
|
return -EINVAL;
|
copy_from_user(msg, buff, len);
|
msg[len] = '\0';
|
return len;*/
|
return 0;
|
}
|
|
static int ip1811_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
{
|
int ret;
|
unsigned long len, cmdid, fno, fsubg, fgrp, fusg;
|
void *cptr;
|
char *cdata, *cmptr;
|
int offset_t;
|
|
#ifdef IP1811DEBUG
|
printk(KERN_ALERT "ip1811: +ioctl...\n");
|
#endif
|
len = (int)(_IOC_SIZE(cmd));
|
cptr = (void *)arg;
|
offset_t = sizeof(void*) + sizeof(unsigned long);
|
|
do {
|
cdata = kmalloc(len, GFP_KERNEL);
|
cmptr=cdata;
|
|
if (!cdata)
|
{
|
printk(KERN_ERR "cdata==NULL");
|
ret = -ENOMEM;
|
goto out_ip1811_ioctl;
|
}
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
if(access_ok(VERIFY_READ, cptr, len)){
|
#else
|
if(access_ok(cptr, len)){
|
#endif
|
if(copy_from_user(cdata, cptr, len)){
|
printk(KERN_ERR "copy_from_user fail. len:%ld",(unsigned long)len);
|
ret=-EFAULT;
|
goto out_ip1811_ioctl;
|
}
|
}
|
else{
|
printk(KERN_ERR "[switchDriver] copy_from_user access fail by %s:%d CMD:%x\n",__FUNCTION__,__LINE__,cmd);
|
ret = -EFAULT;
|
goto out_ip1811_ioctl;
|
}
|
if(cmptr!=cdata){
|
printk(KERN_ERR "cdata error org: %p, after: %p", cmptr, cdata);
|
}
|
cmdid = *((unsigned long *)(cdata+offset_t));
|
fno = (cmdid >> _CMDID_NRSHIFT) & _CMDID_NRMASK;
|
fsubg=(cmdid >> _CMDID_SUBGSHIFT) & _CMDID_SUBGMASK;
|
fgrp= (cmdid >> _CMDID_GRPSHIFT) & _CMDID_GRPMASK;
|
fusg= (cmdid >> _CMDID_USGSHIFT) & _CMDID_USGMASK;
|
#ifdef IP1811DEBUG
|
printk(KERN_ALERT "cmdid=0x%08x\n", (unsigned int)cmdid);
|
#endif
|
|
if (fusg == _CMDID_USG_COMMON)
|
{
|
switch (fgrp)
|
{
|
case _CMDID_GRP_BASIC:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_SMI:
|
ret = func_of_common_smi[fno](cdata, len); break;
|
|
case _CMDID_SUBG_CAP:
|
ret = func_of_common_cap[fno](cdata, len); break;
|
|
case _CMDID_SUBG_LUT:
|
ret = func_of_common_lut[fno](cdata, len); break;
|
|
case _CMDID_SUBG_SNIFFER:
|
ret = func_of_common_sniffer[fno](cdata, len); break;
|
|
case _CMDID_SUBG_STORM:
|
ret = func_of_common_storm[fno](cdata, len); break;
|
|
case _CMDID_SUBG_EOC:
|
ret = func_of_common_eoc[fno](cdata, len); break;
|
|
case _CMDID_SUBG_LD:
|
ret = func_of_common_ld[fno](cdata, len); break;
|
|
case _CMDID_SUBG_WOL:
|
ret = func_of_common_wol[fno](cdata, len); break;
|
|
case _CMDID_SUBG_STAG:
|
ret = func_of_common_stag[fno](cdata, len); break;
|
|
case _CMDID_SUB_BANDWIDTH:
|
ret = func_of_common_bandwidth[fno](cdata, len); break;
|
|
case _CMDID_SUBG_MISC:
|
ret = func_of_common_misc[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_VLAN:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_VLAN:
|
ret = func_of_common_vlan[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_QOS:
|
switch (fsubg)
|
{
|
case _CMDID_SUB_BANDWIDTH:
|
ret = func_of_common_bandwidth[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_SEC:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_IMP:
|
ret = func_of_common_imp[fno](cdata, len); break;
|
|
case _CMDID_SUBG_COS:
|
ret = func_of_common_cos[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_ADV:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_STP:
|
ret = func_of_common_stp[fno](cdata, len); break;
|
|
case _CMDID_SUBG_LACP:
|
ret = func_of_common_lacp[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
default:
|
ret = -EINVAL;
|
}
|
}
|
else if (fusg == _CMDID_USG_IP1811)
|
{
|
switch (fgrp)
|
{
|
case _CMDID_GRP_BASIC:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_CAP:
|
ret = func_of_common_cap[fno](cdata, len); break;
|
|
case _CMDID_SUBG_LUT:
|
ret = func_of_ip1811_lut[fno](cdata, len); break;
|
|
case _CMDID_SUBG_SNIFFER:
|
ret = func_of_ip1811_sniffer[fno](cdata, len); break;
|
|
case _CMDID_SUBG_STORM:
|
ret = func_of_ip1811_storm[fno](cdata, len); break;
|
|
case _CMDID_SUBG_EOC:
|
ret = func_of_ip1811_eoc[fno](cdata, len); break;
|
|
case _CMDID_SUBG_LD:
|
ret = func_of_ip1811_ld[fno](cdata, len); break;
|
|
case _CMDID_SUBG_WOL:
|
ret = func_of_ip1811_wol[fno](cdata, len); break;
|
|
case _CMDID_SUBG_IGMP:
|
ret = func_of_ip1811_igmp[fno](cdata, len); break;
|
|
case _CMDID_SUBG_PTP:
|
ret = func_of_ip1811_ptp[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_VLAN:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_VLAN:
|
ret = func_of_ip1811_vlan[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
case _CMDID_GRP_QOS:
|
switch (fsubg)
|
{
|
case _CMDID_SUB_QOS:
|
ret = func_of_ip1811_qos[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
case _CMDID_GRP_ACL:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_ACL:
|
ret = func_of_ip1811_acl[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_SEC:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_IMP:
|
ret = func_of_ip1811_imp[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_ADV:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_STP:
|
ret = func_of_ip1811_stp[fno](cdata, len); break;
|
|
case _CMDID_SUBG_LACP:
|
ret = func_of_ip1811_lacp[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
case _CMDID_GRP_MON:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_MIB_COUNTER:
|
ret = func_of_ip1811_mib_counter[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
case _CMDID_GRP_HSR:
|
switch (fsubg)
|
{
|
case _CMDID_SUBG_HSR:
|
ret = func_of_ip1811_hsr[fno](cdata, len); break;
|
|
default:
|
ret = -EINVAL;
|
}
|
break;
|
|
default:
|
ret = -EINVAL;
|
}
|
}
|
else
|
ret = -EINVAL;
|
|
if (ret < 0) goto out_ip1811_ioctl;
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0)
|
if(access_ok(WERIFY_WRITE, cptr, len)){
|
#else
|
if(access_ok(cptr, len)){
|
#endif
|
if (copy_to_user(cptr, cdata, len)) {
|
printk(KERN_ERR "copy_touser fail.");
|
ret = -EFAULT;
|
goto out_ip1811_ioctl;
|
}
|
}
|
else{
|
printk(KERN_ERR "[switchDriver] copy_from_user access fail by %s:%d CMD:%x\n",__FUNCTION__,__LINE__,cmd);
|
ret=-EFAULT;
|
goto out_ip1811_ioctl;
|
}
|
cptr= (void *)*((unsigned long *)cdata);
|
len = *((unsigned long *)(cdata+4));
|
|
kfree(cdata);
|
cdata = NULL;
|
} while (cptr);
|
out_ip1811_ioctl:
|
if(cdata)
|
{
|
//memset(cdata, 0x0, len);
|
kfree(cdata);
|
}
|
#ifdef IP1811DEBUG
|
printk(KERN_ALERT "ip1811: -ioctl...\n");
|
#endif
|
return (ret < 0) ? ret : 0;
|
}
|
|
static void lock_key_ioctl(void)
|
{
|
mutex_lock(&ip1811_mutex);
|
}
|
|
static void unlock_key_ioctl(void)
|
{
|
mutex_unlock(&ip1811_mutex);
|
}
|
|
static long ip1811_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
{
|
int ret;
|
|
lock_key_ioctl();
|
ret = ip1811_ioctl(filep, cmd, arg);
|
unlock_key_ioctl();
|
|
return ret;
|
}
|
|
static struct file_operations ip1811_fops = {
|
.owner = THIS_MODULE,
|
.read = ip1811_read,
|
.write = ip1811_write,
|
.unlocked_ioctl = ip1811_unlocked_ioctl,
|
.open = ip1811_open,
|
.release = ip1811_release
|
};
|
|
extern u16 Read_Reg(u8 regaddr);
|
extern void Write_Reg(u8 regaddr, u16 value);
|
extern void IP2Page(u8 page);
|
extern u16 Read_Reg_0_With_1s(void);
|
|
/* ==================================================================================== */
|
|
static int __init ip1811_init(void)
|
{
|
int result;
|
|
result = register_chrdev_region(MKDEV(IP1811_MAJOR, 0), 1, IP1811_NAME);
|
if (result < 0)
|
{
|
printk(KERN_WARNING "ip1811: can't get major %d\n", IP1811_MAJOR);
|
return result;
|
}
|
|
cdev_init(&ip1811_cdev, &ip1811_fops);
|
ip1811_cdev.owner = THIS_MODULE;
|
result = cdev_add(&ip1811_cdev, MKDEV(IP1811_MAJOR, 0), 1);
|
if (result)
|
{
|
printk(KERN_WARNING "ip1811: error %d adding driver\n", result);
|
return result;
|
}
|
|
CPU_IF_SPEED_NORMAL = 0; //set to normal speed initially
|
|
IP2Page(0);
|
if( (Read_Reg_0_With_1s() & 0xFFF0) == 0x8120 )
|
{
|
printk("ip1811: CPU I/F High speed.");
|
}
|
else
|
{
|
CPU_IF_SPEED_NORMAL = 1;
|
printk("ip1811: CPU I/F Normal speed.");
|
}
|
|
// for acl_man init.
|
acl_init();
|
|
printk(" Driver loaded!\n");
|
return 0;
|
/*
|
fail_return:
|
if(ip1811_cdev){
|
cdev_del(ip1811_cdev);
|
kfree(ip1811_cdev);
|
ip1811_cdev=NULL;
|
}
|
if(devno)
|
unregister_chrdev_region(devno, 1);
|
if(ip1811_class)
|
class_destroy(ip1811_class);
|
return -1;
|
*/
|
}
|
|
static void __exit ip1811_exit(void)
|
{
|
/*
|
if(ip1811_cdev){
|
cdev_del(ip1811_cdev);
|
kfree(ip1811_cdev);
|
ip1811_cdev=NULL;
|
}
|
if(devno)
|
unregister_chrdev_region(devno, 1);
|
if(ip1811_class)
|
class_destroy(ip1811_class);
|
*/
|
cdev_del(&ip1811_cdev);
|
unregister_chrdev_region(MKDEV(IP1811_MAJOR, 0), 1);
|
printk("ip1811: Driver unloaded!\n");
|
}
|
|
module_init(ip1811_init);
|
module_exit(ip1811_exit);
|