Implement various SNDRV_CTL_xxx ioctls.

Patch from Ivan Sorokin via BZ#334936.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14111 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index a693111..22e6250 100644
--- a/NEWS
+++ b/NEWS
@@ -160,6 +160,7 @@
 334705  sendmsg and recvmsg should guard against bogus msghdr fields.
 334727  Build fails with -Werror=format-security
 334788  clarify doc about --log-file initial program directory
+334936  patch to fix false positives on alsa SNDRV_CTL_* ioctls
 335034  Unhandled ioctl: HCIGETDEVLIST
 335155  vgdb, fix error print statement.
 335262  arm64: movi 8bit version is not supported
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index e1157e9..ed10584 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -6104,6 +6104,39 @@
    case VKI_SNDRV_PCM_IOCTL_LINK:
       /* these just take an int by value */
       break;
+   case VKI_SNDRV_CTL_IOCTL_PVERSION:
+      PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_PVERSION)", (Addr)ARG3, sizeof(int) );
+      break;
+   case VKI_SNDRV_CTL_IOCTL_CARD_INFO:
+      PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_CARD_INFO)", (Addr)ARG3, sizeof(struct vki_snd_ctl_card_info) );
+      break;
+   case VKI_SNDRV_CTL_IOCTL_ELEM_LIST: {
+      struct vki_snd_ctl_elem_list *data = (struct vki_snd_ctl_elem_list *)ARG3;
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->offset, sizeof(data->offset) );
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->space, sizeof(data->space) );
+      PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->used, sizeof(data->used) );
+      PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->count, sizeof(data->count) );
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)&data->pids, sizeof(data->pids) );
+      if (data->pids) {
+         PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_ELEM_LIST)", (Addr)data->pids, sizeof(struct vki_snd_ctl_elem_id) * data->space );
+      }
+      break;
+   }
+   case VKI_SNDRV_CTL_IOCTL_TLV_READ: {
+      struct vki_snd_ctl_tlv *data = (struct vki_snd_ctl_tlv *)ARG3;
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_READ)", (Addr)&data->numid, sizeof(data->numid) );
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_READ)", (Addr)&data->length, sizeof(data->length) );
+      PRE_MEM_WRITE( "ioctl(SNDRV_CTL_IOCTL_TLV_READ)", (Addr)data->tlv, data->length );
+      break;
+   }
+   case VKI_SNDRV_CTL_IOCTL_TLV_WRITE:
+   case VKI_SNDRV_CTL_IOCTL_TLV_COMMAND: {
+      struct vki_snd_ctl_tlv *data = (struct vki_snd_ctl_tlv *)ARG3;
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_WRITE)", (Addr)&data->numid, sizeof(data->numid) );
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_WRITE)", (Addr)&data->length, sizeof(data->length) );
+      PRE_MEM_READ( "ioctl(SNDRV_CTL_IOCTL_TLV_WRITE)", (Addr)data->tlv, data->length );
+      break;
+   }
 
       /* Real Time Clock (/dev/rtc) ioctls */
    case VKI_RTC_UIE_ON:
@@ -7449,6 +7482,30 @@
    case VKI_SNDRV_TIMER_IOCTL_STOP:
    case VKI_SNDRV_TIMER_IOCTL_CONTINUE:
    case VKI_SNDRV_TIMER_IOCTL_PAUSE:
+   case VKI_SNDRV_CTL_IOCTL_PVERSION: {
+      POST_MEM_WRITE( (Addr)ARG3, sizeof(int) );
+      break;
+   }
+   case VKI_SNDRV_CTL_IOCTL_CARD_INFO:
+      POST_MEM_WRITE( (Addr)ARG3, sizeof(struct vki_snd_ctl_card_info) );
+      break;
+   case VKI_SNDRV_CTL_IOCTL_ELEM_LIST: {
+      struct vki_snd_ctl_elem_list *data = (struct vki_snd_ctl_elem_list *)ARG3;
+      POST_MEM_WRITE( (Addr)&data->used, sizeof(data->used) );
+      POST_MEM_WRITE( (Addr)&data->count, sizeof(data->count) );
+      if (data->pids) {
+         POST_MEM_WRITE( (Addr)data->pids, sizeof(struct vki_snd_ctl_elem_id) * data->used );
+      }
+      break;
+   }
+   case VKI_SNDRV_CTL_IOCTL_TLV_READ: {
+      struct vki_snd_ctl_tlv *data = (struct vki_snd_ctl_tlv *)ARG3;
+      POST_MEM_WRITE( (Addr)data->tlv, data->length );
+      break;
+   }
+   case VKI_SNDRV_CTL_IOCTL_TLV_WRITE:
+   case VKI_SNDRV_CTL_IOCTL_TLV_COMMAND:
+      break;
 
       /* SCSI no operand */
    case VKI_SCSI_IOCTL_DOORLOCK:
diff --git a/docs/internals/3_9_BUGSTATUS.txt b/docs/internals/3_9_BUGSTATUS.txt
index 9e779c3..d972bae 100644
--- a/docs/internals/3_9_BUGSTATUS.txt
+++ b/docs/internals/3_9_BUGSTATUS.txt
@@ -168,7 +168,6 @@
 ========================================================================
 ========================================================================
 
-334936  patch to fix false positives on alsa SNDRV_CTL_* ioctls
 333628  Out of tree build  (is fixed, but needs to land)
 335143  Capabilities not supported
 197259  (wine) Unsupported arch_prtctl option
diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h
index 9123e24..9ee8603 100644
--- a/include/vki/vki-linux.h
+++ b/include/vki/vki-linux.h
@@ -2312,6 +2312,59 @@
 	VKI_SNDRV_TIMER_IOCTL_PAUSE = _VKI_IO('T', 0xa3),
 };
 
+struct vki_snd_ctl_card_info {
+	int card;			/* card number */
+	int pad;			/* reserved for future (was type) */
+	unsigned char id[16];		/* ID of card (user selectable) */
+	unsigned char driver[16];	/* Driver name */
+	unsigned char name[32];		/* Short name of soundcard */
+	unsigned char longname[80];	/* name + info text about soundcard */
+	unsigned char reserved_[16];	/* reserved for future (was ID of mixer) */
+	unsigned char mixername[80];	/* visual mixer identification */
+	unsigned char components[128];	/* card components / fine identification, delimited with one space (AC97 etc..) */
+};
+
+typedef int vki_snd_ctl_elem_iface_t;
+#define	VKI_SNDRV_CTL_ELEM_IFACE_CARD		((vki_snd_ctl_elem_iface_t) 0) /* global control */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_HWDEP		((vki_snd_ctl_elem_iface_t) 1) /* hardware dependent device */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_MIXER		((vki_snd_ctl_elem_iface_t) 2) /* virtual mixer device */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_PCM		((vki_snd_ctl_elem_iface_t) 3) /* PCM device */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_RAWMIDI	((vki_snd_ctl_elem_iface_t) 4) /* RawMidi device */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_TIMER		((vki_snd_ctl_elem_iface_t) 5) /* timer device */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_SEQUENCER	((vki_snd_ctl_elem_iface_t) 6) /* sequencer client */
+#define	VKI_SNDRV_CTL_ELEM_IFACE_LAST		VKI_SNDRV_CTL_ELEM_IFACE_SEQUENCER
+
+struct vki_snd_ctl_elem_id {
+	unsigned int numid;		/* numeric identifier, zero = invalid */
+	vki_snd_ctl_elem_iface_t iface;	/* interface identifier */
+	unsigned int device;		/* device/client number */
+	unsigned int subdevice;		/* subdevice (substream) number */
+	unsigned char name[44];		/* ASCII name of item */
+	unsigned int index;		/* index of item */
+};
+
+struct vki_snd_ctl_elem_list {
+	unsigned int offset;		/* W: first element ID to get */
+	unsigned int space;		/* W: count of element IDs to get */
+	unsigned int used;		/* R: count of element IDs set */
+	unsigned int count;		/* R: count of all elements */
+	struct vki_snd_ctl_elem_id __user *pids; /* R: IDs */
+	unsigned char reserved[50];
+};
+
+struct vki_snd_ctl_tlv {
+    unsigned int numid;	/* control element numeric identification */
+    unsigned int length;	/* in bytes aligned to 4 */
+    unsigned int tlv[0];	/* first TLV */
+};
+
+#define VKI_SNDRV_CTL_IOCTL_PVERSION	_VKI_IOR('U', 0x00, int)
+#define VKI_SNDRV_CTL_IOCTL_CARD_INFO	_VKI_IOR('U', 0x01, struct vki_snd_ctl_card_info)
+#define VKI_SNDRV_CTL_IOCTL_ELEM_LIST	_VKI_IOWR('U', 0x10, struct vki_snd_ctl_elem_list)
+#define VKI_SNDRV_CTL_IOCTL_TLV_READ	_VKI_IOWR('U', 0x1a, struct vki_snd_ctl_tlv)
+#define VKI_SNDRV_CTL_IOCTL_TLV_WRITE	_VKI_IOWR('U', 0x1b, struct vki_snd_ctl_tlv)
+#define VKI_SNDRV_CTL_IOCTL_TLV_COMMAND	_VKI_IOWR('U', 0x1c, struct vki_snd_ctl_tlv)
+
 //----------------------------------------------------------------------
 // From linux-2.6.15.4/include/linux/serial.h
 //----------------------------------------------------------------------