]> err.no Git - linux-2.6/blobdiff - drivers/ieee1394/raw1394.c
ieee1394: raw1394: Fix read() for 32bit userland on 64bit kernel
[linux-2.6] / drivers / ieee1394 / raw1394.c
index bf71e069eaf5345cc39fe8b903ae66eb58074882..858fd9ba01430441ae82749184ea8d2e793255cd 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 #include <linux/cdev.h>
@@ -99,6 +98,21 @@ static struct hpsb_address_ops arm_ops = {
 
 static void queue_complete_cb(struct pending_request *req);
 
+#include <asm/current.h>
+static void print_old_iso_deprecation(void)
+{
+       static pid_t p;
+
+       if (p == current->pid)
+               return;
+       p = current->pid;
+       printk(KERN_WARNING "raw1394: WARNING - Program \"%s\" uses unsupported"
+              " isochronous request types which will be removed in a next"
+              " kernel release\n", current->comm);
+       printk(KERN_WARNING "raw1394: Update your software to use libraw1394's"
+              " newer interface\n");
+}
+
 static struct pending_request *__alloc_pending_request(gfp_t flags)
 {
        struct pending_request *req;
@@ -445,7 +459,7 @@ static const char __user *raw1394_compat_write(const char __user *buf)
 static int
 raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
 {
-       struct compat_raw1394_req __user *cr = (typeof(cr)) r;
+       struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
        if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) ||
            P(type) ||
            P(error) ||
@@ -621,27 +635,32 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
 
        case RAW1394_REQ_SET_CARD:
                spin_lock_irqsave(&host_info_lock, flags);
-               if (req->req.misc < host_count) {
-                       list_for_each_entry(hi, &host_info_list, list) {
-                               if (!req->req.misc--)
-                                       break;
-                       }
-                       get_device(&hi->host->device);  // XXX Need to handle failure case
-                       list_add_tail(&fi->list, &hi->file_info_list);
-                       fi->host = hi->host;
-                       fi->state = connected;
-
-                       req->req.error = RAW1394_ERROR_NONE;
-                       req->req.generation = get_hpsb_generation(fi->host);
-                       req->req.misc = (fi->host->node_id << 16)
-                           | fi->host->node_count;
-                       if (fi->protocol_version > 3) {
-                               req->req.misc |=
-                                   NODEID_TO_NODE(fi->host->irm_id) << 8;
-                       }
-               } else {
+               if (req->req.misc >= host_count) {
                        req->req.error = RAW1394_ERROR_INVALID_ARG;
+                       goto out_set_card;
                }
+               list_for_each_entry(hi, &host_info_list, list)
+                       if (!req->req.misc--)
+                               break;
+               get_device(&hi->host->device); /* FIXME handle failure case */
+               list_add_tail(&fi->list, &hi->file_info_list);
+
+               /* prevent unloading of the host's low-level driver */
+               if (!try_module_get(hi->host->driver->owner)) {
+                       req->req.error = RAW1394_ERROR_ABORTED;
+                       goto out_set_card;
+               }
+               WARN_ON(fi->host);
+               fi->host = hi->host;
+               fi->state = connected;
+
+               req->req.error = RAW1394_ERROR_NONE;
+               req->req.generation = get_hpsb_generation(fi->host);
+               req->req.misc = (fi->host->node_id << 16)
+                               | fi->host->node_count;
+               if (fi->protocol_version > 3)
+                       req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
+out_set_card:
                spin_unlock_irqrestore(&host_info_lock, flags);
 
                req->req.length = 0;
@@ -917,15 +936,18 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
        struct hpsb_packet *packet;
        int header_length = req->req.misc & 0xffff;
        int expect_response = req->req.misc >> 16;
+       size_t data_size;
 
-       if ((header_length > req->req.length) || (header_length < 12)) {
+       if (header_length > req->req.length || header_length < 12 ||
+           header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
                req->req.error = RAW1394_ERROR_INVALID_ARG;
                req->req.length = 0;
                queue_complete_req(req);
                return sizeof(struct raw1394_request);
        }
 
-       packet = hpsb_alloc_packet(req->req.length - header_length);
+       data_size = req->req.length - header_length;
+       packet = hpsb_alloc_packet(data_size);
        req->packet = packet;
        if (!packet)
                return -ENOMEM;
@@ -940,7 +962,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
 
        if (copy_from_user
            (packet->data, int2ptr(req->req.sendb) + header_length,
-            packet->data_size)) {
+            data_size)) {
                req->req.error = RAW1394_ERROR_MEMFAULT;
                req->req.length = 0;
                queue_complete_req(req);
@@ -954,7 +976,7 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
        packet->host = fi->host;
        packet->expect_response = expect_response;
        packet->header_size = header_length;
-       packet->data_size = req->req.length - header_length;
+       packet->data_size = data_size;
 
        req->req.length = 0;
        hpsb_set_packet_complete_task(packet,
@@ -2292,6 +2314,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
                return sizeof(struct raw1394_request);
 
        case RAW1394_REQ_ISO_SEND:
+               print_old_iso_deprecation();
                return handle_iso_send(fi, req, node);
 
        case RAW1394_REQ_ARM_REGISTER:
@@ -2310,6 +2333,7 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
                return reset_notification(fi, req);
 
        case RAW1394_REQ_ISO_LISTEN:
+               print_old_iso_deprecation();
                handle_iso_listen(fi, req);
                return sizeof(struct raw1394_request);
 
@@ -2647,6 +2671,18 @@ static void raw1394_iso_shutdown(struct file_info *fi)
        fi->iso_state = RAW1394_ISO_INACTIVE;
 }
 
+static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
+{
+       struct raw1394_cycle_timer ct;
+       int err;
+
+       err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
+       if (!err)
+               if (copy_to_user(uaddr, &ct, sizeof(ct)))
+                       err = -EFAULT;
+       return err;
+}
+
 /* mmap the rawiso xmit/recv buffer */
 static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
@@ -2755,6 +2791,14 @@ static int raw1394_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
+       /* state-independent commands */
+       switch(cmd) {
+       case RAW1394_IOC_GET_CYCLE_TIMER:
+               return raw1394_read_cycle_timer(fi, argp);
+       default:
+               break;
+       }
+
        return -EINVAL;
 }
 
@@ -2938,6 +2982,11 @@ static int raw1394_release(struct inode *inode, struct file *file)
                put_device(&fi->host->device);
        }
 
+       spin_lock_irqsave(&host_info_lock, flags);
+       if (fi->host)
+               module_put(fi->host->driver->owner);
+       spin_unlock_irqrestore(&host_info_lock, flags);
+
        kfree(fi);
 
        return 0;
@@ -2970,12 +3019,8 @@ static struct ieee1394_device_id raw1394_id_table[] = {
 MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
 
 static struct hpsb_protocol_driver raw1394_driver = {
-       .name = "raw1394 Driver",
+       .name = "raw1394",
        .id_table = raw1394_id_table,
-       .driver = {
-                  .name = "raw1394",
-                  .bus = &ieee1394_bus_type,
-                  },
 };
 
 /******************************************************************************/
@@ -2990,7 +3035,7 @@ static struct hpsb_highlevel raw1394_highlevel = {
 };
 
 static struct cdev raw1394_cdev;
-static struct file_operations raw1394_fops = {
+static const struct file_operations raw1394_fops = {
        .owner = THIS_MODULE,
        .read = raw1394_read,
        .write = raw1394_write,