Can vm_mmap()/vm_map_remove() be called with giant held? (linuxolator dvb patches)

Juergen Lock nox at jelal.kn-bremen.de
Fri Feb 18 20:58:14 UTC 2011


I have finally got back to this and did the style and vm_map_remove()
return value handling fixes, updated the patches in-place:

	http://people.freebsd.org/~nox/dvb/linux-dvb.patch

(for head)

	http://people.freebsd.org/~nox/dvb/linux-dvb-8.patch

(for 8.)

On Sun, Jan 30, 2011 at 12:54:48AM +0100, Juergen Lock wrote:
> On Sat, Jan 29, 2011 at 10:51:05PM +0200, Kostik Belousov wrote:
> > On Sat, Jan 29, 2011 at 09:10:00PM +0100, Juergen Lock wrote:
> > > Hi!
> > > 
> > >  I was kinda hoping to be able to post a correct patch in public but
> > > getting an answer to ${Subject} seems to be more difficult than I
> > > thought... :)  So, does anyone here know?  copyout_map() and
> > You do not need Giant locked for vm_map* functions.
> > 
> The question was more do I need to drop it first before calling them...
> 
> > > copyout_unmap() are copied from ksyms_map() from sys/dev/ksyms/ksyms.c
> > > - should there maybe be global versions instead of two static copies
> > > each, and what would be good names?  And giant is taken by linux_ioctl()
> > Would you make a patch for this ?
> > 
>  Heh if you want me to...  Where should they go and are my name choices ok?
> 
 I haven't done this yet so people can keep patching linux.ko in-place
without having to build a new kernel too...

> > > in the same source file before calling the parts I added.  So here
> > > comes the patch, it is to add support for dvb ioctls to the linuxolator
> > > as discussed on -emulation earlier in this thread:
> > > 
> > > 	http://lists.freebsd.org/pipermail/freebsd-multimedia/2011-January/011575.html
> > > 
> > > (patch also at:
> > > 
> > > 	http://people.freebsd.org/~nox/dvb/linux-dvb.patch
> > > 
> > > and a version for 8, which is what I tested with w_scan on dvb-s2
> > > and dvb-t, and Andrew Gallatin also tested it with SageTV:
> > > 
> > > 	http://people.freebsd.org/~nox/dvb/linux-dvb-8.patch
> > > 
> > > )
> > > 

> > > +	/*
> > > +	 * Map somewhere after heap in process memory.
> > > +	 */
> > > +	PROC_LOCK(td->td_proc);
> > > +	*addr = round_page((vm_offset_t)vms->vm_daddr +
> > > +	    lim_max(td->td_proc, RLIMIT_DATA));
> > > +	PROC_UNLOCK(td->td_proc);
> > Are you sure that this is needed ? Why not leave the address selection
> > to the VM ?
> > 
>  I don't know, maybe sys/dev/ksyms/ksyms.c has a reason?

 How would I leave the address selection to the VM?  Just trying
to initialize *addr to (vm_offset_t)NULL there caused the patch to
stop working.

 Thanx, :)
	Juergen

 Here is the new version for head:

Index: src/sys/compat/linux/linux_ioctl.c
===================================================================
RCS file: /home/scvs/src/sys/compat/linux/linux_ioctl.c,v
retrieving revision 1.167
diff -u -p -r1.167 linux_ioctl.c
--- src/sys/compat/linux/linux_ioctl.c	30 Dec 2010 02:18:04 -0000	1.167
+++ src/sys/compat/linux/linux_ioctl.c	18 Feb 2011 20:10:32 -0000
@@ -59,6 +59,14 @@ __FBSDID("$FreeBSD: src/sys/compat/linux
 #include <sys/sx.h>
 #include <sys/tty.h>
 #include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/resourcevar.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_map.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -83,6 +91,9 @@ __FBSDID("$FreeBSD: src/sys/compat/linux
 #include <compat/linux/linux_videodev.h>
 #include <compat/linux/linux_videodev_compat.h>
 
+#include <compat/linux/linux_dvb.h>
+#include <compat/linux/linux_dvb_compat.h>
+
 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
 
 static linux_ioctl_function_t linux_ioctl_cdrom;
@@ -97,6 +108,7 @@ static linux_ioctl_function_t linux_ioct
 static linux_ioctl_function_t linux_ioctl_drm;
 static linux_ioctl_function_t linux_ioctl_sg;
 static linux_ioctl_function_t linux_ioctl_v4l;
+static linux_ioctl_function_t linux_ioctl_dvb;
 static linux_ioctl_function_t linux_ioctl_special;
 static linux_ioctl_function_t linux_ioctl_fbsd_usb;
 
@@ -124,6 +136,8 @@ static struct linux_ioctl_handler sg_han
 { linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX };
 static struct linux_ioctl_handler video_handler =
 { linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX };
+static struct linux_ioctl_handler dvb_handler =
+{ linux_ioctl_dvb, LINUX_IOCTL_DVB_MIN, LINUX_IOCTL_DVB_MAX };
 static struct linux_ioctl_handler fbsd_usb =
 { linux_ioctl_fbsd_usb, FBSD_LUSB_MIN, FBSD_LUSB_MAX };
 
@@ -139,6 +153,7 @@ DATA_SET(linux_ioctl_handler_set, privat
 DATA_SET(linux_ioctl_handler_set, drm_handler);
 DATA_SET(linux_ioctl_handler_set, sg_handler);
 DATA_SET(linux_ioctl_handler_set, video_handler);
+DATA_SET(linux_ioctl_handler_set, dvb_handler);
 DATA_SET(linux_ioctl_handler_set, fbsd_usb);
 
 struct handler_element
@@ -2989,6 +3004,255 @@ linux_ioctl_special(struct thread *td, s
 }
 
 /*
+ * Map some anonymous memory in user space of size sz, rounded up to the page
+ * boundary.
+ */
+static int
+copyout_map(struct thread *td, vm_offset_t *addr, size_t sz)
+{
+	struct vmspace *vms;
+	int error;
+	vm_size_t size;
+
+	vms = td->td_proc->p_vmspace;
+
+	/*
+	 * Map somewhere after heap in process memory.
+	 */
+	PROC_LOCK(td->td_proc);
+	*addr = round_page((vm_offset_t)vms->vm_daddr +
+	    lim_max(td->td_proc, RLIMIT_DATA));
+	PROC_UNLOCK(td->td_proc);
+
+	/* Round size up to page boundary. */
+	size = (vm_size_t)round_page(sz);
+
+	error = vm_mmap(&vms->vm_map, addr, size, PROT_READ | PROT_WRITE,
+	    VM_PROT_ALL, MAP_PRIVATE | MAP_ANON, OBJT_DEFAULT, NULL, 0);
+
+	return (error);
+}
+
+/*
+ * Unmap memory in user space.
+ */
+static int
+copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz)
+{
+	int error;
+	vm_map_t map;
+	vm_size_t size;
+
+	map = &td->td_proc->p_vmspace->vm_map;
+	size = (vm_size_t) round_page(sz);
+
+	error = vm_map_remove(map, addr, addr + size);
+
+	return (error);
+}
+
+static int
+linux_to_bsd_dtv_properties(struct l_dtv_properties *lvps, struct dtv_properties *vps)
+{
+
+	vps->num = lvps->num;
+	vps->props = PTRIN(lvps->props);	/* possible pointer size conversion */
+	return (0);
+}
+
+static int
+linux_to_bsd_dtv_property(struct l_dtv_property *lvp, struct dtv_property *vp)
+{
+
+	/*
+	 * Everything until u.buffer.reserved2 is fixed size so
+	 * just memcpy it.
+	 */
+	memcpy(vp, lvp, offsetof(struct l_dtv_property, u.buffer.reserved2));
+	/*
+	 * The pointer may be garbage since it's part of a union,
+	 * currently no Linux code uses it so just set it to NULL.
+	 */
+	vp->u.buffer.reserved2 = NULL;
+	vp->result = lvp->result;
+	return (0);
+}
+
+static int
+bsd_to_linux_dtv_property(struct dtv_property *vp, struct l_dtv_property *lvp)
+{
+
+	/*
+	 * Everything until u.buffer.reserved2 is fixed size so
+	 * just memcpy it.
+	 */
+	memcpy(lvp, vp, offsetof(struct l_dtv_property, u.buffer.reserved2));
+	/*
+	 * The pointer may be garbage since it's part of a union,
+	 * currently no Linux code uses it so just set it to NULL.
+	 */
+	lvp->u.buffer.reserved2 = PTROUT(NULL);
+	lvp->result = vp->result;
+	return (0);
+}
+
+static int
+linux_ioctl_dvb(struct thread *td, struct linux_ioctl_args *args)
+{
+	struct file *fp;
+	int error, i;
+	struct l_dtv_properties l_vps;
+	struct dtv_properties vps;
+	struct l_dtv_property *l_vp, *l_p;
+	struct dtv_property *vp, *p;
+	size_t l_propsiz, propsiz;
+	vm_offset_t uvp;
+
+	l_vp = NULL;
+	vp = NULL;
+
+	switch (args->cmd & 0xffff) {
+	case LINUX_AUDIO_STOP:
+	case LINUX_AUDIO_PLAY:
+	case LINUX_AUDIO_PAUSE:
+	case LINUX_AUDIO_CONTINUE:
+	case LINUX_AUDIO_SELECT_SOURCE:
+	case LINUX_AUDIO_SET_MUTE:
+	case LINUX_AUDIO_SET_AV_SYNC:
+	case LINUX_AUDIO_SET_BYPASS_MODE:
+	case LINUX_AUDIO_CHANNEL_SELECT:
+	case LINUX_AUDIO_CLEAR_BUFFER:
+	case LINUX_AUDIO_SET_ID:
+	case LINUX_AUDIO_SET_STREAMTYPE:
+	case LINUX_AUDIO_SET_EXT_ID:
+	case LINUX_AUDIO_BILINGUAL_CHANNEL_SELECT:
+	case LINUX_DMX_START:
+	case LINUX_DMX_STOP:
+	case LINUX_DMX_SET_BUFFER_SIZE:
+	case LINUX_NET_REMOVE_IF:
+	case LINUX_FE_DISEQC_RESET_OVERLOAD:
+	case LINUX_FE_DISEQC_SEND_BURST:
+	case LINUX_FE_SET_TONE:
+	case LINUX_FE_SET_VOLTAGE:
+	case LINUX_FE_ENABLE_HIGH_LNB_VOLTAGE:
+	case LINUX_FE_DISHNETWORK_SEND_LEGACY_CMD:
+	case LINUX_FE_SET_FRONTEND_TUNE_MODE:
+	case LINUX_CA_RESET:
+		if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID)
+			return ENOIOCTL;
+		args->cmd = (args->cmd & 0xffff) | IOC_VOID;
+		break;
+
+	case LINUX_DMX_REMOVE_PID:
+		/* overlaps with LINUX_NET_ADD_IF */
+		if ((args->cmd & IOC_DIRMASK) == LINUX_IOC_INOUT)
+			goto net_add_if;
+		/* FALLTHRU */
+	case LINUX_AUDIO_SET_MIXER:
+	case LINUX_AUDIO_SET_ATTRIBUTES:
+	case LINUX_AUDIO_SET_KARAOKE:
+	case LINUX_DMX_SET_FILTER:
+	case LINUX_DMX_SET_PES_FILTER:
+	case LINUX_DMX_SET_SOURCE:
+	case LINUX_DMX_ADD_PID:
+	case LINUX_FE_DISEQC_SEND_MASTER_CMD:
+	case LINUX_FE_SET_FRONTEND:
+	case LINUX_CA_SEND_MSG:
+	case LINUX_CA_SET_DESCR:
+	case LINUX_CA_SET_PID:
+		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN;
+		break;
+
+	case LINUX_AUDIO_GET_STATUS:
+	case LINUX_AUDIO_GET_CAPABILITIES:
+	case LINUX_AUDIO_GET_PTS:
+	case LINUX_DMX_GET_PES_PIDS:
+	case LINUX_DMX_GET_CAPS:
+	case LINUX_FE_GET_INFO:
+	case LINUX_FE_DISEQC_RECV_SLAVE_REPLY:
+	case LINUX_FE_READ_STATUS:
+	case LINUX_FE_READ_BER:
+	case LINUX_FE_READ_SIGNAL_STRENGTH:
+	case LINUX_FE_READ_SNR:
+	case LINUX_FE_READ_UNCORRECTED_BLOCKS:
+	case LINUX_FE_GET_FRONTEND:
+	case LINUX_FE_GET_EVENT:
+	case LINUX_CA_GET_CAP:
+	case LINUX_CA_GET_SLOT_INFO:
+	case LINUX_CA_GET_DESCR_INFO:
+	case LINUX_CA_GET_MSG:
+		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT;
+		break;
+
+	case LINUX_DMX_GET_STC:
+	case LINUX_NET_GET_IF:
+	net_add_if:
+		args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
+		break;
+
+	case LINUX_FE_SET_PROPERTY:
+	case LINUX_FE_GET_PROPERTY:
+		error = copyin((void *)args->arg, &l_vps, sizeof(l_vps));
+		if (error)
+			return (error);
+		linux_to_bsd_dtv_properties(&l_vps, &vps);
+		if ((vps.num == 0) || vps.num > DTV_IOCTL_MAX_MSGS)
+			return EINVAL;
+
+		l_propsiz = vps.num * sizeof(*l_vp);
+		propsiz = vps.num * sizeof(*vp);
+		l_vp = malloc(l_propsiz, M_LINUX, M_WAITOK);
+		vp = malloc(propsiz, M_LINUX, M_WAITOK);
+		error = copyin((void *)vps.props, l_vp, l_propsiz);
+		if (error)
+			goto out2;
+		for (i = vps.num, l_p = l_vp, p = vp; i--; ++l_p, ++p)
+			linux_to_bsd_dtv_property(l_p, p);
+
+		error = copyout_map(td, &uvp, propsiz);
+		if (error)
+			goto out2;
+		copyout(vp, (void *)uvp, propsiz);
+
+		if ((error = fget(td, args->fd, &fp)) != 0) {
+			(void)copyout_unmap(td, uvp, propsiz);
+			goto out2;
+		}
+		vps.props = (void *)uvp;
+		if ((args->cmd & 0xffff) == LINUX_FE_SET_PROPERTY)
+			error = fo_ioctl(fp, FE_SET_PROPERTY, &vps, td->td_ucred, td);
+		else
+			error = fo_ioctl(fp, FE_GET_PROPERTY, &vps, td->td_ucred, td);
+		if (error) {
+			(void)copyout_unmap(td, uvp, propsiz);
+			goto out;
+		}
+		error = copyin((void *)uvp, vp, propsiz);
+		(void)copyout_unmap(td, uvp, propsiz);
+		if (error)
+			goto out;
+		for (i = vps.num, l_p = l_vp, p = vp; i--; ++l_p, ++p)
+			bsd_to_linux_dtv_property(p, l_p);
+		linux_to_bsd_dtv_properties(&l_vps, &vps);
+		copyout(l_vp, (void *)vps.props, l_propsiz);
+
+	out:
+		fdrop(fp, td);
+	out2:
+		if (l_vp)
+			free(l_vp, M_LINUX);
+		if (vp)
+			free(vp, M_LINUX);
+		return (error);
+
+	default:			return (ENOIOCTL);
+	}
+
+	error = ioctl(td, (struct ioctl_args *)args);
+	return (error);
+}
+
+/*
  * Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros
  * instead of USB* ones. This lets us to provide correct values for cmd.
  * 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone.
Index: src/sys/compat/linux/linux_ioctl.h
===================================================================
RCS file: /home/scvs/src/sys/compat/linux/linux_ioctl.h,v
retrieving revision 1.32
diff -u -p -r1.32 linux_ioctl.h
--- src/sys/compat/linux/linux_ioctl.h	30 Dec 2010 02:18:04 -0000	1.32
+++ src/sys/compat/linux/linux_ioctl.h	18 Jan 2011 17:48:27 -0000
@@ -32,6 +32,17 @@
 #define	_LINUX_IOCTL_H_
 
 /*
+ * ioctl
+ *
+ * XXX comments in Linux' <asm-generic/ioctl.h> indicate these
+ * could be arch-dependant...
+ */
+#define LINUX_IOC_VOID		0
+#define LINUX_IOC_IN		0x40000000
+#define LINUX_IOC_OUT		0x80000000
+#define LINUX_IOC_INOUT		(LINUX_IOC_IN|LINUX_IOC_OUT)
+
+/*
  * disk
  */
 #define	LINUX_BLKROSET		0x125d
@@ -613,6 +624,83 @@ int		 linux_ifname(struct ifnet *, char 
 #define LINUX_IOCTL_VIDEO_MAX	LINUX_VIDIOCSVBIFMT
 
 /*
+ * DVB (osd.h and video.h not handled)
+ */
+#define LINUX_AUDIO_STOP			0x6f01 /* 0x00006f01 */
+#define LINUX_AUDIO_PLAY			0x6f02 /* 0x00006f02 */
+#define LINUX_AUDIO_PAUSE			0x6f03 /* 0x00006f03 */
+#define LINUX_AUDIO_CONTINUE			0x6f04 /* 0x00006f04 */
+#define LINUX_AUDIO_SELECT_SOURCE		0x6f05 /* 0x00006f05 */
+#define LINUX_AUDIO_SET_MUTE			0x6f06 /* 0x00006f06 */
+#define LINUX_AUDIO_SET_AV_SYNC			0x6f07 /* 0x00006f07 */
+#define LINUX_AUDIO_SET_BYPASS_MODE		0x6f08 /* 0x00006f08 */
+#define LINUX_AUDIO_CHANNEL_SELECT		0x6f09 /* 0x00006f09 */
+#define LINUX_AUDIO_GET_STATUS			0x6f0a /* 0x80206f0a */
+#define LINUX_AUDIO_GET_CAPABILITIES		0x6f0b /* 0x80046f0b */
+#define LINUX_AUDIO_CLEAR_BUFFER		0x6f0c /* 0x00006f0c */
+#define LINUX_AUDIO_SET_ID			0x6f0d /* 0x00006f0d */
+#define LINUX_AUDIO_SET_MIXER			0x6f0e /* 0x40086f0e */
+#define LINUX_AUDIO_SET_STREAMTYPE		0x6f0f /* 0x00006f0f */
+#define LINUX_AUDIO_SET_EXT_ID			0x6f10 /* 0x00006f10 */
+#define LINUX_AUDIO_SET_ATTRIBUTES		0x6f11 /* 0x40026f11 */
+#define LINUX_AUDIO_SET_KARAOKE			0x6f12 /* 0x400c6f12 */
+#define LINUX_AUDIO_GET_PTS			0x6f13 /* 0x80086f13 */
+#define LINUX_AUDIO_BILINGUAL_CHANNEL_SELECT	0x6f14 /* 0x00006f14 */
+#define LINUX_DMX_START				0x6f29 /* 0x00006f29 */
+#define LINUX_DMX_STOP				0x6f2a /* 0x00006f2a */
+#define LINUX_DMX_SET_FILTER			0x6f2b /* 0x403c6f2b */
+#define LINUX_DMX_SET_PES_FILTER		0x6f2c /* 0x40146f2c */
+#define LINUX_DMX_SET_BUFFER_SIZE		0x6f2d /* 0x00006f2d */
+#define LINUX_DMX_GET_PES_PIDS			0x6f2f /* 0x800a6f2f */
+#define LINUX_DMX_GET_CAPS			0x6f30 /* 0x80086f30 */
+#define LINUX_DMX_SET_SOURCE			0x6f31 /* 0x40046f31 */
+#define LINUX_DMX_GET_STC			0x6f32 /* 0xc0106f32 */
+#define LINUX_DMX_ADD_PID			0x6f33 /* 0x40026f33 */
+#define LINUX_DMX_REMOVE_PID			0x6f34 /* 0x40026f34 */
+#define LINUX_FE_GET_INFO			0x6f3d /* 0x80a86f3d */
+#define LINUX_FE_DISEQC_RESET_OVERLOAD		0x6f3e /* 0x00006f3e */
+#define LINUX_FE_DISEQC_SEND_MASTER_CMD		0x6f3f /* 0x40076f3f */
+#define LINUX_FE_DISEQC_RECV_SLAVE_REPLY	0x6f40 /* 0x800c6f40 */
+#define LINUX_FE_DISEQC_SEND_BURST		0x6f41 /* 0x00006f41 */
+#define LINUX_FE_SET_TONE			0x6f42 /* 0x00006f42 */
+#define LINUX_FE_SET_VOLTAGE			0x6f43 /* 0x00006f43 */
+#define LINUX_FE_ENABLE_HIGH_LNB_VOLTAGE	0x6f44 /* 0x00006f44 */
+#define LINUX_FE_READ_STATUS			0x6f45 /* 0x80046f45 */
+#define LINUX_FE_READ_BER			0x6f46 /* 0x80046f46 */
+#define LINUX_FE_READ_SIGNAL_STRENGTH		0x6f47 /* 0x80026f47 */
+#define LINUX_FE_READ_SNR			0x6f48 /* 0x80026f48 */
+#define LINUX_FE_READ_UNCORRECTED_BLOCKS	0x6f49 /* 0x80046f49 */
+#define LINUX_FE_SET_FRONTEND			0x6f4c /* 0x40246f4c */
+#define LINUX_FE_GET_FRONTEND			0x6f4d /* 0x80246f4d */
+#define LINUX_FE_GET_EVENT			0x6f4e /* 0x80286f4e */
+#define LINUX_FE_DISHNETWORK_SEND_LEGACY_CMD	0x6f50 /* 0x00006f50 */
+#define LINUX_FE_SET_FRONTEND_TUNE_MODE		0x6f51 /* 0x00006f51 */
+#define LINUX_FE_SET_PROPERTY			0x6f52 /* 0x40086f52 */
+#define LINUX_FE_GET_PROPERTY			0x6f53 /* 0x80086f53 */
+#define LINUX_CA_RESET				0x6f80 /* 0x00006f80 */
+#define LINUX_CA_GET_CAP			0x6f81 /* 0x80106f81 */
+#define LINUX_CA_GET_SLOT_INFO			0x6f82 /* 0x800c6f82 */
+#define LINUX_CA_GET_DESCR_INFO			0x6f83 /* 0x80086f83 */
+#define LINUX_CA_GET_MSG			0x6f84 /* 0x810c6f84 */
+#define LINUX_CA_SEND_MSG			0x6f85 /* 0x410c6f85 */
+#define LINUX_CA_SET_DESCR			0x6f86 /* 0x40106f86 */
+#define LINUX_CA_SET_PID			0x6f87 /* 0x40086f87 */
+
+/*
+ * DVB net.h
+ * (LINUX_NET_ADD_IF and LINUX___NET_ADD_IF_OLD overlap with
+ *  LINUX_DMX_REMOVE_PID)
+ */
+#define LINUX_NET_ADD_IF			0x6f34 /* 0xc0066f34 */
+#define LINUX_NET_REMOVE_IF			0x6f35 /* 0x00006f35 */
+#define LINUX_NET_GET_IF			0x6f36 /* 0xc0066f36 */
+#define LINUX___NET_ADD_IF_OLD			0x6f34 /* 0xc0046f34 */
+#define LINUX___NET_GET_IF_OLD			0x6f36 /* 0xc0046f36 */
+
+#define LINUX_IOCTL_DVB_MIN	LINUX_AUDIO_STOP
+#define LINUX_IOCTL_DVB_MAX	LINUX_CA_SET_PID
+
+/*
  * Our libusb(8) calls emulated within linux(4).
  */
 #define	FBSD_LUSB_DEVICEENUMERATE	0xffff
Index: src/sys/compat/linux/linux_dvb.h
@@ -0,0 +1,63 @@
+/*
+ * Extracted from <linux/dvb/frontend.h>, which is:
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus at convergence.de>
+ *		    Ralph  Metzler <ralph at convergence.de>
+ *		    Holger Waechtler <holger at convergence.de>
+ *		    Andre Draszik <ad at convergence.de>
+ *		    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef __LINUX_DVB_H
+#define __LINUX_DVB_H
+
+#include <sys/types.h>
+
+struct dtv_property {
+	uint32_t cmd;
+	uint32_t reserved[3];
+	union {
+		uint32_t data;
+		struct {
+			uint8_t data[32];
+			uint32_t len;
+			uint32_t reserved1[3];
+			void *reserved2;
+		} buffer;
+	} u;
+	int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+
+struct dtv_properties {
+	uint32_t num;
+	struct dtv_property *props;
+};
+
+#define FE_SET_PROPERTY		   _IOW('o', 82, struct dtv_properties)
+/* 
+ * This is broken on linux as well but they workaround it in the driver.
+ * Since this is impossible to do on FreeBSD fix the header instead.
+ * Detailed and discussion :
+ * http://lists.freebsd.org/pipermail/freebsd-multimedia/2010-April/010958.html
+ */
+#define FE_GET_PROPERTY		   _IOW('o', 83, struct dtv_properties)
+
+#endif /*__LINUX_DVB_H*/
Index: src/sys/compat/linux/linux_dvb_compat.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_DVB_COMPAT_H
+#define __LINUX_DVB_COMPAT_H
+
+#include <sys/types.h>
+
+struct l_dtv_property {
+	uint32_t cmd;
+	uint32_t reserved[3];
+	union {
+		uint32_t data;
+		struct {
+			uint8_t data[32];
+			uint32_t len;
+			uint32_t reserved1[3];
+			l_uintptr_t reserved2;
+		} buffer;
+	} u;
+	l_int result;
+} __attribute__ ((packed));
+
+struct l_dtv_properties {
+	uint32_t num;
+	l_uintptr_t props;
+};
+
+#endif /*__LINUX_DVB_H*/


More information about the freebsd-hackers mailing list