diff -r 19732da2cf86 -r 3001f6523e63 master/cdev.c --- a/master/cdev.c Fri May 13 15:33:16 2011 +0200 +++ b/master/cdev.c Fri May 13 15:34:20 2011 +0200 @@ -186,7 +186,7 @@ ec_ioctl_master_t data; unsigned int i; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; data.slave_count = master->slave_count; data.config_count = ec_master_config_count(master); @@ -197,9 +197,9 @@ data.phase = (uint8_t) master->phase; data.active = (uint8_t) master->active; data.scan_busy = master->scan_busy; - up(&master->master_sem); - - if (down_interruptible(&master->device_sem)) + ec_mutex_unlock(&master->master_mutex); + + if (ec_mutex_lock_interruptible(&master->device_mutex)) return -EINTR; if (master->main_device.dev) { @@ -242,7 +242,7 @@ data.devices[1].loss_rates[i] = master->backup_device.loss_rates[i]; } - up(&master->device_sem); + ec_mutex_unlock(&master->device_mutex); data.app_time = master->app_time; data.ref_clock = @@ -271,12 +271,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.position); return -EINVAL; } @@ -330,7 +330,7 @@ ec_cdev_strcpy(data.order, slave->sii.order); ec_cdev_strcpy(data.name, slave->sii.name); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -355,19 +355,19 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; } if (data.sync_index >= slave->sii.sync_count) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", data.sync_index); return -EINVAL; @@ -381,7 +381,7 @@ data.enable = sync->enable; data.pdo_count = ec_pdo_list_count(&sync->pdos); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -407,19 +407,19 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; } if (data.sync_index >= slave->sii.sync_count) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", data.sync_index); return -EINVAL; @@ -428,7 +428,7 @@ sync = &slave->sii.syncs[data.sync_index]; if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( &sync->pdos, data.pdo_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with " "position %u!\n", data.sync_index, data.pdo_pos); return -EINVAL; @@ -438,7 +438,7 @@ data.entry_count = ec_pdo_entry_count(pdo); ec_cdev_strcpy(data.name, pdo->name); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -465,19 +465,19 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; } if (data.sync_index >= slave->sii.sync_count) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "Sync manager %u does not exist!\n", data.sync_index); return -EINVAL; @@ -486,7 +486,7 @@ sync = &slave->sii.syncs[data.sync_index]; if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( &sync->pdos, data.pdo_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "Sync manager %u does not contain a PDO with " "position %u!\n", data.sync_index, data.pdo_pos); return -EINVAL; @@ -494,7 +494,7 @@ if (!(entry = ec_pdo_find_entry_by_pos_const( pdo, data.entry_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "PDO 0x%04X does not contain an entry with " "position %u!\n", data.pdo_pos, data.entry_pos); return -EINVAL; @@ -505,7 +505,7 @@ data.bit_length = entry->bit_length; ec_cdev_strcpy(data.name, entry->name); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -529,22 +529,23 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(domain = ec_master_find_domain_const(master, data.index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Domain %u does not exist!\n", data.index); return -EINVAL; } data.data_size = domain->data_size; + data.tx_size = domain->tx_size; data.logical_base_address = domain->logical_base_address; data.working_counter = domain->working_counter; data.expected_working_counter = domain->expected_working_counter; data.fmmu_count = ec_domain_fmmu_count(domain); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -569,18 +570,18 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Domain %u does not exist!\n", data.domain_index); return -EINVAL; } if (!(fmmu = ec_domain_find_fmmu(domain, data.fmmu_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Domain %u has less than %u" " fmmu configurations.\n", data.domain_index, data.fmmu_index + 1); @@ -592,9 +593,10 @@ data.sync_index = fmmu->sync_index; data.dir = fmmu->dir; data.logical_address = fmmu->logical_start_address; + data.domain_address = fmmu->domain_address; data.data_size = fmmu->data_size; - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -618,18 +620,18 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Domain %u does not exist!\n", data.domain_index); return -EINVAL; } if (domain->data_size != data.data_size) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Data size mismatch %u/%zu!\n", data.data_size, domain->data_size); return -EFAULT; @@ -637,11 +639,11 @@ if (copy_to_user((void __user *) data.target, domain->data, domain->data_size)) { - up(&master->master_sem); - return -EFAULT; - } - - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); + return -EFAULT; + } + + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -686,12 +688,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; @@ -699,7 +701,7 @@ ec_slave_request_state(slave, data.al_state); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -720,12 +722,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; @@ -733,7 +735,7 @@ if (!(sdo = ec_slave_get_sdo_by_pos_const( slave, data.sdo_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", data.sdo_position); return -EINVAL; } @@ -742,7 +744,7 @@ data.max_subindex = sdo->max_subindex; ec_cdev_strcpy(data.name, sdo->name); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -768,12 +770,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; @@ -782,14 +784,14 @@ if (data.sdo_spec <= 0) { if (!(sdo = ec_slave_get_sdo_by_pos_const( slave, -data.sdo_spec))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "SDO %u does not exist!\n", -data.sdo_spec); return -EINVAL; } } else { if (!(sdo = ec_slave_get_sdo_const( slave, data.sdo_spec))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "SDO 0x%04X does not exist!\n", data.sdo_spec); return -EINVAL; @@ -798,7 +800,7 @@ if (!(entry = ec_sdo_get_entry_const( sdo, data.sdo_entry_subindex))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "SDO entry 0x%04X:%02X does not exist!\n", sdo->index, data.sdo_entry_subindex); return -EINVAL; @@ -820,7 +822,7 @@ entry->write_access[EC_SDO_ENTRY_ACCESS_OP]; ec_cdev_strcpy(data.description, entry->description); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -838,78 +840,74 @@ ) { ec_ioctl_slave_sdo_upload_t data; - ec_master_sdo_request_t request; + ec_master_sdo_request_t* request; int retval; if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { return -EFAULT; } - ec_sdo_request_init(&request.req); - ec_sdo_request_address(&request.req, - data.sdo_index, data.sdo_entry_subindex); - ecrt_sdo_request_read(&request.req); - - if (down_interruptible(&master->master_sem)) - return -EINTR; - - if (!(request.slave = ec_master_find_slave( + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + kref_init(&request->refcount); + + ec_sdo_request_init(&request->req); + ec_sdo_request_address(&request->req, + data.sdo_index, data.sdo_entry_subindex); + ecrt_sdo_request_read(&request->req); + + if (ec_mutex_lock_interruptible(&master->master_mutex)) { + kref_put(&request->refcount,ec_master_sdo_request_release); + return -EINTR; + } + if (!(request->slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); - ec_sdo_request_clear(&request.req); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); - return -EINVAL; - } - - EC_SLAVE_DBG(request.slave, 1, "Schedule SDO upload request.\n"); + kref_put(&request->refcount,ec_master_sdo_request_release); + return -EINVAL; + } + + EC_SLAVE_DBG(request->slave, 1, "Schedule SDO upload request %p.\n",request); // schedule request. - list_add_tail(&request.list, &request.slave->slave_sdo_requests); - - up(&master->master_sem); + kref_get(&request->refcount); + list_add_tail(&request->list, &request->slave->slave_sdo_requests); + + ec_mutex_unlock(&master->master_mutex); // wait for processing through FSM - if (wait_event_interruptible(request.slave->sdo_queue, - request.req.state != EC_INT_REQUEST_QUEUED)) { + if (wait_event_interruptible(request->slave->sdo_queue, + ((request->req.state == EC_INT_REQUEST_SUCCESS) || (request->req.state == EC_INT_REQUEST_FAILURE)))) { // interrupted by signal - down(&master->master_sem); - if (request.req.state == EC_INT_REQUEST_QUEUED) { - list_del(&request.list); - up(&master->master_sem); - ec_sdo_request_clear(&request.req); - return -EINTR; - } - // request already processing: interrupt not possible. - up(&master->master_sem); - } - - // wait until master FSM has finished processing - wait_event(request.slave->sdo_queue, - request.req.state != EC_INT_REQUEST_BUSY); - - EC_SLAVE_DBG(request.slave, 1, "Finished SDO upload request.\n"); - - data.abort_code = request.req.abort_code; - - if (request.req.state != EC_INT_REQUEST_SUCCESS) { + kref_put(&request->refcount,ec_master_sdo_request_release); + return -EINTR; + } + + EC_SLAVE_DBG(request->slave, 1, "Finished SDO upload request %p.\n",request); + + data.abort_code = request->req.abort_code; + + if (request->req.state != EC_INT_REQUEST_SUCCESS) { data.data_size = 0; - if (request.req.errno) { - retval = -request.req.errno; + if (request->req.errno) { + retval = -request->req.errno; } else { retval = -EIO; } } else { - if (request.req.data_size > data.target_size) { + if (request->req.data_size > data.target_size) { EC_MASTER_ERR(master, "Buffer too small.\n"); - ec_sdo_request_clear(&request.req); + kref_put(&request->refcount,ec_master_sdo_request_release); return -EOVERFLOW; } - data.data_size = request.req.data_size; + data.data_size = request->req.data_size; if (copy_to_user((void __user *) data.target, - request.req.data, data.data_size)) { - ec_sdo_request_clear(&request.req); + request->req.data, data.data_size)) { + kref_put(&request->refcount,ec_master_sdo_request_release); return -EFAULT; } retval = 0; @@ -919,7 +917,7 @@ retval = -EFAULT; } - ec_sdo_request_clear(&request.req); + kref_put(&request->refcount,ec_master_sdo_request_release); return retval; } @@ -933,7 +931,7 @@ ) { ec_ioctl_slave_sdo_download_t data; - ec_master_sdo_request_t request; + ec_master_sdo_request_t* request; int retval; if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { @@ -946,67 +944,63 @@ return -EINVAL; } - ec_sdo_request_init(&request.req); - ec_sdo_request_address(&request.req, + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + kref_init(&request->refcount); + + ec_sdo_request_init(&request->req); + ec_sdo_request_address(&request->req, data.sdo_index, data.sdo_entry_subindex); - if (ec_sdo_request_alloc(&request.req, data.data_size)) { - ec_sdo_request_clear(&request.req); + if (ec_sdo_request_alloc(&request->req, data.data_size)) { + kref_put(&request->refcount,ec_master_sdo_request_release); return -ENOMEM; } - if (copy_from_user(request.req.data, + if (copy_from_user(request->req.data, (void __user *) data.data, data.data_size)) { - ec_sdo_request_clear(&request.req); - return -EFAULT; - } - request.req.data_size = data.data_size; - ecrt_sdo_request_write(&request.req); - - if (down_interruptible(&master->master_sem)) - return -EINTR; - - if (!(request.slave = ec_master_find_slave( + kref_put(&request->refcount,ec_master_sdo_request_release); + return -EFAULT; + } + request->req.data_size = data.data_size; + ecrt_sdo_request_write(&request->req); + + if (ec_mutex_lock_interruptible(&master->master_mutex)) { + kref_put(&request->refcount,ec_master_sdo_request_release); + return -EINTR; + } + if (!(request->slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); - ec_sdo_request_clear(&request.req); + kref_put(&request->refcount,ec_master_sdo_request_release); return -EINVAL; } - EC_SLAVE_DBG(request.slave, 1, "Schedule SDO download request.\n"); + EC_SLAVE_DBG(request->slave, 1, "Schedule SDO download request %p.\n",request); // schedule request. - list_add_tail(&request.list, &request.slave->slave_sdo_requests); - - up(&master->master_sem); + kref_get(&request->refcount); + list_add_tail(&request->list, &request->slave->slave_sdo_requests); + + ec_mutex_unlock(&master->master_mutex); // wait for processing through FSM - if (wait_event_interruptible(request.slave->sdo_queue, - request.req.state != EC_INT_REQUEST_QUEUED)) { + if (wait_event_interruptible(request->slave->sdo_queue, + ((request->req.state == EC_INT_REQUEST_SUCCESS) || (request->req.state == EC_INT_REQUEST_FAILURE)))) { // interrupted by signal - down(&master->master_sem); - if (request.req.state == EC_INT_REQUEST_QUEUED) { - list_del(&request.list); - up(&master->master_sem); - ec_sdo_request_clear(&request.req); - return -EINTR; - } - // request already processing: interrupt not possible. - up(&master->master_sem); - } - - // wait until master FSM has finished processing - wait_event(request.slave->sdo_queue, - request.req.state != EC_INT_REQUEST_BUSY); - - EC_SLAVE_DBG(request.slave, 1, "Finished SDO download request.\n"); - - data.abort_code = request.req.abort_code; - - if (request.req.state == EC_INT_REQUEST_SUCCESS) { + kref_put(&request->refcount,ec_master_sdo_request_release); + return -EINTR; + } + + EC_SLAVE_DBG(request->slave, 1, "Finished SDO download request %p.\n",request); + + data.abort_code = request->req.abort_code; + + if (request->req.state == EC_INT_REQUEST_SUCCESS) { retval = 0; - } else if (request.req.errno) { - retval = -request.req.errno; + } else if (request->req.errno) { + retval = -request->req.errno; } else { retval = -EIO; } @@ -1015,7 +1009,7 @@ retval = -EFAULT; } - ec_sdo_request_clear(&request.req); + kref_put(&request->refcount,ec_master_sdo_request_release); return retval; } @@ -1036,12 +1030,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(slave = ec_master_find_slave_const( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; @@ -1049,7 +1043,7 @@ if (!data.nwords || data.offset + data.nwords > slave->sii_nwords) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_SLAVE_ERR(slave, "Invalid SII read offset/size %u/%u for slave SII" " size %zu!\n", data.offset, data.nwords, slave->sii_nwords); return -EINVAL; @@ -1061,7 +1055,7 @@ else retval = 0; - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return retval; } @@ -1078,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; @@ -1094,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 (down_interruptible(&master->master_sem)) - 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))) { - up(&master->master_sem); + 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); - - up(&master->master_sem); + 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 - down(&master->master_sem); - if (request.state == EC_INT_REQUEST_QUEUED) { - // abort request - list_del(&request.list); - up(&master->master_sem); - kfree(words); - return -EINTR; - } - up(&master->master_sem); - } - - // 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; } /*****************************************************************************/ @@ -1160,7 +1154,8 @@ ec_ioctl_slave_reg_t data; ec_slave_t *slave; uint8_t *contents; - ec_reg_request_t request; + ec_reg_request_t* request; + int retval; if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { return -EFAULT; @@ -1175,56 +1170,58 @@ return -ENOMEM; } - if (down_interruptible(&master->master_sem)) - return -EINTR; - + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + kref_init(&request->refcount); + + // init register request + INIT_LIST_HEAD(&request->list); + request->dir = EC_DIR_INPUT; + request->data = contents; // now "owned" by request, see ec_master_reg_request_release + request->offset = data.offset; + request->length = data.length; + + if (ec_mutex_lock_interruptible(&master->master_mutex)) { + kref_put(&request->refcount,ec_master_reg_request_release); + return -EINTR; + } if (!(slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); - return -EINVAL; - } - - // init register request - INIT_LIST_HEAD(&request.list); - request.slave = slave; - request.dir = EC_DIR_INPUT; - request.data = contents; - request.offset = data.offset; - request.length = data.length; - request.state = EC_INT_REQUEST_QUEUED; + kref_put(&request->refcount,ec_master_reg_request_release); + return -EINVAL; + } + + request->slave = slave; + request->state = EC_INT_REQUEST_QUEUED; // schedule request. - list_add_tail(&request.list, &master->reg_requests); - - up(&master->master_sem); + list_add_tail(&request->list, &master->reg_requests); + kref_get(&request->refcount); + + ec_mutex_unlock(&master->master_mutex); // wait for processing through FSM if (wait_event_interruptible(master->reg_queue, - request.state != EC_INT_REQUEST_QUEUED)) { - // interrupted by signal - down(&master->master_sem); - if (request.state == EC_INT_REQUEST_QUEUED) { - // abort request - list_del(&request.list); - up(&master->master_sem); - kfree(contents); - return -EINTR; + ((request->state == EC_INT_REQUEST_SUCCESS) || (request->state == EC_INT_REQUEST_FAILURE)))) { + // interrupted by signal + kref_put(&request->refcount,ec_master_reg_request_release); + return -EINTR; + } + + if (request->state == EC_INT_REQUEST_SUCCESS) { + if (copy_to_user((void __user *) data.data, request->data, data.length)) { + kref_put(&request->refcount,ec_master_reg_request_release); + return -EFAULT; } - up(&master->master_sem); - } - - // wait until master FSM has finished processing - wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY); - - if (request.state == EC_INT_REQUEST_SUCCESS) { - if (copy_to_user((void __user *) data.data, contents, data.length)) - return -EFAULT; - } - kfree(contents); - - return request.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; + } + retval = request->state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; + + kref_put(&request->refcount,ec_master_reg_request_release); + return retval; } /*****************************************************************************/ @@ -1239,7 +1236,8 @@ ec_ioctl_slave_reg_t data; ec_slave_t *slave; uint8_t *contents; - ec_reg_request_t request; + ec_reg_request_t* request; + int retval; if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { return -EFAULT; @@ -1259,53 +1257,52 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) - return -EINTR; + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + kref_init(&request->refcount); + // init register request + INIT_LIST_HEAD(&request->list); + request->dir = EC_DIR_OUTPUT; + request->data = contents; // now "owned" by request, see ec_master_reg_request_release + request->offset = data.offset; + request->length = data.length; + + if (ec_mutex_lock_interruptible(&master->master_mutex)) { + kref_put(&request->refcount,ec_master_reg_request_release); + return -EINTR; + } if (!(slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); - kfree(contents); - return -EINVAL; - } - - // init register request - INIT_LIST_HEAD(&request.list); - request.slave = slave; - request.dir = EC_DIR_OUTPUT; - request.data = contents; - request.offset = data.offset; - request.length = data.length; - request.state = EC_INT_REQUEST_QUEUED; + kref_put(&request->refcount,ec_master_reg_request_release); + return -EINVAL; + } + + request->slave = slave; + request->state = EC_INT_REQUEST_QUEUED; // schedule request. - list_add_tail(&request.list, &master->reg_requests); - - up(&master->master_sem); + list_add_tail(&request->list, &master->reg_requests); + kref_get(&request->refcount); + + ec_mutex_unlock(&master->master_mutex); // wait for processing through FSM if (wait_event_interruptible(master->reg_queue, - request.state != EC_INT_REQUEST_QUEUED)) { - // interrupted by signal - down(&master->master_sem); - if (request.state == EC_INT_REQUEST_QUEUED) { - // abort request - list_del(&request.list); - up(&master->master_sem); - kfree(contents); - return -EINTR; - } - up(&master->master_sem); - } - - // wait until master FSM has finished processing - wait_event(master->reg_queue, request.state != EC_INT_REQUEST_BUSY); - - kfree(contents); - - 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_reg_request_release); + return -EINTR; + } + + retval = request->state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; + kref_put(&request->refcount,ec_master_reg_request_release); + return retval; + } /*****************************************************************************/ @@ -1325,12 +1322,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config_const( master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave config %u does not exist!\n", data.config_index); return -EINVAL; @@ -1356,7 +1353,7 @@ data.dc_sync[i] = sc->dc_sync[i]; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1387,12 +1384,12 @@ return -EINVAL; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config_const( master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave config %u does not exist!\n", data.config_index); return -EINVAL; @@ -1401,7 +1398,7 @@ if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( &sc->sync_configs[data.sync_index].pdos, data.pdo_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Invalid PDO position!\n"); return -EINVAL; } @@ -1410,7 +1407,7 @@ data.entry_count = ec_pdo_entry_count(pdo); ec_cdev_strcpy(data.name, pdo->name); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1442,12 +1439,12 @@ return -EINVAL; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config_const( master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave config %u does not exist!\n", data.config_index); return -EINVAL; @@ -1456,14 +1453,14 @@ if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( &sc->sync_configs[data.sync_index].pdos, data.pdo_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Invalid PDO position!\n"); return -EINVAL; } if (!(entry = ec_pdo_find_entry_by_pos_const( pdo, data.entry_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Entry not found!\n"); return -EINVAL; } @@ -1473,7 +1470,7 @@ data.bit_length = entry->bit_length; ec_cdev_strcpy(data.name, entry->name); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1498,12 +1495,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config_const( master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave config %u does not exist!\n", data.config_index); return -EINVAL; @@ -1511,7 +1508,7 @@ if (!(req = ec_slave_config_get_sdo_by_pos_const( sc, data.sdo_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Invalid SDO position!\n"); return -EINVAL; } @@ -1522,7 +1519,7 @@ memcpy(&data.data, req->data, min((u32) data.size, (u32) EC_MAX_SDO_DATA_SIZE)); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1547,12 +1544,12 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config_const( master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave config %u does not exist!\n", data.config_index); return -EINVAL; @@ -1560,7 +1557,7 @@ if (!(req = ec_slave_config_get_idn_by_pos_const( sc, data.idn_pos))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Invalid IDN position!\n"); return -EINVAL; } @@ -1572,7 +1569,7 @@ memcpy(&data.data, req->data, min((u32) data.size, (u32) EC_MAX_IDN_DATA_SIZE)); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1598,11 +1595,11 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(eoe = ec_master_get_eoe_handler_const(master, data.eoe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "EoE handler %u does not exist!\n", data.eoe_index); return -EINVAL; @@ -1615,14 +1612,14 @@ } snprintf(data.name, EC_DATAGRAM_NAME_SIZE, eoe->dev->name); data.open = eoe->opened; - data.rx_bytes = eoe->stats.tx_bytes; + data.tx_bytes = eoe->stats.tx_bytes; + data.tx_rate = eoe->tx_rate; + data.rx_bytes = eoe->stats.rx_bytes; data.rx_rate = eoe->tx_rate; - data.tx_bytes = eoe->stats.rx_bytes; - data.tx_rate = eoe->tx_rate; data.tx_queued_frames = eoe->tx_queued_frames; data.tx_queue_size = eoe->tx_queue_size; - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1704,7 +1701,7 @@ data.config_index = 0; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; list_for_each_entry(entry, &master->configs, list) { @@ -1713,7 +1710,7 @@ data.config_index++; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -1742,14 +1739,14 @@ priv->process_data_size = 0; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; list_for_each_entry(domain, &master->domains, list) { priv->process_data_size += ecrt_domain_size(domain); } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (priv->process_data_size) { priv->process_data = vmalloc(priv->process_data_size); @@ -1767,9 +1764,6 @@ } } - ecrt_master_callbacks(master, ec_master_internal_send_cb, - ec_master_internal_receive_cb, master); - ret = ecrt_master_activate(master); if (ret < 0) return ret; @@ -1815,10 +1809,10 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; ec_master_set_send_interval(master,send_interval); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -1837,9 +1831,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->io_sem); + ec_mutex_lock(&master->io_mutex); ecrt_master_send(master); - up(&master->io_sem); + ec_mutex_unlock(&master->io_mutex); return 0; } @@ -1856,9 +1850,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->io_sem); + ec_mutex_lock(&master->io_mutex); ecrt_master_receive(master); - up(&master->io_sem); + ec_mutex_unlock(&master->io_mutex); return 0; } @@ -1887,6 +1881,29 @@ /*****************************************************************************/ +/** Get the master state of all configured slaves. + */ +int ec_cdev_ioctl_master_sc_state( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_master_state_t data; + + if (unlikely(!priv->requested)) + return -EPERM; + + ecrt_master_configured_slaves_state(master, &data); + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) + return -EFAULT; + + return 0; +} + +/*****************************************************************************/ + /** Get the master state. */ int ec_cdev_ioctl_app_time( @@ -1921,9 +1938,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->io_sem); + ec_mutex_lock(&master->io_mutex); ecrt_master_sync_reference_clock(master); - up(&master->io_sem); + ec_mutex_unlock(&master->io_mutex); return 0; } @@ -1940,9 +1957,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->io_sem); + ec_mutex_lock(&master->io_mutex); ecrt_master_sync_slave_clocks(master); - up(&master->io_sem); + ec_mutex_unlock(&master->io_mutex); return 0; } @@ -1959,9 +1976,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->io_sem); + ec_mutex_lock(&master->io_mutex); ecrt_master_sync_monitor_queue(master); - up(&master->io_sem); + ec_mutex_unlock(&master->io_mutex); return 0; } @@ -1980,9 +1997,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->io_sem); + ec_mutex_lock(&master->io_mutex); time_diff = ecrt_master_sync_monitor_process(master); - up(&master->io_sem); + ec_mutex_unlock(&master->io_mutex); if (copy_to_user((void __user *) arg, &time_diff, sizeof(time_diff))) return -EFAULT; @@ -2003,9 +2020,9 @@ if (unlikely(!priv->requested)) return -EPERM; - down(&master->master_sem); + ec_mutex_lock(&master->master_mutex); ecrt_master_reset(master); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -2034,7 +2051,7 @@ goto out_return; } - if (down_interruptible(&master->master_sem)) { + if (ec_mutex_lock_interruptible(&master->master_mutex)) { ret = -EINTR; goto out_return; } @@ -2055,7 +2072,7 @@ } out_up: - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); out_return: return ret; } @@ -2084,7 +2101,7 @@ goto out_return; } - if (down_interruptible(&master->master_sem)) { + if (ec_mutex_lock_interruptible(&master->master_mutex)) { ret = -EINTR; goto out_return; } @@ -2098,11 +2115,55 @@ data.watchdog_divider, data.watchdog_intervals); out_up: - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); out_return: return ret; } + +/*****************************************************************************/ + +/** Configure wether a slave allows overlapping PDOs. + */ +int ec_cdev_ioctl_sc_allow_overlapping_pdos( + ec_master_t *master, /**< EtherCAT master. */ + unsigned long arg, /**< ioctl() argument. */ + ec_cdev_priv_t *priv /**< Private data structure of file handle. */ + ) +{ + ec_ioctl_config_t data; + ec_slave_config_t *sc; + int ret = 0; + + if (unlikely(!priv->requested)) { + ret = -EPERM; + goto out_return; + } + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + ret = -EFAULT; + goto out_return; + } + + if (ec_mutex_lock_interruptible(&master->master_mutex)) { + ret = -EINTR; + goto out_return; + } + + if (!(sc = ec_master_get_config(master, data.config_index))) { + ret = -ENOENT; + goto out_up; + } + + ecrt_slave_config_overlapping_pdos(sc, + data.allow_overlapping_pdos); + +out_up: + ec_mutex_unlock(&master->master_mutex); +out_return: + return ret; +} + /*****************************************************************************/ /** Add a PDO to the assignment. @@ -2122,15 +2183,15 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME return ecrt_slave_config_pdo_assign_add(sc, data.sync_index, data.index); } @@ -2154,15 +2215,15 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME ecrt_slave_config_pdo_assign_clear(sc, data.sync_index); return 0; @@ -2187,15 +2248,15 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME return ecrt_slave_config_pdo_mapping_add(sc, data.pdo_index, data.entry_index, data.entry_subindex, data.entry_bit_length); @@ -2220,15 +2281,15 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME ecrt_slave_config_pdo_mapping_clear(sc, data.index); return 0; @@ -2255,20 +2316,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(domain = ec_master_find_domain(master, data.domain_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME ret = ecrt_slave_config_reg_pdo_entry(sc, data.entry_index, data.entry_subindex, domain, &data.bit_position); @@ -2298,11 +2359,11 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } @@ -2312,7 +2373,7 @@ data.dc_sync[1].cycle_time, data.dc_sync[1].shift_time); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -2350,18 +2411,18 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) { + if (ec_mutex_lock_interruptible(&master->master_mutex)) { kfree(sdo_data); return -EINTR; } if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); kfree(sdo_data); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME if (data.complete_access) { ret = ecrt_slave_config_complete_sdo(sc, @@ -2397,12 +2458,12 @@ data.request_index = 0; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; sc = ec_master_get_config(master, data.config_index); if (!sc) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } @@ -2410,7 +2471,7 @@ data.request_index++; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); req = ecrt_slave_config_create_sdo_request_err(sc, data.sdo_index, data.sdo_subindex, data.size); @@ -2446,12 +2507,12 @@ data.voe_index = 0; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; sc = ec_master_get_config(master, data.config_index); if (!sc) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } @@ -2459,7 +2520,7 @@ data.voe_index++; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); voe = ecrt_slave_config_create_voe_handler_err(sc, data.size); if (IS_ERR(voe)) @@ -2492,17 +2553,17 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config_const(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } ecrt_slave_config_state(sc, &state); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) data.state, &state, sizeof(state))) return -EFAULT; @@ -2543,18 +2604,18 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) { + if (ec_mutex_lock_interruptible(&master->master_mutex)) { kfree(data); return -EINTR; } if (!(sc = ec_master_get_config(master, ioctl.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); kfree(data); return -ENOENT; } - up(&master->master_sem); // FIXME + ec_mutex_unlock(&master->master_mutex); // FIXME ret = ecrt_slave_config_idn( sc, ioctl.drive_no, ioctl.idn, ioctl.al_state, data, ioctl.size); @@ -2578,19 +2639,19 @@ if (unlikely(!priv->requested)) return -EPERM; - if (down_interruptible(&master->master_sem)) { + if (ec_mutex_lock_interruptible(&master->master_mutex)) { return -EINTR; } list_for_each_entry(domain, &master->domains, list) { if (domain->index == arg) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return offset; } offset += ecrt_domain_size(domain); } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } @@ -2609,16 +2670,16 @@ if (unlikely(!priv->requested)) return -EPERM; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(domain = ec_master_find_domain(master, arg))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } ecrt_domain_process(domain); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -2637,16 +2698,16 @@ if (unlikely(!priv->requested)) return -EPERM; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(domain = ec_master_find_domain(master, arg))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } ecrt_domain_queue(domain); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return 0; } @@ -2671,17 +2732,17 @@ return -EFAULT; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(domain = ec_master_find_domain_const(master, data.domain_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } ecrt_domain_state(domain, &state); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) data.state, &state, sizeof(state))) return -EFAULT; @@ -2709,20 +2770,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); ecrt_sdo_request_timeout(req, data.timeout); return 0; @@ -2748,16 +2809,16 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } @@ -2767,7 +2828,7 @@ else data.size = 0; - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) arg, &data, sizeof(data))) return -EFAULT; @@ -2795,20 +2856,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); ecrt_sdo_request_read(req); return 0; @@ -2840,20 +2901,20 @@ return -EINVAL; } - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); ret = ec_sdo_request_alloc(req, data.size); if (ret) @@ -2887,20 +2948,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(req = ec_slave_config_find_sdo_request(sc, data.request_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) data.data, ecrt_sdo_request_data(req), ecrt_sdo_request_data_size(req))) @@ -2937,20 +2998,20 @@ if (get_user(vendor_type, data.vendor_type)) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); ecrt_voe_handler_send_header(voe, vendor_id, vendor_type); return 0; @@ -2978,22 +3039,22 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } ecrt_voe_handler_received_header(voe, &vendor_id, &vendor_type); - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (likely(data.vendor_id)) if (put_user(vendor_id, data.vendor_id)) @@ -3026,20 +3087,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); ecrt_voe_handler_read(voe); return 0; @@ -3065,20 +3126,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); ecrt_voe_handler_read_nosync(voe); return 0; @@ -3104,20 +3165,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (data.size) { if (data.size > ec_voe_handler_mem_size(voe)) @@ -3152,20 +3213,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); data.state = ecrt_voe_handler_execute(voe); if (data.state == EC_REQUEST_SUCCESS && voe->dir == EC_DIR_INPUT) @@ -3199,20 +3260,20 @@ if (copy_from_user(&data, (void __user *) arg, sizeof(data))) return -EFAULT; - if (down_interruptible(&master->master_sem)) + if (ec_mutex_lock_interruptible(&master->master_mutex)) return -EINTR; if (!(sc = ec_master_get_config(master, data.config_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } if (!(voe = ec_slave_config_find_voe_handler(sc, data.voe_index))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); return -ENOENT; } - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); if (copy_to_user((void __user *) data.data, ecrt_voe_handler_data(voe), ecrt_voe_handler_data_size(voe))) @@ -3231,74 +3292,70 @@ ) { ec_ioctl_slave_foe_t data; - ec_master_foe_request_t request; + ec_master_foe_request_t* request; int retval; if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { return -EFAULT; } - ec_foe_request_init(&request.req, data.file_name); - ec_foe_request_read(&request.req); - ec_foe_request_alloc(&request.req, 10000); // FIXME - - if (down_interruptible(&master->master_sem)) - return -EINTR; - - if (!(request.slave = ec_master_find_slave( + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + kref_init(&request->refcount); + + ec_foe_request_init(&request->req, data.file_name); + ec_foe_request_read(&request->req); + ec_foe_request_alloc(&request->req, 10000); // FIXME + + if (ec_mutex_lock_interruptible(&master->master_mutex)) { + kref_put(&request->refcount,ec_master_foe_request_release); + return -EINTR; + } + if (!(request->slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); - ec_foe_request_clear(&request.req); + ec_mutex_unlock(&master->master_mutex); + kref_put(&request->refcount,ec_master_foe_request_release); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); return -EINVAL; } // schedule request. - list_add_tail(&request.list, &request.slave->foe_requests); - - up(&master->master_sem); - - EC_SLAVE_DBG(request.slave, 1, "Scheduled FoE read request.\n"); + list_add_tail(&request->list, &request->slave->foe_requests); + kref_get(&request->refcount); + + ec_mutex_unlock(&master->master_mutex); + + EC_SLAVE_DBG(request->slave, 1, "Scheduled FoE read request %p.\n",request); // wait for processing through FSM - if (wait_event_interruptible(request.slave->foe_queue, - request.req.state != EC_INT_REQUEST_QUEUED)) { + if (wait_event_interruptible(request->slave->foe_queue, + ((request->req.state == EC_INT_REQUEST_SUCCESS) || (request->req.state == EC_INT_REQUEST_FAILURE)))) { // interrupted by signal - down(&master->master_sem); - if (request.req.state == EC_INT_REQUEST_QUEUED) { - list_del(&request.list); - up(&master->master_sem); - ec_foe_request_clear(&request.req); - return -EINTR; - } - // request already processing: interrupt not possible. - up(&master->master_sem); - } - - // wait until master FSM has finished processing - wait_event(request.slave->foe_queue, - request.req.state != EC_INT_REQUEST_BUSY); - - data.result = request.req.result; - data.error_code = request.req.error_code; - - EC_SLAVE_DBG(request.slave, 1, "Read %zd bytes via FoE" - " (result = 0x%x).\n", request.req.data_size, request.req.result); - - if (request.req.state != EC_INT_REQUEST_SUCCESS) { + kref_put(&request->refcount,ec_master_foe_request_release); + return -EINTR; + } + + data.result = request->req.result; + data.error_code = request->req.error_code; + + EC_SLAVE_DBG(request->slave, 1, "Read %zd bytes via FoE" + " (result = 0x%x).\n", request->req.data_size, request->req.result); + + if (request->req.state != EC_INT_REQUEST_SUCCESS) { data.data_size = 0; retval = -EIO; } else { - if (request.req.data_size > data.buffer_size) { + if (request->req.data_size > data.buffer_size) { EC_MASTER_ERR(master, "Buffer too small.\n"); - ec_foe_request_clear(&request.req); + kref_put(&request->refcount,ec_master_foe_request_release); return -EOVERFLOW; } - data.data_size = request.req.data_size; + data.data_size = request->req.data_size; if (copy_to_user((void __user *) data.buffer, - request.req.buffer, data.data_size)) { - ec_foe_request_clear(&request.req); + request->req.buffer, data.data_size)) { + kref_put(&request->refcount,ec_master_foe_request_release); return -EFAULT; } retval = 0; @@ -3308,9 +3365,8 @@ retval = -EFAULT; } - EC_SLAVE_DBG(request.slave, 1, "Finished FoE read request.\n"); - - ec_foe_request_clear(&request.req); + EC_SLAVE_DBG(request->slave, 1, "Finished FoE read request %p.\n",request); + kref_put(&request->refcount,ec_master_foe_request_release); return retval; } @@ -3325,79 +3381,73 @@ ) { ec_ioctl_slave_foe_t data; - ec_master_foe_request_t request; + ec_master_foe_request_t* request; int retval; if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { return -EFAULT; } - INIT_LIST_HEAD(&request.list); - - ec_foe_request_init(&request.req, data.file_name); - - if (ec_foe_request_alloc(&request.req, data.buffer_size)) { - ec_foe_request_clear(&request.req); + request = kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) return -ENOMEM; - } - if (copy_from_user(request.req.buffer, + kref_init(&request->refcount); + + INIT_LIST_HEAD(&request->list); + + ec_foe_request_init(&request->req, data.file_name); + + if (ec_foe_request_alloc(&request->req, data.buffer_size)) { + kref_put(&request->refcount,ec_master_foe_request_release); + return -ENOMEM; + } + if (copy_from_user(request->req.buffer, (void __user *) data.buffer, data.buffer_size)) { - ec_foe_request_clear(&request.req); - return -EFAULT; - } - request.req.data_size = data.buffer_size; - ec_foe_request_write(&request.req); - - if (down_interruptible(&master->master_sem)) - return -EINTR; - - if (!(request.slave = ec_master_find_slave( + kref_put(&request->refcount,ec_master_foe_request_release); + return -EFAULT; + } + request->req.data_size = data.buffer_size; + ec_foe_request_write(&request->req); + + if (ec_mutex_lock_interruptible(&master->master_mutex)) + return -EINTR; + + if (!(request->slave = ec_master_find_slave( master, 0, data.slave_position))) { - up(&master->master_sem); + ec_mutex_unlock(&master->master_mutex); EC_MASTER_ERR(master, "Slave %u does not exist!\n", data.slave_position); - ec_foe_request_clear(&request.req); - return -EINVAL; - } - - EC_SLAVE_DBG(request.slave, 1, "Scheduling FoE write request.\n"); + kref_put(&request->refcount,ec_master_foe_request_release); + return -EINVAL; + } + + EC_SLAVE_DBG(request->slave, 1, "Scheduling FoE write request %p.\n",request); // schedule FoE write request. - list_add_tail(&request.list, &request.slave->foe_requests); - - up(&master->master_sem); + list_add_tail(&request->list, &request->slave->foe_requests); + kref_get(&request->refcount); + + ec_mutex_unlock(&master->master_mutex); // wait for processing through FSM - if (wait_event_interruptible(request.slave->foe_queue, - request.req.state != EC_INT_REQUEST_QUEUED)) { + if (wait_event_interruptible(request->slave->foe_queue, + ((request->req.state == EC_INT_REQUEST_SUCCESS) || (request->req.state == EC_INT_REQUEST_FAILURE)))) { // interrupted by signal - down(&master->master_sem); - if (request.req.state == EC_INT_REQUEST_QUEUED) { - // abort request - list_del(&request.list); - up(&master->master_sem); - ec_foe_request_clear(&request.req); - return -EINTR; - } - up(&master->master_sem); - } - - // wait until master FSM has finished processing - wait_event(request.slave->foe_queue, - request.req.state != EC_INT_REQUEST_BUSY); - - data.result = request.req.result; - data.error_code = request.req.error_code; - - retval = request.req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; + kref_put(&request->refcount,ec_master_foe_request_release); + return -EINTR; + } + + data.result = request->req.result; + data.error_code = request->req.error_code; + + retval = request->req.state == EC_INT_REQUEST_SUCCESS ? 0 : -EIO; if (__copy_to_user((void __user *) arg, &data, sizeof(data))) { retval = -EFAULT; } - ec_foe_request_clear(&request.req); - - EC_SLAVE_DBG(request.slave, 1, "Finished FoE write request.\n"); + EC_SLAVE_DBG(request->slave, 1, "Finished FoE write request %p.\n",request); + kref_put(&request->refcount,ec_master_foe_request_release); return retval; } @@ -3670,6 +3720,8 @@ return ec_cdev_ioctl_receive(master, arg, priv); case EC_IOCTL_MASTER_STATE: return ec_cdev_ioctl_master_state(master, arg, priv); + case EC_IOCTL_MASTER_SC_STATE: + return ec_cdev_ioctl_master_sc_state(master, arg, priv); case EC_IOCTL_APP_TIME: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; @@ -3702,6 +3754,10 @@ if (!(filp->f_mode & FMODE_WRITE)) return -EPERM; return ec_cdev_ioctl_sc_watchdog(master, arg, priv); + case EC_IOCTL_SC_OVERLAPPING_IO: + if (!(filp->f_mode & FMODE_WRITE)) + return -EPERM; + return ec_cdev_ioctl_sc_allow_overlapping_pdos(master,arg,priv); case EC_IOCTL_SC_ADD_PDO: if (!(filp->f_mode & FMODE_WRITE)) return -EPERM;