summaryrefslogtreecommitdiffstats
path: root/sys/dev/drm/drm_drv.h
diff options
context:
space:
mode:
authoranholt <anholt@FreeBSD.org>2002-09-01 17:45:04 +0000
committeranholt <anholt@FreeBSD.org>2002-09-01 17:45:04 +0000
commitd284cb7b2dfe362518bfe2df31ff39e2de0165d0 (patch)
tree0682915dfe24d5fae2b66e520fb6dbb2973e1bc5 /sys/dev/drm/drm_drv.h
parent9c25e3c24e9d5d443522478861808d382b8d9a1f (diff)
downloadFreeBSD-src-d284cb7b2dfe362518bfe2df31ff39e2de0165d0.zip
FreeBSD-src-d284cb7b2dfe362518bfe2df31ff39e2de0165d0.tar.gz
Remove drm_linux.h, move the two useful defines into drm_drv.h. Use fd locking
on -current. Actually copy in data from userspace to kernel in the linux-compat ioctl path. Make sure ioctl sizes are as expected in the handler functions. Reviewed by: rwatson
Diffstat (limited to 'sys/dev/drm/drm_drv.h')
-rw-r--r--sys/dev/drm/drm_drv.h73
1 files changed, 61 insertions, 12 deletions
diff --git a/sys/dev/drm/drm_drv.h b/sys/dev/drm/drm_drv.h
index cb50e1e..ff034dd 100644
--- a/sys/dev/drm/drm_drv.h
+++ b/sys/dev/drm/drm_drv.h
@@ -138,7 +138,6 @@ static struct file_operations DRM(fops) = { \
#include <sys/proc.h>
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
-#include "dev/drm/drm_linux.h"
#endif
#endif /* __FreeBSD__ */
#endif
@@ -1416,34 +1415,84 @@ int DRM(unlock)( DRM_OS_IOCTL )
return 0;
}
-#ifdef __FreeBSD__
#if DRM_LINUX
+#define LINUX_IOCTL_DRM_MIN 0x6400
+#define LINUX_IOCTL_DRM_MAX 0x64ff
+
static linux_ioctl_function_t DRM( linux_ioctl);
static struct linux_ioctl_handler DRM( handler) = {DRM( linux_ioctl), LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX};
SYSINIT (DRM( register), SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_register_handler, &DRM( handler));
SYSUNINIT(DRM( unregister), SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_unregister_handler, &DRM( handler));
+#define LINUX_IOC_VOID IOC_VOID
+#define LINUX_IOC_IN IOC_OUT /* Linux has the values the other way around */
+#define LINUX_IOC_OUT IOC_IN
+
/*
* Linux emulation IOCTL
*/
static int
DRM(linux_ioctl)(DRM_OS_STRUCTPROC *p, struct linux_ioctl_args* args)
{
+ u_long cmd = args->cmd;
+#define STK_PARAMS 128
+ union {
+ char stkbuf[STK_PARAMS];
+ long align;
+ } ubuf;
+ caddr_t data=NULL, memp=NULL;
+ u_int size = IOCPARM_LEN(cmd);
+ int error;
#if (__FreeBSD_version >= 500000)
- struct file *fp = p->td_proc->p_fd->fd_ofiles[args->fd];
+ struct file *fp;
#else
- struct file *fp = p->p_fd->fd_ofiles[args->fd];
+ struct file *fp = p->p_fd->fd_ofiles[args->fd];
#endif
- u_long cmd = args->cmd;
- caddr_t data = (caddr_t) args->arg;
- /*
- * Pass the ioctl off to our standard handler.
- */
+ if ( size > STK_PARAMS ) {
+ if ( size > IOCPARM_MAX )
+ return EINVAL;
+ memp = malloc( (u_long)size, DRM(M_DRM), M_WAITOK );
+ data = memp;
+ } else {
+ data = ubuf.stkbuf;
+ }
+
+ if ( cmd & LINUX_IOC_IN ) {
+ if ( size ) {
+ error = copyin( (caddr_t)args->arg, data, (u_int)size );
+ if (error) {
+ if ( memp )
+ free( data, DRM(M_DRM) );
+ return error;
+ }
+ } else {
+ data = (caddr_t)args->arg;
+ }
+ } else if ( (cmd & LINUX_IOC_OUT) && size ) {
+ /*
+ * Zero the buffer so the user always
+ * gets back something deterministic.
+ */
+ bzero( data, size );
+ } else if ( cmd & LINUX_IOC_VOID ) {
+ *(caddr_t *)data = (caddr_t)args->arg;
+ }
+
#if (__FreeBSD_version >= 500000)
- return(fo_ioctl(fp, cmd, data, p->td_ucred, p));
+ if ( (error = fget( p, args->fd, &fp )) != 0 ) {
+ if ( memp )
+ free( memp, DRM(M_DRM) );
+ return (error);
+ }
+ error = fo_ioctl( fp, cmd, data, p->td_ucred, p );
+ fdrop( fp, p );
#else
- return(fo_ioctl(fp, cmd, data, p));
+ error = fo_ioctl( fp, cmd, data, p );
#endif
+ if ( error == 0 && (cmd & LINUX_IOC_OUT) && size )
+ error = copyout( data, (caddr_t)args->arg, (u_int)size );
+ if ( memp )
+ free( memp, DRM(M_DRM) );
+ return error;
}
#endif /* DRM_LINUX */
-#endif /* __FreeBSD__ */
OpenPOWER on IntegriCloud