105 *****************************************************************************/ |
105 *****************************************************************************/ |
106 |
106 |
107 int eccdev_open(struct inode *inode, struct file *filp) |
107 int eccdev_open(struct inode *inode, struct file *filp) |
108 { |
108 { |
109 ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); |
109 ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); |
|
110 ec_master_t *master = cdev->master; |
110 |
111 |
111 filp->private_data = cdev; |
112 filp->private_data = cdev; |
112 EC_DBG("File opened.\n"); |
113 if (master->debug_level) |
|
114 EC_DBG("File opened.\n"); |
113 return 0; |
115 return 0; |
114 } |
116 } |
115 |
117 |
116 /*****************************************************************************/ |
118 /*****************************************************************************/ |
117 |
119 |
118 int eccdev_release(struct inode *inode, struct file *filp) |
120 int eccdev_release(struct inode *inode, struct file *filp) |
119 { |
121 { |
120 //ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); |
122 ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; |
121 |
123 ec_master_t *master = cdev->master; |
122 EC_DBG("File closed.\n"); |
124 |
|
125 if (master->debug_level) |
|
126 EC_DBG("File closed.\n"); |
123 return 0; |
127 return 0; |
124 } |
128 } |
125 |
129 |
126 /*****************************************************************************/ |
130 /*****************************************************************************/ |
127 |
131 |
128 int eccdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
132 long eccdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
129 unsigned long arg) |
133 { |
130 { |
134 ec_cdev_t *cdev = (ec_cdev_t *) filp->private_data; |
131 ec_cdev_t *cdev = container_of(inode->i_cdev, ec_cdev_t, cdev); |
|
132 ec_master_t *master = cdev->master; |
135 ec_master_t *master = cdev->master; |
|
136 long retval = 0; |
133 |
137 |
134 if (master->debug_level) |
138 if (master->debug_level) |
135 EC_DBG("ioctl(inode = %x, filp = %x, cmd = %u, arg = %u)\n", |
139 EC_DBG("ioctl(filp = %x, cmd = %u, arg = %u)\n", |
136 (u32) inode, (u32) filp, (u32) cmd, (u32) arg); |
140 (u32) filp, (u32) cmd, (u32) arg); |
137 |
141 |
|
142 // FIXME lock |
|
143 |
138 switch (cmd) { |
144 switch (cmd) { |
139 case EC_IOCTL_SLAVE_COUNT: |
145 case EC_IOCTL_SLAVE_COUNT: |
|
146 retval = master->slave_count; |
|
147 break; |
|
148 |
|
149 case EC_IOCTL_SLAVE: |
140 { |
150 { |
141 unsigned int slave_count = master->slave_count; |
151 ec_ioctl_slave_t data; |
142 EC_INFO("EC_IOCTL_SLAVE_COUNT\n"); |
152 const ec_slave_t *slave; |
143 if (!arg) |
153 |
144 return -EFAULT; |
154 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
145 if (copy_to_user((void __user *) arg, &slave_count, |
155 retval = -EFAULT; |
146 sizeof(unsigned int))) |
156 break; |
147 return -EFAULT; |
157 } |
148 return 0; |
158 |
|
159 if (!(slave = ec_master_find_slave( |
|
160 master, 0, data.position))) { |
|
161 EC_ERR("Slave %u does not exist!\n", data.position); |
|
162 retval = -EINVAL; |
|
163 break; |
|
164 } |
|
165 |
|
166 data.vendor_id = slave->sii.vendor_id; |
|
167 data.product_code = slave->sii.product_code; |
|
168 data.alias = slave->sii.alias; |
|
169 data.state = slave->current_state; |
|
170 |
|
171 data.sync_count = slave->sii.sync_count; |
|
172 |
|
173 if (slave->sii.name) { |
|
174 strncpy(data.name, slave->sii.name, |
|
175 EC_IOCTL_SLAVE_NAME_SIZE); |
|
176 data.name[EC_IOCTL_SLAVE_NAME_SIZE - 1] = 0; |
|
177 } else { |
|
178 data.name[0] = 0; |
|
179 } |
|
180 |
|
181 if (copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
182 retval = -EFAULT; |
|
183 break; |
|
184 } |
|
185 |
|
186 break; |
149 } |
187 } |
150 |
188 |
151 case EC_IOCTL_SLAVE_INFO: |
189 case EC_IOCTL_SYNC: |
152 { |
190 { |
153 struct ec_ioctl_slave_info *infos, *info; |
191 ec_ioctl_sync_t data; |
154 unsigned int slave_count = master->slave_count; |
|
155 const ec_slave_t *slave; |
192 const ec_slave_t *slave; |
156 unsigned int i = 0; |
193 const ec_sync_t *sync; |
157 |
194 |
158 if (master->debug_level) |
195 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
159 EC_DBG("EC_IOCTL_SLAVE_INFOS\n"); |
196 retval = -EFAULT; |
160 |
197 break; |
161 if (!slave_count) |
198 } |
162 return 0; |
199 |
163 |
200 if (!(slave = ec_master_find_slave( |
164 if (!arg) |
201 master, 0, data.slave_position))) { |
165 return -EFAULT; |
202 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
166 |
203 retval = -EINVAL; |
167 if (!(infos = kmalloc(slave_count * |
204 break; |
168 sizeof(struct ec_ioctl_slave_info), |
205 } |
169 GFP_KERNEL))) |
206 |
170 return -ENOMEM; |
207 if (data.sync_index >= slave->sii.sync_count) { |
171 |
208 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
172 list_for_each_entry(slave, &master->slaves, list) { |
209 data.sync_index, data.slave_position); |
173 info = &infos[i++]; |
210 retval = -EINVAL; |
174 info->vendor_id = slave->sii.vendor_id; |
211 break; |
175 info->product_code = slave->sii.product_code; |
212 } |
176 info->alias = slave->sii.alias; |
213 |
177 info->ring_position = slave->ring_position; |
214 sync = &slave->sii.syncs[data.sync_index]; |
178 info->state = slave->current_state; |
215 |
179 if (slave->sii.name) { |
216 data.physical_start_address = sync->physical_start_address; |
180 strncpy(info->description, slave->sii.name, |
217 data.default_size = sync->length; |
181 EC_IOCTL_SLAVE_INFO_DESC_SIZE); |
218 data.control_register = sync->control_register; |
182 info->description[EC_IOCTL_SLAVE_INFO_DESC_SIZE - 1] |
219 data.enable = sync->enable; |
183 = 0; |
220 data.assign_source = sync->assign_source; |
184 } else { |
221 data.pdo_count = ec_pdo_list_count(&sync->pdos); |
185 info->description[0] = 0; |
222 |
186 } |
223 if (copy_to_user((void __user *) arg, &data, sizeof(data))) { |
187 } |
224 retval = -EFAULT; |
188 |
225 break; |
189 if (copy_to_user((void __user *) arg, infos, slave_count * |
226 } |
190 sizeof(struct ec_ioctl_slave_info))) { |
227 break; |
191 kfree(infos); |
|
192 return -EFAULT; |
|
193 } |
|
194 |
|
195 kfree(infos); |
|
196 return 0; |
|
197 } |
228 } |
198 |
229 |
|
230 case EC_IOCTL_PDO: |
|
231 { |
|
232 ec_ioctl_pdo_t data; |
|
233 const ec_slave_t *slave; |
|
234 const ec_sync_t *sync; |
|
235 const ec_pdo_t *pdo; |
|
236 |
|
237 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
238 retval = -EFAULT; |
|
239 break; |
|
240 } |
|
241 |
|
242 if (!(slave = ec_master_find_slave( |
|
243 master, 0, data.slave_position))) { |
|
244 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
245 retval = -EINVAL; |
|
246 break; |
|
247 } |
|
248 |
|
249 if (data.sync_index >= slave->sii.sync_count) { |
|
250 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
251 data.sync_index, data.slave_position); |
|
252 retval = -EINVAL; |
|
253 break; |
|
254 } |
|
255 |
|
256 sync = &slave->sii.syncs[data.sync_index]; |
|
257 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
258 &sync->pdos, data.pdo_pos))) { |
|
259 EC_ERR("Sync manager %u does not contain a Pdo with " |
|
260 "position %u in slave %u!\n", data.sync_index, |
|
261 data.pdo_pos, data.slave_position); |
|
262 retval = -EINVAL; |
|
263 break; |
|
264 } |
|
265 |
|
266 data.dir = pdo->dir; |
|
267 data.index = pdo->index; |
|
268 data.entry_count = ec_pdo_entry_count(pdo); |
|
269 |
|
270 if (pdo->name) { |
|
271 strncpy(data.name, pdo->name, EC_IOCTL_PDO_NAME_SIZE); |
|
272 data.name[EC_IOCTL_PDO_NAME_SIZE - 1] = 0; |
|
273 } else { |
|
274 data.name[0] = 0; |
|
275 } |
|
276 |
|
277 if (copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
278 retval = -EFAULT; |
|
279 break; |
|
280 } |
|
281 break; |
|
282 } |
|
283 |
|
284 case EC_IOCTL_PDO_ENTRY: |
|
285 { |
|
286 ec_ioctl_pdo_entry_t data; |
|
287 const ec_slave_t *slave; |
|
288 const ec_sync_t *sync; |
|
289 const ec_pdo_t *pdo; |
|
290 const ec_pdo_entry_t *entry; |
|
291 |
|
292 if (copy_from_user(&data, (void __user *) arg, sizeof(data))) { |
|
293 retval = -EFAULT; |
|
294 break; |
|
295 } |
|
296 |
|
297 if (!(slave = ec_master_find_slave( |
|
298 master, 0, data.slave_position))) { |
|
299 EC_ERR("Slave %u does not exist!\n", data.slave_position); |
|
300 retval = -EINVAL; |
|
301 break; |
|
302 } |
|
303 |
|
304 if (data.sync_index >= slave->sii.sync_count) { |
|
305 EC_ERR("Sync manager %u does not exist in slave %u!\n", |
|
306 data.sync_index, data.slave_position); |
|
307 retval = -EINVAL; |
|
308 break; |
|
309 } |
|
310 |
|
311 sync = &slave->sii.syncs[data.sync_index]; |
|
312 if (!(pdo = ec_pdo_list_find_pdo_by_pos_const( |
|
313 &sync->pdos, data.pdo_pos))) { |
|
314 EC_ERR("Sync manager %u does not contain a Pdo with " |
|
315 "position %u in slave %u!\n", data.sync_index, |
|
316 data.pdo_pos, data.slave_position); |
|
317 retval = -EINVAL; |
|
318 break; |
|
319 } |
|
320 |
|
321 if (!(entry = ec_pdo_find_entry_by_pos_const( |
|
322 pdo, data.entry_pos))) { |
|
323 EC_ERR("Pdo 0x%04X does not contain an entry with " |
|
324 "position %u in slave %u!\n", data.pdo_pos, |
|
325 data.entry_pos, data.slave_position); |
|
326 retval = -EINVAL; |
|
327 break; |
|
328 } |
|
329 |
|
330 data.index = entry->index; |
|
331 data.subindex = entry->subindex; |
|
332 data.bit_length = entry->bit_length; |
|
333 if (entry->name) { |
|
334 strncpy(data.name, entry->name, |
|
335 EC_IOCTL_PDO_ENTRY_NAME_SIZE); |
|
336 data.name[EC_IOCTL_PDO_ENTRY_NAME_SIZE - 1] = 0; |
|
337 } else { |
|
338 data.name[0] = 0; |
|
339 } |
|
340 |
|
341 if (copy_to_user((void __user *) arg, &data, sizeof(data))) { |
|
342 retval = -EFAULT; |
|
343 break; |
|
344 } |
|
345 break; |
|
346 } |
|
347 |
199 default: |
348 default: |
200 return -ENOIOCTLCMD; |
349 retval = -ENOIOCTLCMD; |
201 } |
350 } |
202 } |
351 |
203 |
352 return retval; |
204 /*****************************************************************************/ |
353 } |
|
354 |
|
355 /*****************************************************************************/ |