master/cdev.c
changeset 2030 2bd8ad8bf41f
parent 2029 5ef6507fc77a
child 2031 7a025a9e192d
--- a/master/cdev.c	Wed Jan 05 09:50:35 2011 +0100
+++ b/master/cdev.c	Wed Jan 05 11:33:31 2011 +0100
@@ -1072,7 +1072,8 @@
     ec_slave_t *slave;
     unsigned int byte_size;
     uint16_t *words;
-    ec_sii_write_request_t request;
+    ec_sii_write_request_t* request;
+    int retval;
 
     if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
         return -EFAULT;
@@ -1088,58 +1089,57 @@
         return -ENOMEM;
     }
 
+    request = kmalloc(sizeof(*request), GFP_KERNEL);
+    if (!request)
+        return -ENOMEM;
+    kref_init(&request->refcount);
+    // init SII write request
+    INIT_LIST_HEAD(&request->list);
+    request->words = words; // now "owned" by request, see ec_master_sii_write_request_release
+    request->offset = data.offset;
+    request->nwords = data.nwords;
+
     if (copy_from_user(words,
                 (void __user *) data.words, byte_size)) {
-        kfree(words);
-        return -EFAULT;
-    }
-
-    if (ec_mutex_lock_interruptible(&master->master_mutex))
-        return -EINTR;
-
+        kref_put(&request->refcount,ec_master_sii_write_request_release);
+        return -EFAULT;
+    }
+
+    if (ec_mutex_lock_interruptible(&master->master_mutex)) {
+        kref_put(&request->refcount,ec_master_sii_write_request_release);
+        return -EINTR;
+    }
     if (!(slave = ec_master_find_slave(
                     master, 0, data.slave_position))) {
         ec_mutex_unlock(&master->master_mutex);
         EC_MASTER_ERR(master, "Slave %u does not exist!\n",
                 data.slave_position);
-        kfree(words);
-        return -EINVAL;
-    }
-
-    // init SII write request
-    INIT_LIST_HEAD(&request.list);
-    request.slave = slave;
-    request.words = words;
-    request.offset = data.offset;
-    request.nwords = data.nwords;
-    request.state = EC_INT_REQUEST_QUEUED;
+        kref_put(&request->refcount,ec_master_sii_write_request_release);
+        return -EINVAL;
+    }
+
+    request->slave = slave;
+    request->state = EC_INT_REQUEST_QUEUED;
 
     // schedule SII write request.
-    list_add_tail(&request.list, &master->sii_requests);
+    list_add_tail(&request->list, &master->sii_requests);
+    kref_get(&request->refcount);
 
     ec_mutex_unlock(&master->master_mutex);
 
     // wait for processing through FSM
     if (wait_event_interruptible(master->sii_queue,
-                request.state != EC_INT_REQUEST_QUEUED)) {
-        // interrupted by signal
-        ec_mutex_lock(&master->master_mutex);
-        if (request.state == EC_INT_REQUEST_QUEUED) {
-            // abort request
-            list_del(&request.list);
-            ec_mutex_unlock(&master->master_mutex);
-            kfree(words);
-            return -EINTR;
-        }
-        ec_mutex_unlock(&master->master_mutex);
-    }
-
-    // wait until master FSM has finished processing
-    wait_event(master->sii_queue, request.state != EC_INT_REQUEST_BUSY);
-
-    kfree(words);
-
-    return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
+          ((request->state == EC_INT_REQUEST_SUCCESS) || (request->state == EC_INT_REQUEST_FAILURE)))) {
+           // interrupted by signal
+           kref_put(&request->refcount,ec_master_sii_write_request_release);
+           return -EINTR;
+    }
+
+
+    retval = request->state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO;
+    kref_put(&request->refcount,ec_master_sii_write_request_release);
+
+    return retval;
 }
 
 /*****************************************************************************/