/* -------------------------------------------------------- */
 
+static const struct ioctl_handler {
+       unsigned int cmd;
+       int (*func)(struct snd_seq_client *client, void *arg);
+} ioctl_handlers[] = {
+       { 0, NULL },
+};
+
 static struct seq_ioctl_table {
        unsigned int cmd;
        int (*func)(struct snd_seq_client *client, void __user * arg);
        { 0, NULL },
 };
 
+static long seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct snd_seq_client *client = file->private_data;
+       /* To use kernel stack for ioctl data. */
+       union ioctl_arg {
+               int pversion;
+               int client_id;
+               struct snd_seq_system_info      system_info;
+               struct snd_seq_running_info     running_info;
+               struct snd_seq_client_info      client_info;
+               struct snd_seq_port_info        port_info;
+               struct snd_seq_port_subscribe   port_subscribe;
+               struct snd_seq_queue_info       queue_info;
+               struct snd_seq_queue_status     queue_status;
+               struct snd_seq_queue_tempo      tempo;
+               struct snd_seq_queue_timer      queue_timer;
+               struct snd_seq_queue_client     queue_client;
+               struct snd_seq_client_pool      client_pool;
+               struct snd_seq_remove_events    remove_events;
+               struct snd_seq_query_subs       query_subs;
+       } buf = {0};
+       const struct ioctl_handler *handler;
+       unsigned long size;
+       int err;
+
+       if (snd_BUG_ON(!client))
+               return -ENXIO;
+
+       for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
+               if (handler->cmd == cmd)
+                       break;
+       }
+       if (handler->cmd == 0)
+               return -ENOTTY;
+       /*
+        * All of ioctl commands for ALSA sequencer get an argument of size
+        * within 13 bits. We can safely pick up the size from the command.
+        */
+       size = _IOC_SIZE(handler->cmd);
+       if (_IOC_DIR(handler->cmd) & IOC_IN) {
+               if (copy_from_user(&buf, (const void __user *)arg, size))
+                       return -EFAULT;
+       }
+
+       err = handler->func(client, &buf);
+       if (err >= 0) {
+               /* Some commands includes a bug in 'dir' field. */
+               if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT ||
+                   handler->cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_POOL ||
+                   (_IOC_DIR(handler->cmd) & IOC_OUT))
+                       if (copy_to_user((void __user *)arg, &buf, size))
+                               return -EFAULT;
+       }
+
+       return err;
+}
+
 static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd,
                            void __user *arg)
 {
 {
        struct snd_seq_client *client = file->private_data;
 
+       if (seq_ioctl(file, cmd, arg) >= 0)
+               return 0;
+
        if (snd_BUG_ON(!client))
                return -ENXIO;
-               
+
        return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
 }
 
  */
 int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
 {
+       const struct ioctl_handler *handler;
        struct snd_seq_client *client;
        mm_segment_t fs;
        int result;
        client = clientptr(clientid);
        if (client == NULL)
                return -ENXIO;
+
+       for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
+               if (handler->cmd == cmd)
+                       return handler->func(client, arg);
+       }
+
        fs = snd_enter_user();
        result = snd_seq_do_ioctl(client, cmd, (void __force __user *)arg);
        snd_leave_user(fs);
 
                goto error;
        data->kernel = NULL;
 
+       if (snd_seq_kernel_client_ctl(client->number, cmd, &data) >= 0)
+               return 0;
+
        fs = snd_enter_user();
        err = snd_seq_do_ioctl(client, cmd, data);
        snd_leave_user(fs);
        case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
        case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
        case SNDRV_SEQ_IOCTL_RUNNING_MODE:
+               if (seq_ioctl(file, cmd, arg) >= 0)
+                       return 0;
                return snd_seq_do_ioctl(client, cmd, argp);
        case SNDRV_SEQ_IOCTL_CREATE_PORT32:
                return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);