ieee1394: sbp2: another iPod mini quirk entry
[safe/jmp/linux-2.6] / drivers / ieee1394 / raw1394.c
index 37e7e10..bf7e761 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
@@ -2267,6 +2268,9 @@ static ssize_t raw1394_write(struct file *file, const char __user * buffer,
                return -EFAULT;
        }
 
+       if (!mutex_trylock(&fi->state_mutex))
+               return -EAGAIN;
+
        switch (fi->state) {
        case opened:
                retval = state_opened(fi, req);
@@ -2281,6 +2285,8 @@ static ssize_t raw1394_write(struct file *file, const char __user * buffer,
                break;
        }
 
+       mutex_unlock(&fi->state_mutex);
+
        if (retval < 0) {
                free_pending_request(req);
        } else {
@@ -2356,13 +2362,16 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
 static void raw1394_iso_fill_status(struct hpsb_iso *iso,
                                    struct raw1394_iso_status *stat)
 {
+       int overflows = atomic_read(&iso->overflows);
+       int skips = atomic_read(&iso->skips);
+
        stat->config.data_buf_size = iso->buf_size;
        stat->config.buf_packets = iso->buf_packets;
        stat->config.channel = iso->channel;
        stat->config.speed = iso->speed;
        stat->config.irq_interval = iso->irq_interval;
        stat->n_packets = hpsb_iso_n_ready(iso);
-       stat->overflows = atomic_read(&iso->overflows);
+       stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF));
        stat->xmit_cycle = iso->xmit_cycle;
 }
 
@@ -2437,6 +2446,8 @@ static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
 
        /* reset overflow counter */
        atomic_set(&iso->overflows, 0);
+       /* reset skip counter */
+       atomic_set(&iso->skips, 0);
 
        return 0;
 }
@@ -2536,119 +2547,151 @@ static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
 static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct file_info *fi = file->private_data;
+       int ret;
+
+       if (!mutex_trylock(&fi->state_mutex))
+               return -EAGAIN;
 
        if (fi->iso_state == RAW1394_ISO_INACTIVE)
+               ret = -EINVAL;
+       else
+               ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
+
+       mutex_unlock(&fi->state_mutex);
+
+       return ret;
+}
+
+static long raw1394_ioctl_inactive(struct file_info *fi, unsigned int cmd,
+                                  void __user *argp)
+{
+       switch (cmd) {
+       case RAW1394_IOC_ISO_XMIT_INIT:
+               return raw1394_iso_xmit_init(fi, argp);
+       case RAW1394_IOC_ISO_RECV_INIT:
+               return raw1394_iso_recv_init(fi, argp);
+       default:
                return -EINVAL;
+       }
+}
 
-       return dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
+static long raw1394_ioctl_recv(struct file_info *fi, unsigned int cmd,
+                              unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+
+       switch (cmd) {
+       case RAW1394_IOC_ISO_RECV_START:{
+                       int args[3];
+
+                       if (copy_from_user(&args[0], argp, sizeof(args)))
+                               return -EFAULT;
+                       return hpsb_iso_recv_start(fi->iso_handle,
+                                                  args[0], args[1], args[2]);
+               }
+       case RAW1394_IOC_ISO_XMIT_RECV_STOP:
+               hpsb_iso_stop(fi->iso_handle);
+               return 0;
+       case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
+               return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
+       case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
+               return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
+       case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
+                       u64 mask;
+
+                       if (copy_from_user(&mask, argp, sizeof(mask)))
+                               return -EFAULT;
+                       return hpsb_iso_recv_set_channel_mask(fi->iso_handle,
+                                                             mask);
+               }
+       case RAW1394_IOC_ISO_GET_STATUS:
+               return raw1394_iso_get_status(fi, argp);
+       case RAW1394_IOC_ISO_RECV_PACKETS:
+               return raw1394_iso_recv_packets(fi, argp);
+       case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
+               return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
+       case RAW1394_IOC_ISO_RECV_FLUSH:
+               return hpsb_iso_recv_flush(fi->iso_handle);
+       case RAW1394_IOC_ISO_SHUTDOWN:
+               raw1394_iso_shutdown(fi);
+               return 0;
+       case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
+               queue_rawiso_event(fi);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static long raw1394_ioctl_xmit(struct file_info *fi, unsigned int cmd,
+                              void __user *argp)
+{
+       switch (cmd) {
+       case RAW1394_IOC_ISO_XMIT_START:{
+                       int args[2];
+
+                       if (copy_from_user(&args[0], argp, sizeof(args)))
+                               return -EFAULT;
+                       return hpsb_iso_xmit_start(fi->iso_handle,
+                                                  args[0], args[1]);
+               }
+       case RAW1394_IOC_ISO_XMIT_SYNC:
+               return hpsb_iso_xmit_sync(fi->iso_handle);
+       case RAW1394_IOC_ISO_XMIT_RECV_STOP:
+               hpsb_iso_stop(fi->iso_handle);
+               return 0;
+       case RAW1394_IOC_ISO_GET_STATUS:
+               return raw1394_iso_get_status(fi, argp);
+       case RAW1394_IOC_ISO_XMIT_PACKETS:
+               return raw1394_iso_send_packets(fi, argp);
+       case RAW1394_IOC_ISO_SHUTDOWN:
+               raw1394_iso_shutdown(fi);
+               return 0;
+       case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
+               queue_rawiso_event(fi);
+               return 0;
+       default:
+               return -EINVAL;
+       }
 }
 
 /* ioctl is only used for rawiso operations */
-static int raw1394_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg)
+static long raw1394_ioctl(struct file *file, unsigned int cmd,
+                         unsigned long arg)
 {
        struct file_info *fi = file->private_data;
        void __user *argp = (void __user *)arg;
+       long ret;
+
+       /* state-independent commands */
+       switch(cmd) {
+       case RAW1394_IOC_GET_CYCLE_TIMER:
+               return raw1394_read_cycle_timer(fi, argp);
+       default:
+               break;
+       }
+
+       if (!mutex_trylock(&fi->state_mutex))
+               return -EAGAIN;
 
        switch (fi->iso_state) {
        case RAW1394_ISO_INACTIVE:
-               switch (cmd) {
-               case RAW1394_IOC_ISO_XMIT_INIT:
-                       return raw1394_iso_xmit_init(fi, argp);
-               case RAW1394_IOC_ISO_RECV_INIT:
-                       return raw1394_iso_recv_init(fi, argp);
-               default:
-                       break;
-               }
+               ret = raw1394_ioctl_inactive(fi, cmd, argp);
                break;
        case RAW1394_ISO_RECV:
-               switch (cmd) {
-               case RAW1394_IOC_ISO_RECV_START:{
-                               /* copy args from user-space */
-                               int args[3];
-                               if (copy_from_user
-                                   (&args[0], argp, sizeof(args)))
-                                       return -EFAULT;
-                               return hpsb_iso_recv_start(fi->iso_handle,
-                                                          args[0], args[1],
-                                                          args[2]);
-                       }
-               case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-                       hpsb_iso_stop(fi->iso_handle);
-                       return 0;
-               case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
-                       return hpsb_iso_recv_listen_channel(fi->iso_handle,
-                                                           arg);
-               case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
-                       return hpsb_iso_recv_unlisten_channel(fi->iso_handle,
-                                                             arg);
-               case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
-                               /* copy the u64 from user-space */
-                               u64 mask;
-                               if (copy_from_user(&mask, argp, sizeof(mask)))
-                                       return -EFAULT;
-                               return hpsb_iso_recv_set_channel_mask(fi->
-                                                                     iso_handle,
-                                                                     mask);
-                       }
-               case RAW1394_IOC_ISO_GET_STATUS:
-                       return raw1394_iso_get_status(fi, argp);
-               case RAW1394_IOC_ISO_RECV_PACKETS:
-                       return raw1394_iso_recv_packets(fi, argp);
-               case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
-                       return hpsb_iso_recv_release_packets(fi->iso_handle,
-                                                            arg);
-               case RAW1394_IOC_ISO_RECV_FLUSH:
-                       return hpsb_iso_recv_flush(fi->iso_handle);
-               case RAW1394_IOC_ISO_SHUTDOWN:
-                       raw1394_iso_shutdown(fi);
-                       return 0;
-               case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-                       queue_rawiso_event(fi);
-                       return 0;
-               }
+               ret = raw1394_ioctl_recv(fi, cmd, arg);
                break;
        case RAW1394_ISO_XMIT:
-               switch (cmd) {
-               case RAW1394_IOC_ISO_XMIT_START:{
-                               /* copy two ints from user-space */
-                               int args[2];
-                               if (copy_from_user
-                                   (&args[0], argp, sizeof(args)))
-                                       return -EFAULT;
-                               return hpsb_iso_xmit_start(fi->iso_handle,
-                                                          args[0], args[1]);
-                       }
-               case RAW1394_IOC_ISO_XMIT_SYNC:
-                       return hpsb_iso_xmit_sync(fi->iso_handle);
-               case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-                       hpsb_iso_stop(fi->iso_handle);
-                       return 0;
-               case RAW1394_IOC_ISO_GET_STATUS:
-                       return raw1394_iso_get_status(fi, argp);
-               case RAW1394_IOC_ISO_XMIT_PACKETS:
-                       return raw1394_iso_send_packets(fi, argp);
-               case RAW1394_IOC_ISO_SHUTDOWN:
-                       raw1394_iso_shutdown(fi);
-                       return 0;
-               case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-                       queue_rawiso_event(fi);
-                       return 0;
-               }
+               ret = raw1394_ioctl_xmit(fi, cmd, argp);
                break;
        default:
+               ret = -EINVAL;
                break;
        }
 
-       /* state-independent commands */
-       switch(cmd) {
-       case RAW1394_IOC_GET_CYCLE_TIMER:
-               return raw1394_read_cycle_timer(fi, argp);
-       default:
-               break;
-       }
+       mutex_unlock(&fi->state_mutex);
 
-       return -EINVAL;
+       return ret;
 }
 
 #ifdef CONFIG_COMPAT
@@ -2685,7 +2728,7 @@ static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
            !copy_from_user(&infos32, &arg->infos, sizeof infos32)) {
                infos = compat_ptr(infos32);
                if (!copy_to_user(&dst->infos, &infos, sizeof infos))
-                       err = raw1394_ioctl(NULL, file, cmd, (unsigned long)dst);
+                       err = raw1394_ioctl(file, cmd, (unsigned long)dst);
        }
        return err;
 }
@@ -2709,7 +2752,6 @@ static long raw1394_compat_ioctl(struct file *file,
        void __user *argp = (void __user *)arg;
        long err;
 
-       lock_kernel();
        switch (cmd) {
        /* These requests have same format as long as 'int' has same size. */
        case RAW1394_IOC_ISO_RECV_INIT:
@@ -2726,7 +2768,7 @@ static long raw1394_compat_ioctl(struct file *file,
        case RAW1394_IOC_ISO_GET_STATUS:
        case RAW1394_IOC_ISO_SHUTDOWN:
        case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-               err = raw1394_ioctl(NULL, file, cmd, arg);
+               err = raw1394_ioctl(file, cmd, arg);
                break;
        /* These request have different format. */
        case RAW1394_IOC_ISO_RECV_PACKETS32:
@@ -2742,7 +2784,6 @@ static long raw1394_compat_ioctl(struct file *file,
                err = -EINVAL;
                break;
        }
-       unlock_kernel();
 
        return err;
 }
@@ -2776,6 +2817,7 @@ static int raw1394_open(struct inode *inode, struct file *file)
        fi->notification = (u8) RAW1394_NOTIFY_ON;      /* busreset notification */
 
        INIT_LIST_HEAD(&fi->list);
+       mutex_init(&fi->state_mutex);
        fi->state = opened;
        INIT_LIST_HEAD(&fi->req_pending);
        INIT_LIST_HEAD(&fi->req_complete);
@@ -2935,6 +2977,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
 /*
  * Export information about protocols/devices supported by this driver.
  */
+#ifdef MODULE
 static struct ieee1394_device_id raw1394_id_table[] = {
        {
         .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
@@ -2956,10 +2999,10 @@ static struct ieee1394_device_id raw1394_id_table[] = {
 };
 
 MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
+#endif /* MODULE */
 
 static struct hpsb_protocol_driver raw1394_driver = {
        .name = "raw1394",
-       .id_table = raw1394_id_table,
 };
 
 /******************************************************************************/
@@ -2978,7 +3021,7 @@ static const struct file_operations raw1394_fops = {
        .read = raw1394_read,
        .write = raw1394_write,
        .mmap = raw1394_mmap,
-       .ioctl = raw1394_ioctl,
+       .unlocked_ioctl = raw1394_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = raw1394_compat_ioctl,
 #endif
@@ -2994,17 +3037,16 @@ static int __init init_raw1394(void)
        hpsb_register_highlevel(&raw1394_highlevel);
 
        if (IS_ERR
-           (device_create(
-             hpsb_protocol_class, NULL,
-             MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
-             RAW1394_DEVICE_NAME))) {
+           (device_create(hpsb_protocol_class, NULL,
+                          MKDEV(IEEE1394_MAJOR,
+                                IEEE1394_MINOR_BLOCK_RAW1394 * 16),
+                          NULL, RAW1394_DEVICE_NAME))) {
                ret = -EFAULT;
                goto out_unreg;
        }
 
        cdev_init(&raw1394_cdev, &raw1394_fops);
        raw1394_cdev.owner = THIS_MODULE;
-       kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
        ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
        if (ret) {
                HPSB_ERR("raw1394 failed to register minor device block");