diff -r 96241b092fac -r b954e9d91ea5 master/cdev.c --- a/master/cdev.c Mon Jun 02 10:49:44 2008 +0000 +++ b/master/cdev.c Mon Jun 02 10:51:31 2008 +0000 @@ -52,15 +52,15 @@ int eccdev_release(struct inode *, struct file *); ssize_t eccdev_read(struct file *, char __user *, size_t, loff_t *); ssize_t eccdev_write(struct file *, const char __user *, size_t, loff_t *); -int eccdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +long eccdev_ioctl(struct file *, unsigned int, unsigned long); /*****************************************************************************/ static struct file_operations eccdev_fops = { - .owner = THIS_MODULE, - .open = eccdev_open, - .release = eccdev_release, - .ioctl = eccdev_ioctl + .owner = THIS_MODULE, + .open = eccdev_open, + .release = eccdev_release, + .unlocked_ioctl = eccdev_ioctl }; /** \endcond */ @@ -107,9 +107,11 @@ int eccdev_open(struct inode *inode, struct file *filp) { ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); + ec_master_t *master = cdev->master; filp->private_data = cdev; - EC_DBG("File opened.\n"); + if (master->debug_level) + EC_DBG("File opened.\n"); return 0; } @@ -117,88 +119,237 @@ int eccdev_release(struct inode *inode, struct file *filp) { - //ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); - - EC_DBG("File closed.\n"); + ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; + ec_master_t *master = cdev->master; + + if (master->debug_level) + EC_DBG("File closed.\n"); return 0; } /*****************************************************************************/ -int eccdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); +long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; ec_master_t *master = cdev->master; + long retval = 0; if (master->debug_level) - EC_DBG("ioctl(inode = %x, filp = %x, cmd = %u, arg = %u)\n", - (u32) inode, (u32) filp, (u32) cmd, (u32) arg); - + EC_DBG("ioctl(filp = %x, cmd = %u, arg = %u)\n", + (u32) filp, (u32) cmd, (u32) arg); + + // FIXME lock + switch (cmd) { case EC_IOCTL_SLAVE_COUNT: + retval = master->slave_count; + break; + + case EC_IOCTL_SLAVE: { - unsigned int slave_count = master->slave_count; - EC_INFO("EC_IOCTL_SLAVE_COUNT\n"); - if (!arg) - return -EFAULT; - if (copy_to_user((void __user *) arg, &slave_count, - sizeof(unsigned int))) - return -EFAULT; - return 0; + ec_ioctl_slave_t data; + const ec_slave_t *slave; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.position))) { + EC_ERR("Slave %u does not exist!\n", data.position); + retval = -EINVAL; + break; + } + + data.vendor_id = slave->sii.vendor_id; + data.product_code = slave->sii.product_code; + data.alias = slave->sii.alias; + data.state = slave->current_state; + + data.sync_count = slave->sii.sync_count; + + if (slave->sii.name) { + strncpy(data.name, slave->sii.name, + EC_IOCTL_SLAVE_NAME_SIZE); + data.name[EC_IOCTL_SLAVE_NAME_SIZE - 1] = 0; + } else { + data.name[0] = 0; + } + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + + break; } - case EC_IOCTL_SLAVE_INFO: + case EC_IOCTL_SYNC: { - struct ec_ioctl_slave_info *infos, *info; - unsigned int slave_count = master->slave_count; + ec_ioctl_sync_t data; const ec_slave_t *slave; - unsigned int i = 0; - - if (master->debug_level) - EC_DBG("EC_IOCTL_SLAVE_INFOS\n"); - - if (!slave_count) - return 0; - - if (!arg) - return -EFAULT; - - if (!(infos = kmalloc(slave_count * - sizeof(struct ec_ioctl_slave_info), - GFP_KERNEL))) - return -ENOMEM; - - list_for_each_entry(slave, &master->slaves, list) { - info = &infos[i++]; - info->vendor_id = slave->sii.vendor_id; - info->product_code = slave->sii.product_code; - info->alias = slave->sii.alias; - info->ring_position = slave->ring_position; - info->state = slave->current_state; - if (slave->sii.name) { - strncpy(info->description, slave->sii.name, - EC_IOCTL_SLAVE_INFO_DESC_SIZE); - info->description[EC_IOCTL_SLAVE_INFO_DESC_SIZE - 1] - = 0; - } else { - info->description[0] = 0; - } - } - - if (copy_to_user((void __user *) arg, infos, slave_count * - sizeof(struct ec_ioctl_slave_info))) { - kfree(infos); - return -EFAULT; - } - - kfree(infos); - return 0; + const ec_sync_t *sync; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.slave_position))) { + EC_ERR("Slave %u does not exist!\n", data.slave_position); + retval = -EINVAL; + break; + } + + if (data.sync_index >= slave->sii.sync_count) { + EC_ERR("Sync manager %u does not exist in slave %u!\n", + data.sync_index, data.slave_position); + retval = -EINVAL; + break; + } + + sync = &slave->sii.syncs[data.sync_index]; + + data.physical_start_address = sync->physical_start_address; + data.default_size = sync->length; + data.control_register = sync->control_register; + data.enable = sync->enable; + data.assign_source = sync->assign_source; + data.pdo_count = ec_pdo_list_count(&sync->pdos); + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + break; } + case EC_IOCTL_PDO: + { + ec_ioctl_pdo_t data; + const ec_slave_t *slave; + const ec_sync_t *sync; + const ec_pdo_t *pdo; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.slave_position))) { + EC_ERR("Slave %u does not exist!\n", data.slave_position); + retval = -EINVAL; + break; + } + + if (data.sync_index >= slave->sii.sync_count) { + EC_ERR("Sync manager %u does not exist in slave %u!\n", + data.sync_index, data.slave_position); + retval = -EINVAL; + break; + } + + sync = &slave->sii.syncs[data.sync_index]; + if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( + &sync->pdos, data.pdo_pos))) { + EC_ERR("Sync manager %u does not contain a Pdo with " + "position %u in slave %u!\n", data.sync_index, + data.pdo_pos, data.slave_position); + retval = -EINVAL; + break; + } + + data.dir = pdo->dir; + data.index = pdo->index; + data.entry_count = ec_pdo_entry_count(pdo); + + if (pdo->name) { + strncpy(data.name, pdo->name, EC_IOCTL_PDO_NAME_SIZE); + data.name[EC_IOCTL_PDO_NAME_SIZE - 1] = 0; + } else { + data.name[0] = 0; + } + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + break; + } + + case EC_IOCTL_PDO_ENTRY: + { + ec_ioctl_pdo_entry_t data; + const ec_slave_t *slave; + const ec_sync_t *sync; + const ec_pdo_t *pdo; + const ec_pdo_entry_t *entry; + + if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { + retval = -EFAULT; + break; + } + + if (!(slave = ec_master_find_slave( + master, 0, data.slave_position))) { + EC_ERR("Slave %u does not exist!\n", data.slave_position); + retval = -EINVAL; + break; + } + + if (data.sync_index >= slave->sii.sync_count) { + EC_ERR("Sync manager %u does not exist in slave %u!\n", + data.sync_index, data.slave_position); + retval = -EINVAL; + break; + } + + sync = &slave->sii.syncs[data.sync_index]; + if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( + &sync->pdos, data.pdo_pos))) { + EC_ERR("Sync manager %u does not contain a Pdo with " + "position %u in slave %u!\n", data.sync_index, + data.pdo_pos, data.slave_position); + retval = -EINVAL; + break; + } + + if (!(entry = ec_pdo_find_entry_by_pos_const( + pdo, data.entry_pos))) { + EC_ERR("Pdo 0x%04X does not contain an entry with " + "position %u in slave %u!\n", data.pdo_pos, + data.entry_pos, data.slave_position); + retval = -EINVAL; + break; + } + + data.index = entry->index; + data.subindex = entry->subindex; + data.bit_length = entry->bit_length; + if (entry->name) { + strncpy(data.name, entry->name, + EC_IOCTL_PDO_ENTRY_NAME_SIZE); + data.name[EC_IOCTL_PDO_ENTRY_NAME_SIZE - 1] = 0; + } else { + data.name[0] = 0; + } + + if (copy_to_user((void __user *) arg, &data, sizeof(data))) { + retval = -EFAULT; + break; + } + break; + } + default: - return -ENOIOCTLCMD; + retval = -ENOIOCTLCMD; } -} - -/*****************************************************************************/ + + return retval; +} + +/*****************************************************************************/