--- 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;
}
/*****************************************************************************/