304 lines
7.7 KiB
C
304 lines
7.7 KiB
C
/*****************************************************************************
|
|
* sdla_ec_dev.c
|
|
*
|
|
* WANPIPE(tm) EC Device
|
|
*
|
|
* Authors: Nenad Corbic <ncorbic@sangoma.com>
|
|
*
|
|
* Copyright: (c) 2003-2006 Sangoma Technologies Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
* ============================================================================
|
|
* Jan 16, 2006 Nenad Corbic Initial version.
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "wanpipe_includes.h"
|
|
#include "wanpipe_defines.h"
|
|
#include "wanpipe_debug.h"
|
|
#include "wanpipe.h"
|
|
#if defined(__LINUX__)
|
|
# include "if_wanpipe.h"
|
|
#endif
|
|
|
|
#include "oct6100_api.h"
|
|
#include "oct6100_version.h"
|
|
|
|
#include "wanec_iface.h"
|
|
#include "wanec_iface_api.h"
|
|
|
|
#if !defined(__WINDOWS__)
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
|
# define WP_ECDEV_UDEV 1
|
|
# undef WP_CONFIG_DEVFS_FS
|
|
#else
|
|
# undef WP_ECDEV_UDEV
|
|
# ifdef CONFIG_DEVFS_FS
|
|
# include <linux/devfs_fs_kernel.h>
|
|
# define WP_CONFIG_DEVFS_FS
|
|
# else
|
|
# undef WP_CONFIG_DEVFS_FS
|
|
# warning "Error: Hardware EC Device requires DEVFS: HWEC Will not be supported!"
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef WP_CONFIG_DEVFS_FS
|
|
#define WP_ECDEV_MAJOR 242
|
|
#endif
|
|
#define WANEC_DEV_MAX_MINORS 256
|
|
|
|
#ifdef WP_ECDEV_UDEV
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
|
|
#define class_device_destroy device_destroy
|
|
#define WP_CLASS_DEV_CREATE(class, devt, device, priv_data, name) \
|
|
device_create_drvdata(class, device, devt, priv_data, name)
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
|
|
#define WP_CLASS_DEV_CREATE(class, devt, device, priv_data, name) \
|
|
class_device_create(class, NULL, devt, device, name)
|
|
#else
|
|
#define WP_CLASS_DEV_CREATE(class, devt, device, priv_data, name) \
|
|
class_device_create(class, devt, device, name)
|
|
#endif
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
|
|
static struct class *wanec_dev_class = NULL;
|
|
static struct cdev wanec_cdev = {
|
|
#ifndef LINUX_FEAT_2624
|
|
.kobj = {.name = "wp_ec", },
|
|
#endif
|
|
.owner = THIS_MODULE,
|
|
};
|
|
static dev_t wanec_dev = 0;
|
|
#else
|
|
static struct class_simple *wanec_dev_class = NULL;
|
|
#define class_create class_simple_create
|
|
#define class_destroy class_simple_destroy
|
|
#define class_device_create class_simple_device_add
|
|
#define class_device_destroy(a, b) class_simple_device_remove(b)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#define UNIT(file) MINOR(file->f_dentry->d_inode->i_rdev)
|
|
|
|
#define WP_ECDEV_MAX_CHIPS 255
|
|
|
|
#ifdef WP_CONFIG_DEVFS_FS
|
|
devfs_handle_t devfs_handle;
|
|
#endif
|
|
|
|
#endif/*#if !defined(__WINDOWS__)*/
|
|
|
|
|
|
static int wanec_dev_open(struct inode*, struct file*);
|
|
static int wanec_dev_release(struct inode*, struct file*);
|
|
|
|
#if defined(__WINDOWS__)
|
|
int wanec_dev_ioctl(void *data, char *card_devname);
|
|
#else
|
|
static WAN_IOCTL_RET_TYPE WANDEF_IOCTL_FUNC(wanec_dev_ioctl, struct file*, unsigned int, unsigned long);
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
|
|
static long wanec_dev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long data);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(__WINDOWS__)
|
|
/*==============================================================
|
|
Global Variables
|
|
*/
|
|
static struct file_operations wanec_dev_fops = {
|
|
owner: THIS_MODULE,
|
|
llseek: NULL,
|
|
open: wanec_dev_open,
|
|
release: wanec_dev_release,
|
|
WAN_IOCTL: wanec_dev_ioctl,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
|
|
compat_ioctl: wanec_dev_compat_ioctl,
|
|
#endif
|
|
read: NULL,
|
|
write: NULL,
|
|
poll: NULL,
|
|
mmap: NULL,
|
|
flush: NULL,
|
|
fsync: NULL,
|
|
fasync: NULL,
|
|
};
|
|
|
|
int wanec_create_dev(void)
|
|
{
|
|
int err;
|
|
|
|
DEBUG_EVENT("%s: Registering Wanpipe ECDEV Device!\n",__FUNCTION__);
|
|
#ifdef WP_ECDEV_UDEV
|
|
wanec_dev_class = class_create(THIS_MODULE, "wp_ec");
|
|
#endif
|
|
|
|
#ifdef WP_CONFIG_DEVFS_FS
|
|
err=devfs_register_chrdev(WP_ECDEV_MAJOR, "wp_ec", &wanec_dev_fops);
|
|
if (err) {
|
|
DEBUG_EVENT("Unable to register tor device on %d\n", WP_ECDEV_MAJOR);
|
|
return err;
|
|
}
|
|
#else
|
|
if ((err=alloc_chrdev_region(&wanec_dev, 0, WANEC_DEV_MAX_MINORS, "wp_ec"))) {
|
|
DEBUG_EVENT("Unable to alloc chrdev region for wanpipe ec device with %d minors\n", WANEC_DEV_MAX_MINORS);
|
|
return err;
|
|
}
|
|
cdev_init(&wanec_cdev, &wanec_dev_fops);
|
|
if (cdev_add(&wanec_cdev, wanec_dev, WANEC_DEV_MAX_MINORS)) {
|
|
kobject_put(&wanec_cdev.kobj);
|
|
unregister_chrdev_region(wanec_dev, WANEC_DEV_MAX_MINORS);
|
|
DEBUG_ERROR("%s(): Error wanec cdev_add!\n",__FUNCTION__);
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WP_ECDEV_UDEV
|
|
WP_CLASS_DEV_CREATE( wanec_dev_class,
|
|
MKDEV(MAJOR(wanec_dev), 0),
|
|
NULL,NULL,
|
|
WANEC_DEV_NAME);
|
|
#endif
|
|
|
|
#ifdef WP_CONFIG_DEVFS_FS
|
|
{
|
|
umode_t mode = S_IFCHR|S_IRUGO|S_IWUGO;
|
|
devfs_handle = devfs_register(NULL, WANEC_DEV_NAME, DEVFS_FL_DEFAULT, WP_ECDEV_MAJOR,
|
|
0, mode, &wanec_dev_fops, NULL);
|
|
}
|
|
#endif
|
|
|
|
return err;
|
|
}
|
|
|
|
int wanec_remove_dev(void)
|
|
{
|
|
DEBUG_EVENT("%s: Unregistering Wanpipe ECDEV Device!\n",__FUNCTION__);
|
|
|
|
#ifdef WP_ECDEV_UDEV
|
|
class_device_destroy( wanec_dev_class,
|
|
MKDEV(MAJOR(wanec_dev), 0));
|
|
#endif
|
|
|
|
#ifdef WP_CONFIG_DEVFS_FS
|
|
devfs_unregister(devfs_handle);
|
|
#endif
|
|
|
|
#ifdef WP_ECDEV_UDEV
|
|
class_destroy(wanec_dev_class);
|
|
#endif
|
|
|
|
#ifdef WP_CONFIG_DEVFS_FS
|
|
devfs_unregister_chrdev(WP_ECDEV_MAJOR, "wp_ec");
|
|
#else
|
|
cdev_del(&wanec_cdev);
|
|
unregister_chrdev_region(wanec_dev, WANEC_DEV_MAX_MINORS);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#else/*#if !defined(__WINDOWS__)*/
|
|
|
|
int wanec_create_dev(void)
|
|
{
|
|
int err = 0;
|
|
DEBUG_EVENT("%s(): Registering Wanpipe ECDEV Device!\n",__FUNCTION__);
|
|
return err;
|
|
}
|
|
|
|
int wanec_remove_dev(void)
|
|
{
|
|
DEBUG_EVENT("%s(): Unregistering Wanpipe ECDEV Device!\n",__FUNCTION__);
|
|
return 0;
|
|
}
|
|
#endif/*#if !defined(__WINDOWS__)*/
|
|
|
|
static int wanec_dev_open(struct inode *inode, struct file *file)
|
|
{
|
|
DEBUG_TEST ("%s: DRIVER OPEN EC DEV\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wanec_dev_release(struct inode *inode, struct file *file)
|
|
{
|
|
DEBUG_TEST ("%s: DRIVER CLOSE EC DEV\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(__WINDOWS__)
|
|
extern int wanec_ioctl(void*);
|
|
int wanec_dev_ioctl(void *data, char *card_devname)
|
|
{
|
|
int rc;
|
|
wan_ec_api_t *ec_api;
|
|
char original_ec_api_dev_name[WAN_DRVNAME_SZ];
|
|
|
|
if (data == 0){
|
|
DEBUG_ERROR("%s(): Error: data pointer is NULL!\n",__FUNCTION__);
|
|
return EINVAL;
|
|
}
|
|
|
|
ec_api = (wan_ec_api_t*)data;
|
|
#if 0
|
|
DbgPrint("%s(): card_devname: %s, ec_api->devname: %s",
|
|
__FUNCTION__, card_devname, ec_api->devname);
|
|
#endif
|
|
/* keep the original name which was set in user mode */
|
|
snprintf(original_ec_api_dev_name, WAN_DRVNAME_SZ, "%s", ec_api->devname);
|
|
|
|
/* In user mode the 'ec_api->devname' is set to interface name.
|
|
For example "wanpipe2_if0". But wanec code needs 'card name',
|
|
("wanpipe2") not 'interface name' when the wanec_search() is called.
|
|
Change 'ec_api->devname' to be the 'card name': */
|
|
snprintf(ec_api->devname, WAN_DRVNAME_SZ, "%s", card_devname);
|
|
|
|
rc = wanec_ioctl(data);
|
|
|
|
/* restore the original name which was set in user mode */
|
|
snprintf(ec_api->devname, WAN_DRVNAME_SZ, "%s", original_ec_api_dev_name);
|
|
|
|
return rc;
|
|
}
|
|
#else
|
|
extern WAN_IOCTL_RET_TYPE wanec_ioctl(unsigned int, void*);
|
|
static WAN_IOCTL_RET_TYPE WANDEF_IOCTL_FUNC(wanec_dev_ioctl, struct file *file, unsigned int cmd, unsigned long data)
|
|
{
|
|
long ret;
|
|
if (data == 0){
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef HAVE_UNLOCKED_IOCTL
|
|
ret = wanec_ioctl(cmd,(void*)data);
|
|
return ret;
|
|
#else
|
|
return wanec_ioctl(cmd,(void*)data);
|
|
#endif
|
|
}
|
|
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
|
|
static long wanec_dev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long data)
|
|
{
|
|
#ifdef HAVE_UNLOCKED_IOCTL
|
|
long err = (long) wanec_dev_ioctl(file, cmd, data);
|
|
#else
|
|
long err = (long) wanec_dev_ioctl(NULL, file, cmd, data);
|
|
#endif
|
|
return err;
|
|
}
|
|
#endif
|
|
|
|
|
|
#endif
|