diff options
author | anholt <anholt@FreeBSD.org> | 2002-09-01 17:45:04 +0000 |
---|---|---|
committer | anholt <anholt@FreeBSD.org> | 2002-09-01 17:45:04 +0000 |
commit | d284cb7b2dfe362518bfe2df31ff39e2de0165d0 (patch) | |
tree | 0682915dfe24d5fae2b66e520fb6dbb2973e1bc5 /sys/dev/drm/drm_drv.h | |
parent | 9c25e3c24e9d5d443522478861808d382b8d9a1f (diff) | |
download | FreeBSD-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.h | 73 |
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__ */ |