mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-25 18:59:33 +03:00
Remove Solaris module emulation
Originally I believed that these interfaces would be needed. However, in practice it turned out that it was more straight forward and maintainable to use the native Linux interfaces. As such, this is all dead code and can be safely removed. Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #109
This commit is contained in:
parent
f90096c905
commit
38d31a1e57
@ -31,180 +31,23 @@
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/u8_textprep.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <spl-device.h>
|
||||
|
||||
#define DDI_MAX_NAME_LEN 32
|
||||
|
||||
typedef int ddi_devid_t;
|
||||
|
||||
typedef enum {
|
||||
DDI_INFO_DEVT2DEVINFO = 0,
|
||||
DDI_INFO_DEVT2INSTANCE = 1
|
||||
} ddi_info_cmd_t;
|
||||
#define DDI_DEV_T_NONE ((dev_t)-1)
|
||||
#define DDI_DEV_T_ANY ((dev_t)-2)
|
||||
#define DI_MAJOR_T_UNKNOWN ((major_t)0)
|
||||
|
||||
typedef enum {
|
||||
DDI_ATTACH = 0,
|
||||
DDI_RESUME = 1,
|
||||
DDI_PM_RESUME = 2
|
||||
} ddi_attach_cmd_t;
|
||||
#define DDI_PROP_DONTPASS 0x0001
|
||||
#define DDI_PROP_CANSLEEP 0x0002
|
||||
|
||||
typedef enum {
|
||||
DDI_DETACH = 0,
|
||||
DDI_SUSPEND = 1,
|
||||
DDI_PM_SUSPEND = 2,
|
||||
DDI_HOTPLUG_DETACH = 3
|
||||
} ddi_detach_cmd_t;
|
||||
#define DDI_SUCCESS 0
|
||||
#define DDI_FAILURE -1
|
||||
|
||||
typedef enum {
|
||||
DDI_RESET_FORCE = 0
|
||||
} ddi_reset_cmd_t;
|
||||
|
||||
typedef enum {
|
||||
PROP_LEN = 0,
|
||||
PROP_LEN_AND_VAL_BUF = 1,
|
||||
PROP_LEN_AND_VAL_ALLOC = 2,
|
||||
PROP_EXISTS = 3
|
||||
} ddi_prop_op_t;
|
||||
|
||||
typedef void *devmap_cookie_t;
|
||||
typedef struct as {
|
||||
uchar_t a_flags;
|
||||
} as_t;
|
||||
|
||||
typedef struct pollhead {
|
||||
struct polldat *ph_list;
|
||||
} pollhead_t;
|
||||
|
||||
typedef struct dev_info {
|
||||
kmutex_t di_lock;
|
||||
char di_name[DDI_MAX_NAME_LEN];
|
||||
struct dev_ops *di_ops;
|
||||
struct cdev *di_cdev;
|
||||
spl_class *di_class;
|
||||
spl_device *di_device;
|
||||
major_t di_major;
|
||||
minor_t di_minor;
|
||||
dev_t di_dev;
|
||||
unsigned di_minors;
|
||||
int di_flags;
|
||||
struct list_head di_list;
|
||||
} dev_info_t;
|
||||
|
||||
typedef struct cb_ops {
|
||||
int (*cb_open)(dev_t *devp, int flag, int otyp, cred_t *credp);
|
||||
int (*cb_close)(dev_t dev, int flag, int otyp, cred_t *credp);
|
||||
int (*cb_strategy)(void *bp);
|
||||
int (*cb_print)(dev_t dev, char *str);
|
||||
int (*cb_dump)(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
|
||||
int (*cb_read)(dev_t dev, struct uio *uiop, cred_t *credp);
|
||||
int (*cb_write)(dev_t dev, struct uio *uiop, cred_t *credp);
|
||||
int (*cb_ioctl)(dev_t dev, int cmd, intptr_t arg, int mode,
|
||||
cred_t *credp, int *rvalp);
|
||||
int (*cb_devmap)(dev_t dev, devmap_cookie_t dhp, offset_t off,
|
||||
size_t len, size_t *maplen, uint_t model);
|
||||
int (*cb_mmap)(dev_t dev, off_t off, int prot);
|
||||
int (*cb_segmap)(dev_t dev, off_t off, struct as *asp,
|
||||
caddr_t *addrp, off_t len, unsigned int prot,
|
||||
unsigned int maxprot, unsigned int flags,
|
||||
cred_t *credp);
|
||||
int (*cb_chpoll)(dev_t dev, short events, int anyyet,
|
||||
short *reventsp, struct pollhead **phpp);
|
||||
int (*cb_prop_op)(dev_t dev, dev_info_t *dip,
|
||||
ddi_prop_op_t prop_op, int mod_flags,
|
||||
char *name, caddr_t valuep, int *length);
|
||||
struct streamtab *cb_str;
|
||||
int cb_flag;
|
||||
int cb_rev;
|
||||
int (*cb_aread)(dev_t dev, struct aio_req *aio, cred_t *credp);
|
||||
int (*cb_awrite)(dev_t dev, struct aio_req *aio, cred_t *credp);
|
||||
} cb_ops_t;
|
||||
|
||||
typedef struct dev_ops {
|
||||
int devo_rev;
|
||||
int devo_refcnt;
|
||||
|
||||
int (*devo_getinfo)(dev_info_t *dip,
|
||||
ddi_info_cmd_t infocmd, void *arg, void **result);
|
||||
int (*devo_identify)(dev_info_t *dip);
|
||||
int (*devo_probe)(dev_info_t *dip);
|
||||
int (*devo_attach)(dev_info_t *dip, ddi_attach_cmd_t cmd);
|
||||
int (*devo_detach)(dev_info_t *dip, ddi_detach_cmd_t cmd);
|
||||
int (*devo_reset)(dev_info_t *dip, ddi_reset_cmd_t cmd);
|
||||
|
||||
struct cb_ops *devo_cb_ops;
|
||||
struct bus_ops *devo_bus_ops;
|
||||
int (*devo_power)(dev_info_t *dip, int component, int level);
|
||||
int (*devo_quiesce)(dev_info_t *dip);
|
||||
} dev_ops_t;
|
||||
|
||||
typedef struct mod_ops {
|
||||
int (*modm_install)(void);
|
||||
int (*modm_remove)(void);
|
||||
int (*modm_info)(void);
|
||||
} mod_ops_t;
|
||||
|
||||
typedef struct modldrv {
|
||||
struct mod_ops *drv_modops;
|
||||
char *drv_linkinfo;
|
||||
struct dev_ops *drv_dev_ops;
|
||||
struct dev_info *drv_dev_info;
|
||||
} modldrv_t;
|
||||
|
||||
#define MODREV_1 1
|
||||
|
||||
#define D_NEW 0x000
|
||||
#define D_MP 0x020
|
||||
#define D_64BIT 0x200
|
||||
|
||||
#define DEVO_REV 3
|
||||
#define CB_REV 1
|
||||
|
||||
#define DDI_SUCCESS 0
|
||||
#define DDI_FAILURE -1
|
||||
|
||||
#define DDI_PSEUDO "ddi_pseudo"
|
||||
|
||||
#define nodev NULL
|
||||
#define nochpoll NULL
|
||||
#define nulldev NULL
|
||||
#define mod_driverops NULL
|
||||
#define ddi_prop_op NULL
|
||||
|
||||
#define getminor(x) (x)
|
||||
#define getmajor(x) (x)
|
||||
#define ddi_driver_major(di) getmajor(di->di_dev)
|
||||
|
||||
#define DDI_DEV_T_NONE ((dev_t)-1)
|
||||
#define DDI_DEV_T_ANY ((dev_t)-2)
|
||||
#define DDI_MAJOR_T_UNKNOWN ((major_t)0)
|
||||
|
||||
#define DDI_PROP_DONTPASS 0x0001
|
||||
#define DDI_PROP_CANSLEEP 0x0002
|
||||
|
||||
#define GLOBAL_DEV 0x02
|
||||
#define NODEBOUND_DEV 0x04
|
||||
#define NODESPECIFIC_DEV 0x06
|
||||
#define ENUMERATED_DEV 0x08
|
||||
|
||||
#define ddi_prop_lookup_string(x1,x2,x3,x4,x5) (*x5 = NULL)
|
||||
#define ddi_prop_free(x) (void)0
|
||||
#define ddi_root_node() (void)0
|
||||
|
||||
#define mod_install(x) 0
|
||||
#define mod_remove(x) 0
|
||||
|
||||
extern int __ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
|
||||
minor_t minor_num, char *node_type,
|
||||
int flags, struct module *mod);
|
||||
extern void __ddi_remove_minor_node(dev_info_t *dip, char *name);
|
||||
extern int ddi_quiesce_not_needed(dev_info_t *dip);
|
||||
extern int __mod_install(struct modlinkage *modlp);
|
||||
extern int __mod_remove(struct modlinkage *modlp);
|
||||
extern int __mod_mknod(char *name, char *type, int major, int minor);
|
||||
#define ddi_prop_lookup_string(x1,x2,x3,x4,x5) (*x5 = NULL)
|
||||
#define ddi_prop_free(x) (void)0
|
||||
#define ddi_root_node() (void)0
|
||||
|
||||
extern int ddi_strtoul(const char *, char **, int, unsigned long *);
|
||||
extern int ddi_strtol(const char *, char **, int, long *);
|
||||
@ -214,89 +57,4 @@ extern int ddi_strtoll(const char *, char **, int, long long *);
|
||||
extern int ddi_copyin(const void *from, void *to, size_t len, int flags);
|
||||
extern int ddi_copyout(const void *from, void *to, size_t len, int flags);
|
||||
|
||||
static __inline__ void ddi_report_dev(dev_info_t *d) { }
|
||||
static __inline__ void ddi_prop_remove_all(dev_info_t *dip) { }
|
||||
|
||||
static __inline__ void
|
||||
ddi_remove_minor_node(dev_info_t *di, char *name)
|
||||
{
|
||||
#ifdef HAVE_GPL_ONLY_SYMBOLS
|
||||
/* Cleanup udev (GPL-only symbols required). This is performed as
|
||||
* part of an inline function to ensure that these symbols are not
|
||||
* linked against the SPL which is GPL'ed. But instead they are
|
||||
* linked against the package building against the SPL to ensure
|
||||
* its license allows linking with GPL-only symbols. */
|
||||
if (di->di_class) {
|
||||
spl_device_destroy(di->di_class, di->di_device, di->di_dev);
|
||||
spl_class_destroy(di->di_class);
|
||||
di->di_class = NULL;
|
||||
di->di_dev = 0;
|
||||
}
|
||||
#else
|
||||
/* When we do not have access to the GPL-only device interfaces we
|
||||
* are forced to do something crude. We unlink the special device
|
||||
* file in /dev/ ourselves from within the kernel. On the upside we
|
||||
* are already providing this functionality for Solaris, and it is
|
||||
* easy to leverage the Solaris API to perform the unlink. */
|
||||
if (strlen(di->di_name) > 0)
|
||||
vn_remove(di->di_name, UIO_SYSSPACE, RMFILE);
|
||||
|
||||
#endif /* HAVE_GPL_ONLY_SYMBOLS */
|
||||
|
||||
__ddi_remove_minor_node(di, name);
|
||||
}
|
||||
|
||||
static __inline__ int
|
||||
ddi_create_minor_node(dev_info_t *di, char *name, int spec_type,
|
||||
minor_t minor_num, char *node_type, int flags)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = __ddi_create_minor_node(di, name, spec_type, minor_num,
|
||||
node_type, flags, THIS_MODULE);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
#ifdef HAVE_GPL_ONLY_SYMBOLS
|
||||
/* Setup udev (GPL-only symbols required). This is performed as
|
||||
* part of an inline function to ensure that these symbols are not
|
||||
* linked against the SPL which is GPL'ed. But instead they are
|
||||
* linked against the package building against the SPL to ensure
|
||||
* its license allows linking with GPL-only symbols. */
|
||||
di->di_class = spl_class_create(THIS_MODULE, name);
|
||||
if (IS_ERR(di->di_class)) {
|
||||
rc = PTR_ERR(di->di_class);
|
||||
di->di_class = NULL;
|
||||
ddi_remove_minor_node(di, name);
|
||||
return DDI_FAILURE;
|
||||
}
|
||||
|
||||
/* Do not append a 0 to devices with minor nums of 0 */
|
||||
di->di_device = spl_device_create(di->di_class, NULL, di->di_dev, NULL,
|
||||
(di->di_minor == 0) ? "%s" : "%s%d",
|
||||
name, di->di_minor);
|
||||
#else
|
||||
/* When we do not have access to the GPL-only device interfaces we
|
||||
* are forced to do something horible. We use a user mode helper to
|
||||
* create the special device file in /dev/. By futher extending the
|
||||
* Solaris vnode implementation we could potentially do a vn_create()
|
||||
* from within the kernel but that's still a hack. */
|
||||
if (name) {
|
||||
rc = __mod_mknod(di->di_name, "c", di->di_major, di->di_minor);
|
||||
if (rc) {
|
||||
ddi_remove_minor_node(di, name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_GPL_ONLY_SYMBOLS */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#undef mod_install
|
||||
#undef mod_remove
|
||||
|
||||
#define mod_install __mod_install
|
||||
#define mod_remove __mod_remove
|
||||
|
||||
#endif /* SPL_SUNDDI_H */
|
||||
|
@ -18,7 +18,6 @@ spl-objs += @top_srcdir@/module/spl/spl-vnode.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-err.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-time.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-kobj.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-module.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-generic.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-atomic.o
|
||||
spl-objs += @top_srcdir@/module/spl/spl-mutex.o
|
||||
|
@ -1,375 +0,0 @@
|
||||
/*****************************************************************************\
|
||||
* Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
|
||||
* Copyright (C) 2007 The Regents of the University of California.
|
||||
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
|
||||
* Written by Brian Behlendorf <behlendorf1@llnl.gov>.
|
||||
* UCRL-CODE-235197
|
||||
*
|
||||
* This file is part of the SPL, Solaris Porting Layer.
|
||||
* For details, see <http://github.com/behlendorf/spl/>.
|
||||
*
|
||||
* The SPL 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.
|
||||
*
|
||||
* The SPL is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with the SPL. If not, see <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************
|
||||
* Solaris Porting Layer (SPL) Module Implementation.
|
||||
\*****************************************************************************/
|
||||
|
||||
#include <sys/sunddi.h>
|
||||
#include <spl-debug.h>
|
||||
|
||||
#ifdef SS_DEBUG_SUBSYS
|
||||
#undef SS_DEBUG_SUBSYS
|
||||
#endif
|
||||
|
||||
#define SS_DEBUG_SUBSYS SS_MODULE
|
||||
|
||||
static DEFINE_SPINLOCK(dev_info_lock);
|
||||
static LIST_HEAD(dev_info_list);
|
||||
|
||||
static struct dev_info *
|
||||
get_dev_info(dev_t dev)
|
||||
{
|
||||
struct dev_info *di;
|
||||
|
||||
spin_lock(&dev_info_lock);
|
||||
|
||||
list_for_each_entry(di, &dev_info_list, di_list)
|
||||
if (di->di_dev == dev)
|
||||
goto out;
|
||||
|
||||
di = NULL;
|
||||
out:
|
||||
spin_unlock(&dev_info_lock);
|
||||
return di;
|
||||
}
|
||||
|
||||
static long
|
||||
mod_generic_unlocked_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *ino = file->f_dentry->d_inode;
|
||||
struct dev_info *di;
|
||||
int rc, flags = 0, rvalp = 0;
|
||||
cred_t *cr = NULL;
|
||||
|
||||
di = get_dev_info(MKDEV(imajor(ino), iminor(ino)));
|
||||
if (di == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
rc = di->di_ops->devo_cb_ops->cb_ioctl(di->di_dev,
|
||||
(int)cmd, (intptr_t)arg,
|
||||
flags, cr, &rvalp);
|
||||
/*
|
||||
* The Solaris the kernel returns positive error codes to indicate
|
||||
* a failure. Under linux the kernel is expected to return a
|
||||
* small negative value which is trapped by libc and used to
|
||||
* set errno correctly. For this reason we negate the Solaris
|
||||
* return code to ensure errno gets set correctly.
|
||||
*/
|
||||
return -rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* Compatibility handler for ioctls from 32-bit ELF binaries */
|
||||
static long
|
||||
mod_generic_compat_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return mod_generic_unlocked_ioctl(file, cmd, arg);
|
||||
}
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
int
|
||||
__ddi_create_minor_node(dev_info_t *di, char *name, int spec_type,
|
||||
minor_t minor_num, char *node_type,
|
||||
int flags, struct module *mod)
|
||||
{
|
||||
struct cdev *cdev;
|
||||
struct cb_ops *cb_ops;
|
||||
struct file_operations *fops;
|
||||
int rc;
|
||||
SENTRY;
|
||||
|
||||
ASSERT(spec_type == S_IFCHR);
|
||||
ASSERT(minor_num < di->di_minors);
|
||||
ASSERT(!strcmp(node_type, DDI_PSEUDO));
|
||||
|
||||
fops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
|
||||
if (fops == NULL)
|
||||
SRETURN(DDI_FAILURE);
|
||||
|
||||
cdev = cdev_alloc();
|
||||
if (cdev == NULL) {
|
||||
kfree(fops);
|
||||
SRETURN(DDI_FAILURE);
|
||||
}
|
||||
|
||||
cdev->ops = fops;
|
||||
|
||||
mutex_enter(&di->di_lock);
|
||||
cb_ops = di->di_ops->devo_cb_ops;
|
||||
ASSERT(cb_ops);
|
||||
|
||||
/* Setup the fops to cb_ops mapping */
|
||||
fops->owner = mod;
|
||||
if (cb_ops->cb_ioctl) {
|
||||
fops->unlocked_ioctl = mod_generic_unlocked_ioctl;
|
||||
#ifdef CONFIG_COMPAT
|
||||
fops->compat_ioctl = mod_generic_compat_ioctl;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (cb_ops->cb_open)
|
||||
fops->open = mod_generic_open;
|
||||
|
||||
if (cb_ops->cb_close)
|
||||
fops->release = mod_generic_close;
|
||||
|
||||
if (cb_ops->cb_read)
|
||||
fops->read = mod_generic_read;
|
||||
|
||||
if (cb_ops->cb_write)
|
||||
fops->write = mod_generic_write;
|
||||
#endif
|
||||
/* XXX: Currently unsupported operations */
|
||||
ASSERT(cb_ops->cb_open == NULL);
|
||||
ASSERT(cb_ops->cb_close == NULL);
|
||||
ASSERT(cb_ops->cb_read == NULL);
|
||||
ASSERT(cb_ops->cb_write == NULL);
|
||||
ASSERT(cb_ops->cb_strategy == NULL);
|
||||
ASSERT(cb_ops->cb_print == NULL);
|
||||
ASSERT(cb_ops->cb_dump == NULL);
|
||||
ASSERT(cb_ops->cb_devmap == NULL);
|
||||
ASSERT(cb_ops->cb_mmap == NULL);
|
||||
ASSERT(cb_ops->cb_segmap == NULL);
|
||||
ASSERT(cb_ops->cb_chpoll == NULL);
|
||||
ASSERT(cb_ops->cb_prop_op == NULL);
|
||||
ASSERT(cb_ops->cb_str == NULL);
|
||||
ASSERT(cb_ops->cb_aread == NULL);
|
||||
ASSERT(cb_ops->cb_awrite == NULL);
|
||||
|
||||
snprintf(di->di_name, DDI_MAX_NAME_LEN-1, "/dev/%s", name);
|
||||
di->di_cdev = cdev;
|
||||
di->di_flags = flags;
|
||||
di->di_minor = minor_num;
|
||||
di->di_dev = MKDEV(di->di_major, di->di_minor);
|
||||
|
||||
rc = cdev_add(cdev, di->di_dev, 1);
|
||||
if (rc) {
|
||||
SERROR("Error adding cdev, %d\n", rc);
|
||||
kfree(fops);
|
||||
cdev_del(cdev);
|
||||
mutex_exit(&di->di_lock);
|
||||
SRETURN(DDI_FAILURE);
|
||||
}
|
||||
|
||||
spin_lock(&dev_info_lock);
|
||||
list_add(&di->di_list, &dev_info_list);
|
||||
spin_unlock(&dev_info_lock);
|
||||
|
||||
mutex_exit(&di->di_lock);
|
||||
|
||||
SRETURN(DDI_SUCCESS);
|
||||
}
|
||||
EXPORT_SYMBOL(__ddi_create_minor_node);
|
||||
|
||||
static void
|
||||
__ddi_remove_minor_node_locked(dev_info_t *di, char *name)
|
||||
{
|
||||
if (di->di_cdev) {
|
||||
cdev_del(di->di_cdev);
|
||||
di->di_cdev = NULL;
|
||||
}
|
||||
|
||||
spin_lock(&dev_info_lock);
|
||||
list_del_init(&di->di_list);
|
||||
spin_unlock(&dev_info_lock);
|
||||
}
|
||||
|
||||
void
|
||||
__ddi_remove_minor_node(dev_info_t *di, char *name)
|
||||
{
|
||||
SENTRY;
|
||||
mutex_enter(&di->di_lock);
|
||||
__ddi_remove_minor_node_locked(di, name);
|
||||
mutex_exit(&di->di_lock);
|
||||
SEXIT;
|
||||
}
|
||||
EXPORT_SYMBOL(__ddi_remove_minor_node);
|
||||
|
||||
int
|
||||
ddi_quiesce_not_needed(dev_info_t *dip)
|
||||
{
|
||||
SRETURN(DDI_SUCCESS);
|
||||
}
|
||||
EXPORT_SYMBOL(ddi_quiesce_not_needed);
|
||||
|
||||
#if 0
|
||||
static int
|
||||
mod_generic_open(struct inode *, struct file *)
|
||||
{
|
||||
open(dev_t *devp, int flags, int otyp, cred_t *credp);
|
||||
}
|
||||
|
||||
static int
|
||||
mod_generic_close(struct inode *, struct file *)
|
||||
{
|
||||
close(dev_t dev, int flags, int otyp, cred_t *credp);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
mod_generic_read(struct file *, char __user *, size_t, loff_t *)
|
||||
{
|
||||
read(dev_t dev, struct uio *uiop, cred_t *credp);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
mod_generic_write(struct file *, const char __user *, size_t, loff_t *)
|
||||
{
|
||||
write(dev_t dev, struct uio *uiop, cred_t *credp);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct dev_info *
|
||||
dev_info_alloc(major_t major, minor_t minors, struct dev_ops *ops) {
|
||||
struct dev_info *di;
|
||||
|
||||
di = kmalloc(sizeof(struct dev_info), GFP_KERNEL);
|
||||
if (di == NULL)
|
||||
return NULL;
|
||||
|
||||
mutex_init(&di->di_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
INIT_LIST_HEAD(&di->di_list);
|
||||
di->di_ops = ops;
|
||||
di->di_class = NULL;
|
||||
di->di_cdev = NULL;
|
||||
di->di_major = major;
|
||||
di->di_minor = 0;
|
||||
di->di_minors = minors;
|
||||
di->di_dev = 0;
|
||||
|
||||
return di;
|
||||
}
|
||||
|
||||
static void
|
||||
dev_info_free(struct dev_info *di)
|
||||
{
|
||||
mutex_enter(&di->di_lock);
|
||||
__ddi_remove_minor_node_locked(di, NULL);
|
||||
mutex_exit(&di->di_lock);
|
||||
mutex_destroy(&di->di_lock);
|
||||
kfree(di);
|
||||
}
|
||||
|
||||
int
|
||||
__mod_install(struct modlinkage *modlp)
|
||||
{
|
||||
struct modldrv *drv = modlp->ml_modldrv;
|
||||
struct dev_info *di;
|
||||
int rc;
|
||||
SENTRY;
|
||||
|
||||
di = dev_info_alloc(modlp->ml_major, modlp->ml_minors,
|
||||
drv->drv_dev_ops);
|
||||
if (di == NULL)
|
||||
SRETURN(ENOMEM);
|
||||
|
||||
/* XXX: Really we need to be calling devo_probe if it's available
|
||||
* and then calling devo_attach for each device discovered. However
|
||||
* for now we just call it once and let the app sort it out.
|
||||
*/
|
||||
rc = drv->drv_dev_ops->devo_attach(di, DDI_ATTACH);
|
||||
if (rc != DDI_SUCCESS) {
|
||||
dev_info_free(di);
|
||||
SRETURN(rc);
|
||||
}
|
||||
|
||||
drv->drv_dev_info = di;
|
||||
|
||||
SRETURN(DDI_SUCCESS);
|
||||
}
|
||||
EXPORT_SYMBOL(__mod_install);
|
||||
|
||||
int
|
||||
__mod_mknod(char *name, char *type, int major, int minor)
|
||||
{
|
||||
char cmd[] = "/bin/mknod";
|
||||
char major_str[8];
|
||||
char minor_str[8];
|
||||
char *argv[] = { cmd,
|
||||
name,
|
||||
type,
|
||||
major_str,
|
||||
minor_str,
|
||||
NULL };
|
||||
char *envp[] = { "HOME=/",
|
||||
"TERM=linux",
|
||||
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
|
||||
NULL };
|
||||
|
||||
snprintf(major_str, 8, "%d", major);
|
||||
snprintf(minor_str, 8, "%d", minor);
|
||||
|
||||
return call_usermodehelper(cmd, argv, envp, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(__mod_mknod);
|
||||
|
||||
int
|
||||
__mod_remove(struct modlinkage *modlp)
|
||||
{
|
||||
struct modldrv *drv = modlp->ml_modldrv;
|
||||
struct dev_info *di = drv->drv_dev_info;
|
||||
int rc;
|
||||
SENTRY;
|
||||
|
||||
rc = drv->drv_dev_ops->devo_detach(di, DDI_DETACH);
|
||||
if (rc != DDI_SUCCESS)
|
||||
SRETURN(rc);
|
||||
|
||||
dev_info_free(di);
|
||||
drv->drv_dev_info = NULL;
|
||||
|
||||
SRETURN(DDI_SUCCESS);
|
||||
}
|
||||
EXPORT_SYMBOL(__mod_remove);
|
||||
|
||||
int
|
||||
ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
|
||||
{
|
||||
ldi_ident_t li;
|
||||
SENTRY;
|
||||
|
||||
ASSERT(modlp);
|
||||
ASSERT(lip);
|
||||
|
||||
li = kmalloc(sizeof(struct ldi_ident), GFP_KERNEL);
|
||||
if (li == NULL)
|
||||
SRETURN(ENOMEM);
|
||||
|
||||
li->li_dev = MKDEV(modlp->ml_major, 0);
|
||||
*lip = li;
|
||||
|
||||
SRETURN(0);
|
||||
}
|
||||
EXPORT_SYMBOL(ldi_ident_from_mod);
|
||||
|
||||
void
|
||||
ldi_ident_release(ldi_ident_t lip)
|
||||
{
|
||||
SENTRY;
|
||||
ASSERT(lip);
|
||||
kfree(lip);
|
||||
SEXIT;
|
||||
}
|
||||
EXPORT_SYMBOL(ldi_ident_release);
|
Loading…
Reference in New Issue
Block a user