staging: android: persistent_ram: Introduce persistent_ram_free()
[deliverable/linux.git] / drivers / staging / comedi / comedi_fops.c
CommitLineData
ed9eccbe
DS
1/*
2 comedi/comedi_fops.c
3 comedi kernel module
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23
24#undef DEBUG
25
26#define __NO_VERSION__
27#include "comedi_fops.h"
28#include "comedi_compat32.h"
29
30#include <linux/module.h>
31#include <linux/errno.h>
32#include <linux/kernel.h>
33#include <linux/sched.h>
34#include <linux/fcntl.h>
35#include <linux/delay.h>
36#include <linux/ioport.h>
37#include <linux/mm.h>
38#include <linux/slab.h>
39#include <linux/kmod.h>
40#include <linux/poll.h>
41#include <linux/init.h>
42#include <linux/device.h>
43#include <linux/vmalloc.h>
44#include <linux/fs.h>
45#include "comedidev.h"
46#include <linux/cdev.h>
883db3d9 47#include <linux/stat.h>
ed9eccbe 48
476b8477
GKH
49#include <linux/io.h>
50#include <linux/uaccess.h>
ed9eccbe 51
242e7ad9 52#include "internal.h"
ed9eccbe
DS
53
54MODULE_AUTHOR("http://www.comedi.org");
55MODULE_DESCRIPTION("Comedi core module");
56MODULE_LICENSE("GPL");
57
58#ifdef CONFIG_COMEDI_DEBUG
59int comedi_debug;
18736438 60EXPORT_SYMBOL(comedi_debug);
4d7df821
IA
61module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
62MODULE_PARM_DESC(comedi_debug,
63 "enable comedi core and driver debugging if non-zero (default 0)"
64 );
ed9eccbe
DS
65#endif
66
90ab5ee9 67bool comedi_autoconfig = 1;
4d7df821
IA
68module_param(comedi_autoconfig, bool, S_IRUGO);
69MODULE_PARM_DESC(comedi_autoconfig,
70 "enable drivers to auto-configure comedi devices (default 1)");
6a9d7a21 71
92d0127c 72static int comedi_num_legacy_minors;
4d7df821
IA
73module_param(comedi_num_legacy_minors, int, S_IRUGO);
74MODULE_PARM_DESC(comedi_num_legacy_minors,
75 "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
76 );
77
234bb3c6 78unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
4d7df821
IA
79module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
80MODULE_PARM_DESC(comedi_default_buf_size_kb,
81 "default asynchronous buffer size in KiB (default "
234bb3c6 82 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
4d7df821 83
234bb3c6
IA
84unsigned int comedi_default_buf_maxsize_kb
85 = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
4d7df821
IA
86module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
87MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
88 "default maximum size of asynchronous buffer in KiB (default "
234bb3c6 89 __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
1dd33ab8 90
ed9eccbe 91static DEFINE_SPINLOCK(comedi_file_info_table_lock);
476b8477 92static struct comedi_device_file_info
0a85b6f0 93*comedi_file_info_table[COMEDI_NUM_MINORS];
476b8477 94
0a85b6f0 95static int do_devconfig_ioctl(struct comedi_device *dev,
92d0127c
GKH
96 struct comedi_devconfig __user *arg);
97static int do_bufconfig_ioctl(struct comedi_device *dev,
98 struct comedi_bufconfig __user *arg);
0a85b6f0 99static int do_devinfo_ioctl(struct comedi_device *dev,
92d0127c
GKH
100 struct comedi_devinfo __user *arg,
101 struct file *file);
0a85b6f0 102static int do_subdinfo_ioctl(struct comedi_device *dev,
92d0127c 103 struct comedi_subdinfo __user *arg, void *file);
0a85b6f0 104static int do_chaninfo_ioctl(struct comedi_device *dev,
92d0127c
GKH
105 struct comedi_chaninfo __user *arg);
106static int do_bufinfo_ioctl(struct comedi_device *dev,
53fa827e 107 struct comedi_bufinfo __user *arg, void *file);
92d0127c
GKH
108static int do_cmd_ioctl(struct comedi_device *dev,
109 struct comedi_cmd __user *arg, void *file);
0a85b6f0
MT
110static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
111 void *file);
112static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
113 void *file);
114static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
115 void *file);
92d0127c
GKH
116static int do_cmdtest_ioctl(struct comedi_device *dev,
117 struct comedi_cmd __user *arg, void *file);
118static int do_insnlist_ioctl(struct comedi_device *dev,
119 struct comedi_insnlist __user *arg, void *file);
120static int do_insn_ioctl(struct comedi_device *dev,
121 struct comedi_insn __user *arg, void *file);
0a85b6f0
MT
122static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd,
123 void *file);
71b5f4f1 124
f5283a4b 125static void do_become_nonbusy(struct comedi_device *dev,
0a85b6f0 126 struct comedi_subdevice *s);
34c43922 127static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
ed9eccbe
DS
128
129static int comedi_fasync(int fd, struct file *file, int on);
130
71b5f4f1 131static int is_device_busy(struct comedi_device *dev);
a5011a26 132
883db3d9
FMH
133static int resize_async_buffer(struct comedi_device *dev,
134 struct comedi_subdevice *s,
a5011a26
HS
135 struct comedi_async *async, unsigned new_size)
136{
137 int retval;
138
139 if (new_size > async->max_bufsize)
140 return -EPERM;
141
142 if (s->busy) {
143 DPRINTK("subdevice is busy, cannot resize buffer\n");
144 return -EBUSY;
145 }
146 if (async->mmap_count) {
147 DPRINTK("subdevice is mmapped, cannot resize buffer\n");
148 return -EBUSY;
149 }
150
151 if (!async->prealloc_buf)
152 return -EINVAL;
153
154 /* make sure buffer is an integral number of pages
155 * (we round up) */
156 new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
157
158 retval = comedi_buf_alloc(dev, s, new_size);
159 if (retval < 0)
160 return retval;
161
162 if (s->buf_change) {
163 retval = s->buf_change(dev, s, new_size);
164 if (retval < 0)
165 return retval;
166 }
167
168 DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
169 dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
170 return 0;
171}
172
173/* sysfs attribute files */
174
175static const unsigned bytes_per_kibi = 1024;
176
177static ssize_t show_max_read_buffer_kb(struct device *dev,
178 struct device_attribute *attr, char *buf)
179{
180 ssize_t retval;
181 struct comedi_device_file_info *info = dev_get_drvdata(dev);
182 unsigned max_buffer_size_kb = 0;
183 struct comedi_subdevice *const read_subdevice =
184 comedi_get_read_subdevice(info);
185
186 mutex_lock(&info->device->mutex);
187 if (read_subdevice &&
188 (read_subdevice->subdev_flags & SDF_CMD_READ) &&
189 read_subdevice->async) {
190 max_buffer_size_kb = read_subdevice->async->max_bufsize /
191 bytes_per_kibi;
192 }
193 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
194 mutex_unlock(&info->device->mutex);
195
196 return retval;
197}
198
199static ssize_t store_max_read_buffer_kb(struct device *dev,
200 struct device_attribute *attr,
201 const char *buf, size_t count)
202{
203 struct comedi_device_file_info *info = dev_get_drvdata(dev);
204 unsigned int new_max_size_kb;
205 unsigned int new_max_size;
206 int ret;
207 struct comedi_subdevice *const read_subdevice =
208 comedi_get_read_subdevice(info);
209
210 ret = kstrtouint(buf, 10, &new_max_size_kb);
211 if (ret)
212 return ret;
213 if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
214 return -EINVAL;
215 new_max_size = new_max_size_kb * bytes_per_kibi;
216
217 mutex_lock(&info->device->mutex);
218 if (read_subdevice == NULL ||
219 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
220 read_subdevice->async == NULL) {
221 mutex_unlock(&info->device->mutex);
222 return -EINVAL;
223 }
224 read_subdevice->async->max_bufsize = new_max_size;
225 mutex_unlock(&info->device->mutex);
226
227 return count;
228}
229
230static DEVICE_ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
231 show_max_read_buffer_kb, store_max_read_buffer_kb);
232
233static ssize_t show_read_buffer_kb(struct device *dev,
234 struct device_attribute *attr, char *buf)
235{
236 ssize_t retval;
237 struct comedi_device_file_info *info = dev_get_drvdata(dev);
238 unsigned buffer_size_kb = 0;
239 struct comedi_subdevice *const read_subdevice =
240 comedi_get_read_subdevice(info);
241
242 mutex_lock(&info->device->mutex);
243 if (read_subdevice &&
244 (read_subdevice->subdev_flags & SDF_CMD_READ) &&
245 read_subdevice->async) {
246 buffer_size_kb = read_subdevice->async->prealloc_bufsz /
247 bytes_per_kibi;
248 }
249 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
250 mutex_unlock(&info->device->mutex);
251
252 return retval;
253}
254
255static ssize_t store_read_buffer_kb(struct device *dev,
256 struct device_attribute *attr,
257 const char *buf, size_t count)
258{
259 struct comedi_device_file_info *info = dev_get_drvdata(dev);
260 unsigned int new_size_kb;
261 unsigned int new_size;
262 int retval;
263 int ret;
264 struct comedi_subdevice *const read_subdevice =
265 comedi_get_read_subdevice(info);
266
267 ret = kstrtouint(buf, 10, &new_size_kb);
268 if (ret)
269 return ret;
270 if (new_size_kb > (UINT_MAX / bytes_per_kibi))
271 return -EINVAL;
272 new_size = new_size_kb * bytes_per_kibi;
273
274 mutex_lock(&info->device->mutex);
275 if (read_subdevice == NULL ||
276 (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
277 read_subdevice->async == NULL) {
278 mutex_unlock(&info->device->mutex);
279 return -EINVAL;
280 }
281 retval = resize_async_buffer(info->device, read_subdevice,
282 read_subdevice->async, new_size);
283 mutex_unlock(&info->device->mutex);
284
285 if (retval < 0)
286 return retval;
287 return count;
288}
883db3d9 289
a5011a26
HS
290static DEVICE_ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
291 show_read_buffer_kb, store_read_buffer_kb);
292
293static ssize_t show_max_write_buffer_kb(struct device *dev,
294 struct device_attribute *attr,
295 char *buf)
296{
297 ssize_t retval;
298 struct comedi_device_file_info *info = dev_get_drvdata(dev);
299 unsigned max_buffer_size_kb = 0;
300 struct comedi_subdevice *const write_subdevice =
301 comedi_get_write_subdevice(info);
302
303 mutex_lock(&info->device->mutex);
304 if (write_subdevice &&
305 (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
306 write_subdevice->async) {
307 max_buffer_size_kb = write_subdevice->async->max_bufsize /
308 bytes_per_kibi;
309 }
310 retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
311 mutex_unlock(&info->device->mutex);
312
313 return retval;
314}
315
316static ssize_t store_max_write_buffer_kb(struct device *dev,
317 struct device_attribute *attr,
318 const char *buf, size_t count)
319{
320 struct comedi_device_file_info *info = dev_get_drvdata(dev);
321 unsigned int new_max_size_kb;
322 unsigned int new_max_size;
323 int ret;
324 struct comedi_subdevice *const write_subdevice =
325 comedi_get_write_subdevice(info);
326
327 ret = kstrtouint(buf, 10, &new_max_size_kb);
328 if (ret)
329 return ret;
330 if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
331 return -EINVAL;
332 new_max_size = new_max_size_kb * bytes_per_kibi;
333
334 mutex_lock(&info->device->mutex);
335 if (write_subdevice == NULL ||
336 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
337 write_subdevice->async == NULL) {
338 mutex_unlock(&info->device->mutex);
339 return -EINVAL;
340 }
341 write_subdevice->async->max_bufsize = new_max_size;
342 mutex_unlock(&info->device->mutex);
343
344 return count;
345}
346
347static DEVICE_ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
348 show_max_write_buffer_kb, store_max_write_buffer_kb);
349
350static ssize_t show_write_buffer_kb(struct device *dev,
351 struct device_attribute *attr, char *buf)
352{
353 ssize_t retval;
354 struct comedi_device_file_info *info = dev_get_drvdata(dev);
355 unsigned buffer_size_kb = 0;
356 struct comedi_subdevice *const write_subdevice =
357 comedi_get_write_subdevice(info);
358
359 mutex_lock(&info->device->mutex);
360 if (write_subdevice &&
361 (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
362 write_subdevice->async) {
363 buffer_size_kb = write_subdevice->async->prealloc_bufsz /
364 bytes_per_kibi;
365 }
366 retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
367 mutex_unlock(&info->device->mutex);
368
369 return retval;
370}
371
372static ssize_t store_write_buffer_kb(struct device *dev,
373 struct device_attribute *attr,
374 const char *buf, size_t count)
375{
376 struct comedi_device_file_info *info = dev_get_drvdata(dev);
377 unsigned int new_size_kb;
378 unsigned int new_size;
379 int retval;
380 int ret;
381 struct comedi_subdevice *const write_subdevice =
382 comedi_get_write_subdevice(info);
383
384 ret = kstrtouint(buf, 10, &new_size_kb);
385 if (ret)
386 return ret;
387 if (new_size_kb > (UINT_MAX / bytes_per_kibi))
388 return -EINVAL;
389 new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
390
391 mutex_lock(&info->device->mutex);
392 if (write_subdevice == NULL ||
393 (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
394 write_subdevice->async == NULL) {
395 mutex_unlock(&info->device->mutex);
396 return -EINVAL;
397 }
398 retval = resize_async_buffer(info->device, write_subdevice,
399 write_subdevice->async, new_size);
400 mutex_unlock(&info->device->mutex);
401
402 if (retval < 0)
403 return retval;
404 return count;
405}
406
407static DEVICE_ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
408 show_write_buffer_kb, store_write_buffer_kb);
409
410static struct attribute *comedi_attrs[] = {
411 &dev_attr_max_read_buffer_kb.attr,
412 &dev_attr_read_buffer_kb.attr,
413 &dev_attr_max_write_buffer_kb.attr,
414 &dev_attr_write_buffer_kb.attr,
415 NULL
416};
417
418static const struct attribute_group comedi_sysfs_files = {
419 .attrs = comedi_attrs,
420};
ed9eccbe 421
ed9eccbe 422static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
476b8477 423 unsigned long arg)
ed9eccbe
DS
424{
425 const unsigned minor = iminor(file->f_dentry->d_inode);
476b8477
GKH
426 struct comedi_device_file_info *dev_file_info =
427 comedi_get_device_file_info(minor);
71b5f4f1 428 struct comedi_device *dev;
ed9eccbe
DS
429 int rc;
430
53b670a7
FMH
431 if (dev_file_info == NULL || dev_file_info->device == NULL)
432 return -ENODEV;
433 dev = dev_file_info->device;
434
ed9eccbe
DS
435 mutex_lock(&dev->mutex);
436
437 /* Device config is special, because it must work on
438 * an unconfigured device. */
439 if (cmd == COMEDI_DEVCONFIG) {
92d0127c
GKH
440 rc = do_devconfig_ioctl(dev,
441 (struct comedi_devconfig __user *)arg);
ed9eccbe
DS
442 goto done;
443 }
444
445 if (!dev->attached) {
446 DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor);
447 rc = -ENODEV;
448 goto done;
449 }
450
451 switch (cmd) {
452 case COMEDI_BUFCONFIG:
92d0127c
GKH
453 rc = do_bufconfig_ioctl(dev,
454 (struct comedi_bufconfig __user *)arg);
ed9eccbe
DS
455 break;
456 case COMEDI_DEVINFO:
92d0127c
GKH
457 rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg,
458 file);
ed9eccbe
DS
459 break;
460 case COMEDI_SUBDINFO:
92d0127c
GKH
461 rc = do_subdinfo_ioctl(dev,
462 (struct comedi_subdinfo __user *)arg,
463 file);
ed9eccbe
DS
464 break;
465 case COMEDI_CHANINFO:
92d0127c 466 rc = do_chaninfo_ioctl(dev, (void __user *)arg);
ed9eccbe
DS
467 break;
468 case COMEDI_RANGEINFO:
92d0127c 469 rc = do_rangeinfo_ioctl(dev, (void __user *)arg);
ed9eccbe
DS
470 break;
471 case COMEDI_BUFINFO:
92d0127c 472 rc = do_bufinfo_ioctl(dev,
53fa827e
IA
473 (struct comedi_bufinfo __user *)arg,
474 file);
ed9eccbe
DS
475 break;
476 case COMEDI_LOCK:
477 rc = do_lock_ioctl(dev, arg, file);
478 break;
479 case COMEDI_UNLOCK:
480 rc = do_unlock_ioctl(dev, arg, file);
481 break;
482 case COMEDI_CANCEL:
483 rc = do_cancel_ioctl(dev, arg, file);
484 break;
485 case COMEDI_CMD:
92d0127c 486 rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file);
ed9eccbe
DS
487 break;
488 case COMEDI_CMDTEST:
92d0127c
GKH
489 rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg,
490 file);
ed9eccbe
DS
491 break;
492 case COMEDI_INSNLIST:
92d0127c
GKH
493 rc = do_insnlist_ioctl(dev,
494 (struct comedi_insnlist __user *)arg,
495 file);
ed9eccbe
DS
496 break;
497 case COMEDI_INSN:
92d0127c
GKH
498 rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg,
499 file);
ed9eccbe
DS
500 break;
501 case COMEDI_POLL:
502 rc = do_poll_ioctl(dev, arg, file);
503 break;
504 default:
505 rc = -ENOTTY;
506 break;
507 }
508
476b8477 509done:
ed9eccbe
DS
510 mutex_unlock(&dev->mutex);
511 return rc;
512}
513
514/*
515 COMEDI_DEVCONFIG
516 device config ioctl
517
518 arg:
519 pointer to devconfig structure
520
521 reads:
522 devconfig structure at arg
523
524 writes:
525 none
526*/
0a85b6f0 527static int do_devconfig_ioctl(struct comedi_device *dev,
92d0127c 528 struct comedi_devconfig __user *arg)
ed9eccbe 529{
0707bb04 530 struct comedi_devconfig it;
ed9eccbe
DS
531 int ret;
532 unsigned char *aux_data = NULL;
533 int aux_len;
534
535 if (!capable(CAP_SYS_ADMIN))
536 return -EPERM;
537
538 if (arg == NULL) {
539 if (is_device_busy(dev))
540 return -EBUSY;
476b8477 541 if (dev->attached) {
ed9eccbe
DS
542 struct module *driver_module = dev->driver->module;
543 comedi_device_detach(dev);
544 module_put(driver_module);
545 }
546 return 0;
547 }
548
0707bb04 549 if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
ed9eccbe
DS
550 return -EFAULT;
551
552 it.board_name[COMEDI_NAMELEN - 1] = 0;
553
554 if (comedi_aux_data(it.options, 0) &&
476b8477 555 it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
ed9eccbe
DS
556 int bit_shift;
557 aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
558 if (aux_len < 0)
559 return -EFAULT;
560
561 aux_data = vmalloc(aux_len);
562 if (!aux_data)
563 return -ENOMEM;
564
565 if (copy_from_user(aux_data,
476b8477 566 comedi_aux_data(it.options, 0), aux_len)) {
ed9eccbe
DS
567 vfree(aux_data);
568 return -EFAULT;
569 }
570 it.options[COMEDI_DEVCONF_AUX_DATA_LO] =
476b8477 571 (unsigned long)aux_data;
ed9eccbe
DS
572 if (sizeof(void *) > sizeof(int)) {
573 bit_shift = sizeof(int) * 8;
574 it.options[COMEDI_DEVCONF_AUX_DATA_HI] =
476b8477 575 ((unsigned long)aux_data) >> bit_shift;
ed9eccbe
DS
576 } else
577 it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0;
578 }
579
580 ret = comedi_device_attach(dev, &it);
476b8477
GKH
581 if (ret == 0) {
582 if (!try_module_get(dev->driver->module)) {
ed9eccbe 583 comedi_device_detach(dev);
abae41e6 584 ret = -ENOSYS;
ed9eccbe
DS
585 }
586 }
587
588 if (aux_data)
589 vfree(aux_data);
590
591 return ret;
592}
593
594/*
595 COMEDI_BUFCONFIG
596 buffer configuration ioctl
597
598 arg:
599 pointer to bufconfig structure
600
601 reads:
602 bufconfig at arg
603
604 writes:
605 modified bufconfig at arg
606
607*/
92d0127c
GKH
608static int do_bufconfig_ioctl(struct comedi_device *dev,
609 struct comedi_bufconfig __user *arg)
ed9eccbe 610{
be6aba4a 611 struct comedi_bufconfig bc;
d163679c 612 struct comedi_async *async;
34c43922 613 struct comedi_subdevice *s;
883db3d9 614 int retval = 0;
ed9eccbe 615
be6aba4a 616 if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
ed9eccbe
DS
617 return -EFAULT;
618
619 if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
620 return -EINVAL;
621
622 s = dev->subdevices + bc.subdevice;
623 async = s->async;
624
625 if (!async) {
626 DPRINTK("subdevice does not have async capability\n");
627 bc.size = 0;
628 bc.maximum_size = 0;
629 goto copyback;
630 }
631
632 if (bc.maximum_size) {
633 if (!capable(CAP_SYS_ADMIN))
634 return -EPERM;
635
636 async->max_bufsize = bc.maximum_size;
637 }
638
639 if (bc.size) {
883db3d9
FMH
640 retval = resize_async_buffer(dev, s, async, bc.size);
641 if (retval < 0)
642 return retval;
ed9eccbe
DS
643 }
644
645 bc.size = async->prealloc_bufsz;
646 bc.maximum_size = async->max_bufsize;
647
476b8477 648copyback:
be6aba4a 649 if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
ed9eccbe
DS
650 return -EFAULT;
651
652 return 0;
653}
654
655/*
656 COMEDI_DEVINFO
657 device info ioctl
658
659 arg:
660 pointer to devinfo structure
661
662 reads:
663 none
664
665 writes:
666 devinfo structure
667
668*/
0a85b6f0 669static int do_devinfo_ioctl(struct comedi_device *dev,
92d0127c
GKH
670 struct comedi_devinfo __user *arg,
671 struct file *file)
ed9eccbe 672{
063db04b 673 struct comedi_devinfo devinfo;
ed9eccbe 674 const unsigned minor = iminor(file->f_dentry->d_inode);
476b8477
GKH
675 struct comedi_device_file_info *dev_file_info =
676 comedi_get_device_file_info(minor);
34c43922 677 struct comedi_subdevice *read_subdev =
476b8477 678 comedi_get_read_subdevice(dev_file_info);
34c43922 679 struct comedi_subdevice *write_subdev =
476b8477 680 comedi_get_write_subdevice(dev_file_info);
ed9eccbe
DS
681
682 memset(&devinfo, 0, sizeof(devinfo));
683
684 /* fill devinfo structure */
685 devinfo.version_code = COMEDI_VERSION_CODE;
686 devinfo.n_subdevs = dev->n_subdevices;
819cbb12
VK
687 strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
688 strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
ed9eccbe 689
476b8477 690 if (read_subdev)
ed9eccbe 691 devinfo.read_subdevice = read_subdev - dev->subdevices;
476b8477 692 else
ed9eccbe 693 devinfo.read_subdevice = -1;
476b8477
GKH
694
695 if (write_subdev)
ed9eccbe 696 devinfo.write_subdevice = write_subdev - dev->subdevices;
476b8477 697 else
ed9eccbe 698 devinfo.write_subdevice = -1;
ed9eccbe 699
063db04b 700 if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
ed9eccbe
DS
701 return -EFAULT;
702
703 return 0;
704}
705
706/*
707 COMEDI_SUBDINFO
708 subdevice info ioctl
709
710 arg:
711 pointer to array of subdevice info structures
712
713 reads:
714 none
715
716 writes:
717 array of subdevice info structures at arg
718
719*/
0a85b6f0 720static int do_subdinfo_ioctl(struct comedi_device *dev,
92d0127c 721 struct comedi_subdinfo __user *arg, void *file)
ed9eccbe
DS
722{
723 int ret, i;
bd52efbb 724 struct comedi_subdinfo *tmp, *us;
34c43922 725 struct comedi_subdevice *s;
ed9eccbe 726
0a85b6f0
MT
727 tmp =
728 kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo),
729 GFP_KERNEL);
ed9eccbe
DS
730 if (!tmp)
731 return -ENOMEM;
732
733 /* fill subdinfo structs */
734 for (i = 0; i < dev->n_subdevices; i++) {
735 s = dev->subdevices + i;
736 us = tmp + i;
737
738 us->type = s->type;
739 us->n_chan = s->n_chan;
740 us->subd_flags = s->subdev_flags;
741 if (comedi_get_subdevice_runflags(s) & SRF_RUNNING)
742 us->subd_flags |= SDF_RUNNING;
743#define TIMER_nanosec 5 /* backwards compatibility */
744 us->timer_type = TIMER_nanosec;
745 us->len_chanlist = s->len_chanlist;
746 us->maxdata = s->maxdata;
747 if (s->range_table) {
748 us->range_type =
476b8477 749 (i << 24) | (0 << 16) | (s->range_table->length);
ed9eccbe
DS
750 } else {
751 us->range_type = 0; /* XXX */
752 }
753 us->flags = s->flags;
754
755 if (s->busy)
756 us->subd_flags |= SDF_BUSY;
757 if (s->busy == file)
758 us->subd_flags |= SDF_BUSY_OWNER;
759 if (s->lock)
760 us->subd_flags |= SDF_LOCKED;
761 if (s->lock == file)
762 us->subd_flags |= SDF_LOCK_OWNER;
763 if (!s->maxdata && s->maxdata_list)
764 us->subd_flags |= SDF_MAXDATA;
765 if (s->flaglist)
766 us->subd_flags |= SDF_FLAGS;
767 if (s->range_table_list)
768 us->subd_flags |= SDF_RANGETYPE;
769 if (s->do_cmd)
770 us->subd_flags |= SDF_CMD;
771
772 if (s->insn_bits != &insn_inval)
773 us->insn_bits_support = COMEDI_SUPPORTED;
774 else
775 us->insn_bits_support = COMEDI_UNSUPPORTED;
776
777 us->settling_time_0 = s->settling_time_0;
778 }
779
780 ret = copy_to_user(arg, tmp,
bd52efbb 781 dev->n_subdevices * sizeof(struct comedi_subdinfo));
ed9eccbe
DS
782
783 kfree(tmp);
784
785 return ret ? -EFAULT : 0;
786}
787
788/*
789 COMEDI_CHANINFO
790 subdevice info ioctl
791
792 arg:
793 pointer to chaninfo structure
794
795 reads:
796 chaninfo structure at arg
797
798 writes:
799 arrays at elements of chaninfo structure
800
801*/
0a85b6f0 802static int do_chaninfo_ioctl(struct comedi_device *dev,
92d0127c 803 struct comedi_chaninfo __user *arg)
ed9eccbe 804{
34c43922 805 struct comedi_subdevice *s;
a18b416d 806 struct comedi_chaninfo it;
ed9eccbe 807
a18b416d 808 if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
ed9eccbe
DS
809 return -EFAULT;
810
811 if (it.subdev >= dev->n_subdevices)
812 return -EINVAL;
813 s = dev->subdevices + it.subdev;
814
815 if (it.maxdata_list) {
816 if (s->maxdata || !s->maxdata_list)
817 return -EINVAL;
818 if (copy_to_user(it.maxdata_list, s->maxdata_list,
790c5541 819 s->n_chan * sizeof(unsigned int)))
ed9eccbe
DS
820 return -EFAULT;
821 }
822
823 if (it.flaglist) {
824 if (!s->flaglist)
825 return -EINVAL;
826 if (copy_to_user(it.flaglist, s->flaglist,
476b8477 827 s->n_chan * sizeof(unsigned int)))
ed9eccbe
DS
828 return -EFAULT;
829 }
830
831 if (it.rangelist) {
832 int i;
833
834 if (!s->range_table_list)
835 return -EINVAL;
836 for (i = 0; i < s->n_chan; i++) {
837 int x;
838
839 x = (dev->minor << 28) | (it.subdev << 24) | (i << 16) |
476b8477 840 (s->range_table_list[i]->length);
81604d43
VK
841 if (put_user(x, it.rangelist + i))
842 return -EFAULT;
ed9eccbe 843 }
476b8477
GKH
844#if 0
845 if (copy_to_user(it.rangelist, s->range_type_list,
0a85b6f0 846 s->n_chan * sizeof(unsigned int)))
476b8477
GKH
847 return -EFAULT;
848#endif
ed9eccbe
DS
849 }
850
851 return 0;
852}
853
854 /*
855 COMEDI_BUFINFO
856 buffer information ioctl
857
858 arg:
859 pointer to bufinfo structure
860
861 reads:
862 bufinfo at arg
863
864 writes:
865 modified bufinfo at arg
866
867 */
92d0127c 868static int do_bufinfo_ioctl(struct comedi_device *dev,
53fa827e 869 struct comedi_bufinfo __user *arg, void *file)
ed9eccbe 870{
9aa5339a 871 struct comedi_bufinfo bi;
34c43922 872 struct comedi_subdevice *s;
d163679c 873 struct comedi_async *async;
ed9eccbe 874
9aa5339a 875 if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
ed9eccbe
DS
876 return -EFAULT;
877
878 if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
879 return -EINVAL;
880
881 s = dev->subdevices + bi.subdevice;
53fa827e
IA
882
883 if (s->lock && s->lock != file)
884 return -EACCES;
885
ed9eccbe
DS
886 async = s->async;
887
888 if (!async) {
889 DPRINTK("subdevice does not have async capability\n");
890 bi.buf_write_ptr = 0;
891 bi.buf_read_ptr = 0;
892 bi.buf_write_count = 0;
893 bi.buf_read_count = 0;
4772c018
IA
894 bi.bytes_read = 0;
895 bi.bytes_written = 0;
ed9eccbe
DS
896 goto copyback;
897 }
53fa827e
IA
898 if (!s->busy) {
899 bi.bytes_read = 0;
900 bi.bytes_written = 0;
901 goto copyback_position;
902 }
903 if (s->busy != file)
904 return -EACCES;
ed9eccbe
DS
905
906 if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
907 bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
908 comedi_buf_read_free(async, bi.bytes_read);
909
910 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR |
476b8477
GKH
911 SRF_RUNNING))
912 && async->buf_write_count == async->buf_read_count) {
ed9eccbe
DS
913 do_become_nonbusy(dev, s);
914 }
915 }
916
917 if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) {
918 bi.bytes_written =
476b8477 919 comedi_buf_write_alloc(async, bi.bytes_written);
ed9eccbe
DS
920 comedi_buf_write_free(async, bi.bytes_written);
921 }
922
53fa827e 923copyback_position:
ed9eccbe
DS
924 bi.buf_write_count = async->buf_write_count;
925 bi.buf_write_ptr = async->buf_write_ptr;
926 bi.buf_read_count = async->buf_read_count;
927 bi.buf_read_ptr = async->buf_read_ptr;
928
476b8477 929copyback:
9aa5339a 930 if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
ed9eccbe
DS
931 return -EFAULT;
932
933 return 0;
934}
935
0a85b6f0
MT
936static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
937 unsigned int *data, void *file);
ed9eccbe 938/*
20617f22
PDP
939 * COMEDI_INSNLIST
940 * synchronous instructions
ed9eccbe 941 *
20617f22
PDP
942 * arg:
943 * pointer to sync cmd structure
ed9eccbe 944 *
20617f22
PDP
945 * reads:
946 * sync cmd struct at arg
947 * instruction list
948 * data (for writes)
ed9eccbe 949 *
20617f22
PDP
950 * writes:
951 * data (for reads)
ed9eccbe
DS
952 */
953/* arbitrary limits */
954#define MAX_SAMPLES 256
92d0127c
GKH
955static int do_insnlist_ioctl(struct comedi_device *dev,
956 struct comedi_insnlist __user *arg, void *file)
ed9eccbe 957{
da613f4f 958 struct comedi_insnlist insnlist;
90035c08 959 struct comedi_insn *insns = NULL;
790c5541 960 unsigned int *data = NULL;
ed9eccbe
DS
961 int i = 0;
962 int ret = 0;
963
da613f4f 964 if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
ed9eccbe
DS
965 return -EFAULT;
966
790c5541 967 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
ed9eccbe
DS
968 if (!data) {
969 DPRINTK("kmalloc failed\n");
970 ret = -ENOMEM;
971 goto error;
972 }
973
0a85b6f0 974 insns =
dfd8ee92 975 kcalloc(insnlist.n_insns, sizeof(struct comedi_insn), GFP_KERNEL);
ed9eccbe
DS
976 if (!insns) {
977 DPRINTK("kmalloc failed\n");
978 ret = -ENOMEM;
979 goto error;
980 }
981
982 if (copy_from_user(insns, insnlist.insns,
90035c08 983 sizeof(struct comedi_insn) * insnlist.n_insns)) {
ed9eccbe
DS
984 DPRINTK("copy_from_user failed\n");
985 ret = -EFAULT;
986 goto error;
987 }
988
989 for (i = 0; i < insnlist.n_insns; i++) {
990 if (insns[i].n > MAX_SAMPLES) {
991 DPRINTK("number of samples too large\n");
992 ret = -EINVAL;
993 goto error;
994 }
995 if (insns[i].insn & INSN_MASK_WRITE) {
996 if (copy_from_user(data, insns[i].data,
790c5541 997 insns[i].n * sizeof(unsigned int))) {
ed9eccbe
DS
998 DPRINTK("copy_from_user failed\n");
999 ret = -EFAULT;
1000 goto error;
1001 }
1002 }
1003 ret = parse_insn(dev, insns + i, data, file);
1004 if (ret < 0)
1005 goto error;
1006 if (insns[i].insn & INSN_MASK_READ) {
1007 if (copy_to_user(insns[i].data, data,
790c5541 1008 insns[i].n * sizeof(unsigned int))) {
ed9eccbe
DS
1009 DPRINTK("copy_to_user failed\n");
1010 ret = -EFAULT;
1011 goto error;
1012 }
1013 }
1014 if (need_resched())
1015 schedule();
1016 }
1017
476b8477
GKH
1018error:
1019 kfree(insns);
1020 kfree(data);
ed9eccbe
DS
1021
1022 if (ret < 0)
1023 return ret;
1024 return i;
1025}
1026
0a85b6f0
MT
1027static int check_insn_config_length(struct comedi_insn *insn,
1028 unsigned int *data)
ed9eccbe 1029{
476b8477
GKH
1030 if (insn->n < 1)
1031 return -EINVAL;
ed9eccbe
DS
1032
1033 switch (data[0]) {
1034 case INSN_CONFIG_DIO_OUTPUT:
1035 case INSN_CONFIG_DIO_INPUT:
1036 case INSN_CONFIG_DISARM:
1037 case INSN_CONFIG_RESET:
1038 if (insn->n == 1)
1039 return 0;
1040 break;
1041 case INSN_CONFIG_ARM:
1042 case INSN_CONFIG_DIO_QUERY:
1043 case INSN_CONFIG_BLOCK_SIZE:
1044 case INSN_CONFIG_FILTER:
1045 case INSN_CONFIG_SERIAL_CLOCK:
1046 case INSN_CONFIG_BIDIRECTIONAL_DATA:
1047 case INSN_CONFIG_ALT_SOURCE:
1048 case INSN_CONFIG_SET_COUNTER_MODE:
1049 case INSN_CONFIG_8254_READ_STATUS:
1050 case INSN_CONFIG_SET_ROUTING:
1051 case INSN_CONFIG_GET_ROUTING:
1052 case INSN_CONFIG_GET_PWM_STATUS:
1053 case INSN_CONFIG_PWM_SET_PERIOD:
1054 case INSN_CONFIG_PWM_GET_PERIOD:
1055 if (insn->n == 2)
1056 return 0;
1057 break;
1058 case INSN_CONFIG_SET_GATE_SRC:
1059 case INSN_CONFIG_GET_GATE_SRC:
1060 case INSN_CONFIG_SET_CLOCK_SRC:
1061 case INSN_CONFIG_GET_CLOCK_SRC:
1062 case INSN_CONFIG_SET_OTHER_SRC:
1063 case INSN_CONFIG_GET_COUNTER_STATUS:
1064 case INSN_CONFIG_PWM_SET_H_BRIDGE:
1065 case INSN_CONFIG_PWM_GET_H_BRIDGE:
1066 case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
1067 if (insn->n == 3)
1068 return 0;
1069 break;
1070 case INSN_CONFIG_PWM_OUTPUT:
1071 case INSN_CONFIG_ANALOG_TRIG:
1072 if (insn->n == 5)
1073 return 0;
1074 break;
0a85b6f0
MT
1075 /* by default we allow the insn since we don't have checks for
1076 * all possible cases yet */
ed9eccbe 1077 default:
3fffdf20
MR
1078 printk(KERN_WARNING
1079 "comedi: no check for data length of config insn id "
0a85b6f0
MT
1080 "%i is implemented.\n"
1081 " Add a check to %s in %s.\n"
1082 " Assuming n=%i is correct.\n", data[0], __func__,
1083 __FILE__, insn->n);
ed9eccbe
DS
1084 return 0;
1085 break;
1086 }
1087 return -EINVAL;
1088}
1089
0a85b6f0
MT
1090static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
1091 unsigned int *data, void *file)
ed9eccbe 1092{
34c43922 1093 struct comedi_subdevice *s;
ed9eccbe
DS
1094 int ret = 0;
1095 int i;
1096
1097 if (insn->insn & INSN_MASK_SPECIAL) {
1098 /* a non-subdevice instruction */
1099
1100 switch (insn->insn) {
1101 case INSN_GTOD:
1102 {
1103 struct timeval tv;
1104
1105 if (insn->n != 2) {
1106 ret = -EINVAL;
1107 break;
1108 }
1109
1110 do_gettimeofday(&tv);
1111 data[0] = tv.tv_sec;
1112 data[1] = tv.tv_usec;
1113 ret = 2;
1114
1115 break;
1116 }
1117 case INSN_WAIT:
1118 if (insn->n != 1 || data[0] >= 100000) {
1119 ret = -EINVAL;
1120 break;
1121 }
1122 udelay(data[0] / 1000);
1123 ret = 1;
1124 break;
1125 case INSN_INTTRIG:
1126 if (insn->n != 1) {
1127 ret = -EINVAL;
1128 break;
1129 }
1130 if (insn->subdev >= dev->n_subdevices) {
1131 DPRINTK("%d not usable subdevice\n",
1132 insn->subdev);
1133 ret = -EINVAL;
1134 break;
1135 }
1136 s = dev->subdevices + insn->subdev;
1137 if (!s->async) {
1138 DPRINTK("no async\n");
1139 ret = -EINVAL;
1140 break;
1141 }
1142 if (!s->async->inttrig) {
1143 DPRINTK("no inttrig\n");
1144 ret = -EAGAIN;
1145 break;
1146 }
1147 ret = s->async->inttrig(dev, s, insn->data[0]);
1148 if (ret >= 0)
1149 ret = 1;
1150 break;
1151 default:
1152 DPRINTK("invalid insn\n");
1153 ret = -EINVAL;
1154 break;
1155 }
1156 } else {
1157 /* a subdevice instruction */
790c5541 1158 unsigned int maxdata;
ed9eccbe
DS
1159
1160 if (insn->subdev >= dev->n_subdevices) {
1161 DPRINTK("subdevice %d out of range\n", insn->subdev);
1162 ret = -EINVAL;
1163 goto out;
1164 }
1165 s = dev->subdevices + insn->subdev;
1166
1167 if (s->type == COMEDI_SUBD_UNUSED) {
1168 DPRINTK("%d not usable subdevice\n", insn->subdev);
1169 ret = -EIO;
1170 goto out;
1171 }
1172
1173 /* are we locked? (ioctl lock) */
1174 if (s->lock && s->lock != file) {
1175 DPRINTK("device locked\n");
1176 ret = -EACCES;
1177 goto out;
1178 }
1179
0fd0ca75 1180 ret = comedi_check_chanlist(s, 1, &insn->chanspec);
476b8477 1181 if (ret < 0) {
ed9eccbe
DS
1182 ret = -EINVAL;
1183 DPRINTK("bad chanspec\n");
1184 goto out;
1185 }
1186
1187 if (s->busy) {
1188 ret = -EBUSY;
1189 goto out;
1190 }
1191 /* This looks arbitrary. It is. */
1192 s->busy = &parse_insn;
1193 switch (insn->insn) {
1194 case INSN_READ:
1195 ret = s->insn_read(dev, s, insn, data);
1196 break;
1197 case INSN_WRITE:
1198 maxdata = s->maxdata_list
476b8477
GKH
1199 ? s->maxdata_list[CR_CHAN(insn->chanspec)]
1200 : s->maxdata;
ed9eccbe
DS
1201 for (i = 0; i < insn->n; ++i) {
1202 if (data[i] > maxdata) {
1203 ret = -EINVAL;
1204 DPRINTK("bad data value(s)\n");
1205 break;
1206 }
1207 }
1208 if (ret == 0)
1209 ret = s->insn_write(dev, s, insn, data);
1210 break;
1211 case INSN_BITS:
1212 if (insn->n != 2) {
1213 ret = -EINVAL;
2f644ccf
IA
1214 } else {
1215 /* Most drivers ignore the base channel in
1216 * insn->chanspec. Fix this here if
1217 * the subdevice has <= 32 channels. */
1218 unsigned int shift;
1219 unsigned int orig_mask;
1220
1221 orig_mask = data[0];
1222 if (s->n_chan <= 32) {
1223 shift = CR_CHAN(insn->chanspec);
1224 if (shift > 0) {
1225 insn->chanspec = 0;
1226 data[0] <<= shift;
1227 data[1] <<= shift;
1228 }
1229 } else
1230 shift = 0;
1231 ret = s->insn_bits(dev, s, insn, data);
1232 data[0] = orig_mask;
1233 if (shift > 0)
1234 data[1] >>= shift;
ed9eccbe 1235 }
ed9eccbe
DS
1236 break;
1237 case INSN_CONFIG:
1238 ret = check_insn_config_length(insn, data);
1239 if (ret)
1240 break;
1241 ret = s->insn_config(dev, s, insn, data);
1242 break;
1243 default:
1244 ret = -EINVAL;
1245 break;
1246 }
1247
1248 s->busy = NULL;
1249 }
1250
476b8477 1251out:
ed9eccbe
DS
1252 return ret;
1253}
1254
1255/*
20617f22
PDP
1256 * COMEDI_INSN
1257 * synchronous instructions
ed9eccbe 1258 *
20617f22
PDP
1259 * arg:
1260 * pointer to insn
ed9eccbe 1261 *
20617f22
PDP
1262 * reads:
1263 * struct comedi_insn struct at arg
1264 * data (for writes)
ed9eccbe 1265 *
20617f22
PDP
1266 * writes:
1267 * data (for reads)
ed9eccbe 1268 */
92d0127c
GKH
1269static int do_insn_ioctl(struct comedi_device *dev,
1270 struct comedi_insn __user *arg, void *file)
ed9eccbe 1271{
90035c08 1272 struct comedi_insn insn;
790c5541 1273 unsigned int *data = NULL;
ed9eccbe
DS
1274 int ret = 0;
1275
790c5541 1276 data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
ed9eccbe
DS
1277 if (!data) {
1278 ret = -ENOMEM;
1279 goto error;
1280 }
1281
90035c08 1282 if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
ed9eccbe
DS
1283 ret = -EFAULT;
1284 goto error;
1285 }
1286
1287 /* This is where the behavior of insn and insnlist deviate. */
1288 if (insn.n > MAX_SAMPLES)
1289 insn.n = MAX_SAMPLES;
1290 if (insn.insn & INSN_MASK_WRITE) {
21fe2eea
M
1291 if (copy_from_user(data,
1292 insn.data,
1293 insn.n * sizeof(unsigned int))) {
ed9eccbe
DS
1294 ret = -EFAULT;
1295 goto error;
1296 }
1297 }
1298 ret = parse_insn(dev, &insn, data, file);
1299 if (ret < 0)
1300 goto error;
1301 if (insn.insn & INSN_MASK_READ) {
21fe2eea
M
1302 if (copy_to_user(insn.data,
1303 data,
1304 insn.n * sizeof(unsigned int))) {
ed9eccbe
DS
1305 ret = -EFAULT;
1306 goto error;
1307 }
1308 }
1309 ret = insn.n;
1310
476b8477
GKH
1311error:
1312 kfree(data);
ed9eccbe
DS
1313
1314 return ret;
1315}
1316
181bd67b
GKH
1317static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
1318 unsigned mask, unsigned bits)
1319{
1320 unsigned long flags;
1321
1322 spin_lock_irqsave(&s->spin_lock, flags);
1323 s->runflags &= ~mask;
1324 s->runflags |= (bits & mask);
1325 spin_unlock_irqrestore(&s->spin_lock, flags);
1326}
1327
92d0127c
GKH
1328static int do_cmd_ioctl(struct comedi_device *dev,
1329 struct comedi_cmd __user *cmd, void *file)
ed9eccbe 1330{
ea6d0d4c 1331 struct comedi_cmd user_cmd;
34c43922 1332 struct comedi_subdevice *s;
d163679c 1333 struct comedi_async *async;
ed9eccbe 1334 int ret = 0;
92d0127c 1335 unsigned int __user *chanlist_saver = NULL;
ed9eccbe 1336
92d0127c 1337 if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
ed9eccbe
DS
1338 DPRINTK("bad cmd address\n");
1339 return -EFAULT;
1340 }
476b8477 1341 /* save user's chanlist pointer so it can be restored later */
ed9eccbe
DS
1342 chanlist_saver = user_cmd.chanlist;
1343
1344 if (user_cmd.subdev >= dev->n_subdevices) {
1345 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1346 return -ENODEV;
1347 }
1348
1349 s = dev->subdevices + user_cmd.subdev;
1350 async = s->async;
1351
1352 if (s->type == COMEDI_SUBD_UNUSED) {
1353 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1354 return -EIO;
1355 }
1356
1357 if (!s->do_cmd || !s->do_cmdtest || !s->async) {
1358 DPRINTK("subdevice %i does not support commands\n",
1359 user_cmd.subdev);
1360 return -EIO;
1361 }
1362
1363 /* are we locked? (ioctl lock) */
1364 if (s->lock && s->lock != file) {
1365 DPRINTK("subdevice locked\n");
1366 return -EACCES;
1367 }
1368
1369 /* are we busy? */
1370 if (s->busy) {
1371 DPRINTK("subdevice busy\n");
1372 return -EBUSY;
1373 }
1374 s->busy = file;
1375
1376 /* make sure channel/gain list isn't too long */
1377 if (user_cmd.chanlist_len > s->len_chanlist) {
1378 DPRINTK("channel/gain list too long %u > %d\n",
1379 user_cmd.chanlist_len, s->len_chanlist);
1380 ret = -EINVAL;
1381 goto cleanup;
1382 }
1383
1384 /* make sure channel/gain list isn't too short */
1385 if (user_cmd.chanlist_len < 1) {
1386 DPRINTK("channel/gain list too short %u < 1\n",
1387 user_cmd.chanlist_len);
1388 ret = -EINVAL;
1389 goto cleanup;
1390 }
1391
476b8477 1392 kfree(async->cmd.chanlist);
ed9eccbe
DS
1393 async->cmd = user_cmd;
1394 async->cmd.data = NULL;
1395 /* load channel/gain list */
1396 async->cmd.chanlist =
476b8477 1397 kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL);
ed9eccbe
DS
1398 if (!async->cmd.chanlist) {
1399 DPRINTK("allocation failed\n");
1400 ret = -ENOMEM;
1401 goto cleanup;
1402 }
1403
1404 if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
476b8477 1405 async->cmd.chanlist_len * sizeof(int))) {
ed9eccbe
DS
1406 DPRINTK("fault reading chanlist\n");
1407 ret = -EFAULT;
1408 goto cleanup;
1409 }
1410
1411 /* make sure each element in channel/gain list is valid */
21fe2eea
M
1412 ret = comedi_check_chanlist(s,
1413 async->cmd.chanlist_len,
1414 async->cmd.chanlist);
476b8477 1415 if (ret < 0) {
ed9eccbe
DS
1416 DPRINTK("bad chanlist\n");
1417 goto cleanup;
1418 }
1419
1420 ret = s->do_cmdtest(dev, s, &async->cmd);
1421
1422 if (async->cmd.flags & TRIG_BOGUS || ret) {
1423 DPRINTK("test returned %d\n", ret);
1424 user_cmd = async->cmd;
476b8477 1425 /* restore chanlist pointer before copying back */
ed9eccbe
DS
1426 user_cmd.chanlist = chanlist_saver;
1427 user_cmd.data = NULL;
92d0127c 1428 if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
ed9eccbe
DS
1429 DPRINTK("fault writing cmd\n");
1430 ret = -EFAULT;
1431 goto cleanup;
1432 }
1433 ret = -EAGAIN;
1434 goto cleanup;
1435 }
1436
1437 if (!async->prealloc_bufsz) {
1438 ret = -ENOMEM;
1439 DPRINTK("no buffer (?)\n");
1440 goto cleanup;
1441 }
1442
1443 comedi_reset_async_buf(async);
1444
1445 async->cb_mask =
476b8477
GKH
1446 COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR |
1447 COMEDI_CB_OVERFLOW;
1448 if (async->cmd.flags & TRIG_WAKE_EOS)
ed9eccbe 1449 async->cb_mask |= COMEDI_CB_EOS;
ed9eccbe
DS
1450
1451 comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING);
1452
ed9eccbe
DS
1453 ret = s->do_cmd(dev, s);
1454 if (ret == 0)
1455 return 0;
1456
476b8477 1457cleanup:
ed9eccbe
DS
1458 do_become_nonbusy(dev, s);
1459
1460 return ret;
1461}
1462
1463/*
1464 COMEDI_CMDTEST
1465 command testing ioctl
1466
1467 arg:
1468 pointer to cmd structure
1469
1470 reads:
1471 cmd structure at arg
1472 channel/range list
1473
1474 writes:
1475 modified cmd structure at arg
1476
1477*/
92d0127c
GKH
1478static int do_cmdtest_ioctl(struct comedi_device *dev,
1479 struct comedi_cmd __user *arg, void *file)
ed9eccbe 1480{
ea6d0d4c 1481 struct comedi_cmd user_cmd;
34c43922 1482 struct comedi_subdevice *s;
ed9eccbe
DS
1483 int ret = 0;
1484 unsigned int *chanlist = NULL;
92d0127c 1485 unsigned int __user *chanlist_saver = NULL;
ed9eccbe 1486
ea6d0d4c 1487 if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
ed9eccbe
DS
1488 DPRINTK("bad cmd address\n");
1489 return -EFAULT;
1490 }
476b8477 1491 /* save user's chanlist pointer so it can be restored later */
ed9eccbe
DS
1492 chanlist_saver = user_cmd.chanlist;
1493
1494 if (user_cmd.subdev >= dev->n_subdevices) {
1495 DPRINTK("%d no such subdevice\n", user_cmd.subdev);
1496 return -ENODEV;
1497 }
1498
1499 s = dev->subdevices + user_cmd.subdev;
1500 if (s->type == COMEDI_SUBD_UNUSED) {
1501 DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
1502 return -EIO;
1503 }
1504
1505 if (!s->do_cmd || !s->do_cmdtest) {
1506 DPRINTK("subdevice %i does not support commands\n",
1507 user_cmd.subdev);
1508 return -EIO;
1509 }
1510
1511 /* make sure channel/gain list isn't too long */
1512 if (user_cmd.chanlist_len > s->len_chanlist) {
1513 DPRINTK("channel/gain list too long %d > %d\n",
1514 user_cmd.chanlist_len, s->len_chanlist);
1515 ret = -EINVAL;
1516 goto cleanup;
1517 }
1518
1519 /* load channel/gain list */
1520 if (user_cmd.chanlist) {
1521 chanlist =
476b8477 1522 kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
ed9eccbe
DS
1523 if (!chanlist) {
1524 DPRINTK("allocation failed\n");
1525 ret = -ENOMEM;
1526 goto cleanup;
1527 }
1528
1529 if (copy_from_user(chanlist, user_cmd.chanlist,
476b8477 1530 user_cmd.chanlist_len * sizeof(int))) {
ed9eccbe
DS
1531 DPRINTK("fault reading chanlist\n");
1532 ret = -EFAULT;
1533 goto cleanup;
1534 }
1535
1536 /* make sure each element in channel/gain list is valid */
0fd0ca75 1537 ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
476b8477 1538 if (ret < 0) {
ed9eccbe
DS
1539 DPRINTK("bad chanlist\n");
1540 goto cleanup;
1541 }
1542
1543 user_cmd.chanlist = chanlist;
1544 }
1545
1546 ret = s->do_cmdtest(dev, s, &user_cmd);
1547
476b8477 1548 /* restore chanlist pointer before copying back */
ed9eccbe
DS
1549 user_cmd.chanlist = chanlist_saver;
1550
ea6d0d4c 1551 if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
ed9eccbe
DS
1552 DPRINTK("bad cmd address\n");
1553 ret = -EFAULT;
1554 goto cleanup;
1555 }
476b8477
GKH
1556cleanup:
1557 kfree(chanlist);
ed9eccbe
DS
1558
1559 return ret;
1560}
1561
1562/*
1563 COMEDI_LOCK
1564 lock subdevice
1565
1566 arg:
1567 subdevice number
1568
1569 reads:
1570 none
1571
1572 writes:
1573 none
1574
1575*/
1576
0a85b6f0
MT
1577static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
1578 void *file)
ed9eccbe
DS
1579{
1580 int ret = 0;
1581 unsigned long flags;
34c43922 1582 struct comedi_subdevice *s;
ed9eccbe
DS
1583
1584 if (arg >= dev->n_subdevices)
1585 return -EINVAL;
1586 s = dev->subdevices + arg;
1587
5f74ea14 1588 spin_lock_irqsave(&s->spin_lock, flags);
476b8477 1589 if (s->busy || s->lock)
ed9eccbe 1590 ret = -EBUSY;
476b8477 1591 else
ed9eccbe 1592 s->lock = file;
5f74ea14 1593 spin_unlock_irqrestore(&s->spin_lock, flags);
ed9eccbe 1594
c5274ab0 1595#if 0
ed9eccbe
DS
1596 if (ret < 0)
1597 return ret;
1598
ed9eccbe
DS
1599 if (s->lock_f)
1600 ret = s->lock_f(dev, s);
1601#endif
1602
1603 return ret;
1604}
1605
1606/*
1607 COMEDI_UNLOCK
1608 unlock subdevice
1609
1610 arg:
1611 subdevice number
1612
1613 reads:
1614 none
1615
1616 writes:
1617 none
1618
1619 This function isn't protected by the semaphore, since
1620 we already own the lock.
1621*/
0a85b6f0
MT
1622static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg,
1623 void *file)
ed9eccbe 1624{
34c43922 1625 struct comedi_subdevice *s;
ed9eccbe
DS
1626
1627 if (arg >= dev->n_subdevices)
1628 return -EINVAL;
1629 s = dev->subdevices + arg;
1630
1631 if (s->busy)
1632 return -EBUSY;
1633
1634 if (s->lock && s->lock != file)
1635 return -EACCES;
1636
1637 if (s->lock == file) {
1638#if 0
1639 if (s->unlock)
1640 s->unlock(dev, s);
1641#endif
1642
1643 s->lock = NULL;
1644 }
1645
1646 return 0;
1647}
1648
1649/*
1650 COMEDI_CANCEL
1651 cancel acquisition ioctl
1652
1653 arg:
1654 subdevice number
1655
1656 reads:
1657 nothing
1658
1659 writes:
1660 nothing
1661
1662*/
0a85b6f0
MT
1663static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg,
1664 void *file)
ed9eccbe 1665{
34c43922 1666 struct comedi_subdevice *s;
ed9eccbe
DS
1667
1668 if (arg >= dev->n_subdevices)
1669 return -EINVAL;
1670 s = dev->subdevices + arg;
1671 if (s->async == NULL)
1672 return -EINVAL;
1673
1674 if (s->lock && s->lock != file)
1675 return -EACCES;
1676
1677 if (!s->busy)
1678 return 0;
1679
1680 if (s->busy != file)
1681 return -EBUSY;
1682
1683 return do_cancel(dev, s);
1684}
1685
1686/*
1687 COMEDI_POLL ioctl
1688 instructs driver to synchronize buffers
1689
1690 arg:
1691 subdevice number
1692
1693 reads:
1694 nothing
1695
1696 writes:
1697 nothing
1698
1699*/
0a85b6f0
MT
1700static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg,
1701 void *file)
ed9eccbe 1702{
34c43922 1703 struct comedi_subdevice *s;
ed9eccbe
DS
1704
1705 if (arg >= dev->n_subdevices)
1706 return -EINVAL;
1707 s = dev->subdevices + arg;
1708
1709 if (s->lock && s->lock != file)
1710 return -EACCES;
1711
1712 if (!s->busy)
1713 return 0;
1714
1715 if (s->busy != file)
1716 return -EBUSY;
1717
1718 if (s->poll)
1719 return s->poll(dev, s);
1720
1721 return -EINVAL;
1722}
1723
34c43922 1724static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
ed9eccbe
DS
1725{
1726 int ret = 0;
1727
1728 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel)
1729 ret = s->cancel(dev, s);
1730
1731 do_become_nonbusy(dev, s);
1732
1733 return ret;
1734}
1735
df30b21c
FV
1736
1737static void comedi_vm_open(struct vm_area_struct *area)
1738{
1739 struct comedi_async *async;
1740 struct comedi_device *dev;
1741
1742 async = area->vm_private_data;
1743 dev = async->subdevice->device;
1744
1745 mutex_lock(&dev->mutex);
1746 async->mmap_count++;
1747 mutex_unlock(&dev->mutex);
1748}
1749
1750static void comedi_vm_close(struct vm_area_struct *area)
ed9eccbe 1751{
d163679c 1752 struct comedi_async *async;
71b5f4f1 1753 struct comedi_device *dev;
ed9eccbe
DS
1754
1755 async = area->vm_private_data;
1756 dev = async->subdevice->device;
1757
1758 mutex_lock(&dev->mutex);
1759 async->mmap_count--;
1760 mutex_unlock(&dev->mutex);
1761}
1762
1763static struct vm_operations_struct comedi_vm_ops = {
df30b21c
FV
1764 .open = comedi_vm_open,
1765 .close = comedi_vm_close,
ed9eccbe
DS
1766};
1767
1768static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
1769{
1770 const unsigned minor = iminor(file->f_dentry->d_inode);
d163679c 1771 struct comedi_async *async = NULL;
ed9eccbe
DS
1772 unsigned long start = vma->vm_start;
1773 unsigned long size;
1774 int n_pages;
1775 int i;
1776 int retval;
34c43922 1777 struct comedi_subdevice *s;
3ffab428
BP
1778 struct comedi_device_file_info *dev_file_info;
1779 struct comedi_device *dev;
1780
1781 dev_file_info = comedi_get_device_file_info(minor);
1782 if (dev_file_info == NULL)
70fe742c 1783 return -ENODEV;
3ffab428
BP
1784 dev = dev_file_info->device;
1785 if (dev == NULL)
70fe742c 1786 return -ENODEV;
ed9eccbe
DS
1787
1788 mutex_lock(&dev->mutex);
1789 if (!dev->attached) {
1790 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1791 retval = -ENODEV;
1792 goto done;
1793 }
476b8477 1794 if (vma->vm_flags & VM_WRITE)
ed9eccbe 1795 s = comedi_get_write_subdevice(dev_file_info);
476b8477 1796 else
ed9eccbe 1797 s = comedi_get_read_subdevice(dev_file_info);
476b8477 1798
ed9eccbe
DS
1799 if (s == NULL) {
1800 retval = -EINVAL;
1801 goto done;
1802 }
1803 async = s->async;
1804 if (async == NULL) {
1805 retval = -EINVAL;
1806 goto done;
1807 }
1808
1809 if (vma->vm_pgoff != 0) {
1810 DPRINTK("comedi: mmap() offset must be 0.\n");
1811 retval = -EINVAL;
1812 goto done;
1813 }
1814
1815 size = vma->vm_end - vma->vm_start;
1816 if (size > async->prealloc_bufsz) {
1817 retval = -EFAULT;
1818 goto done;
1819 }
1820 if (size & (~PAGE_MASK)) {
1821 retval = -EFAULT;
1822 goto done;
1823 }
1824
1825 n_pages = size >> PAGE_SHIFT;
1826 for (i = 0; i < n_pages; ++i) {
1827 if (remap_pfn_range(vma, start,
0a85b6f0
MT
1828 page_to_pfn(virt_to_page
1829 (async->buf_page_list
1830 [i].virt_addr)), PAGE_SIZE,
1831 PAGE_SHARED)) {
ed9eccbe
DS
1832 retval = -EAGAIN;
1833 goto done;
1834 }
1835 start += PAGE_SIZE;
1836 }
1837
1838 vma->vm_ops = &comedi_vm_ops;
1839 vma->vm_private_data = async;
1840
1841 async->mmap_count++;
1842
1843 retval = 0;
476b8477 1844done:
ed9eccbe
DS
1845 mutex_unlock(&dev->mutex);
1846 return retval;
1847}
1848
1ae5062a 1849static unsigned int comedi_poll(struct file *file, poll_table *wait)
ed9eccbe
DS
1850{
1851 unsigned int mask = 0;
1852 const unsigned minor = iminor(file->f_dentry->d_inode);
34c43922
BP
1853 struct comedi_subdevice *read_subdev;
1854 struct comedi_subdevice *write_subdev;
3ffab428
BP
1855 struct comedi_device_file_info *dev_file_info;
1856 struct comedi_device *dev;
1857 dev_file_info = comedi_get_device_file_info(minor);
1858
1859 if (dev_file_info == NULL)
70fe742c 1860 return -ENODEV;
3ffab428
BP
1861 dev = dev_file_info->device;
1862 if (dev == NULL)
70fe742c 1863 return -ENODEV;
ed9eccbe
DS
1864
1865 mutex_lock(&dev->mutex);
1866 if (!dev->attached) {
1867 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1868 mutex_unlock(&dev->mutex);
1869 return 0;
1870 }
1871
1872 mask = 0;
1873 read_subdev = comedi_get_read_subdevice(dev_file_info);
1874 if (read_subdev) {
1875 poll_wait(file, &read_subdev->async->wait_head, wait);
1876 if (!read_subdev->busy
476b8477
GKH
1877 || comedi_buf_read_n_available(read_subdev->async) > 0
1878 || !(comedi_get_subdevice_runflags(read_subdev) &
1879 SRF_RUNNING)) {
ed9eccbe
DS
1880 mask |= POLLIN | POLLRDNORM;
1881 }
1882 }
1883 write_subdev = comedi_get_write_subdevice(dev_file_info);
1884 if (write_subdev) {
1885 poll_wait(file, &write_subdev->async->wait_head, wait);
476b8477
GKH
1886 comedi_buf_write_alloc(write_subdev->async,
1887 write_subdev->async->prealloc_bufsz);
ed9eccbe 1888 if (!write_subdev->busy
476b8477
GKH
1889 || !(comedi_get_subdevice_runflags(write_subdev) &
1890 SRF_RUNNING)
1891 || comedi_buf_write_n_allocated(write_subdev->async) >=
1892 bytes_per_sample(write_subdev->async->subdevice)) {
ed9eccbe
DS
1893 mask |= POLLOUT | POLLWRNORM;
1894 }
1895 }
1896
1897 mutex_unlock(&dev->mutex);
1898 return mask;
1899}
1900
92d0127c
GKH
1901static ssize_t comedi_write(struct file *file, const char __user *buf,
1902 size_t nbytes, loff_t *offset)
ed9eccbe 1903{
34c43922 1904 struct comedi_subdevice *s;
d163679c 1905 struct comedi_async *async;
ed9eccbe
DS
1906 int n, m, count = 0, retval = 0;
1907 DECLARE_WAITQUEUE(wait, current);
1908 const unsigned minor = iminor(file->f_dentry->d_inode);
3ffab428
BP
1909 struct comedi_device_file_info *dev_file_info;
1910 struct comedi_device *dev;
1911 dev_file_info = comedi_get_device_file_info(minor);
1912
1913 if (dev_file_info == NULL)
70fe742c 1914 return -ENODEV;
3ffab428
BP
1915 dev = dev_file_info->device;
1916 if (dev == NULL)
70fe742c 1917 return -ENODEV;
ed9eccbe
DS
1918
1919 if (!dev->attached) {
1920 DPRINTK("no driver configured on comedi%i\n", dev->minor);
1921 retval = -ENODEV;
1922 goto done;
1923 }
1924
1925 s = comedi_get_write_subdevice(dev_file_info);
1926 if (s == NULL) {
1927 retval = -EIO;
1928 goto done;
1929 }
1930 async = s->async;
1931
1932 if (!nbytes) {
1933 retval = 0;
1934 goto done;
1935 }
1936 if (!s->busy) {
1937 retval = 0;
1938 goto done;
1939 }
1940 if (s->busy != file) {
1941 retval = -EACCES;
1942 goto done;
1943 }
1944 add_wait_queue(&async->wait_head, &wait);
1945 while (nbytes > 0 && !retval) {
1946 set_current_state(TASK_INTERRUPTIBLE);
1947
d2611540
IA
1948 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
1949 if (count == 0) {
1950 if (comedi_get_subdevice_runflags(s) &
1951 SRF_ERROR) {
1952 retval = -EPIPE;
1953 } else {
1954 retval = 0;
1955 }
1956 do_become_nonbusy(dev, s);
1957 }
1958 break;
1959 }
1960
ed9eccbe
DS
1961 n = nbytes;
1962
1963 m = n;
476b8477 1964 if (async->buf_write_ptr + m > async->prealloc_bufsz)
ed9eccbe 1965 m = async->prealloc_bufsz - async->buf_write_ptr;
ed9eccbe 1966 comedi_buf_write_alloc(async, async->prealloc_bufsz);
476b8477 1967 if (m > comedi_buf_write_n_allocated(async))
ed9eccbe 1968 m = comedi_buf_write_n_allocated(async);
ed9eccbe
DS
1969 if (m < n)
1970 n = m;
1971
1972 if (n == 0) {
ed9eccbe
DS
1973 if (file->f_flags & O_NONBLOCK) {
1974 retval = -EAGAIN;
1975 break;
1976 }
6a9ce6b6 1977 schedule();
ed9eccbe
DS
1978 if (signal_pending(current)) {
1979 retval = -ERESTARTSYS;
1980 break;
1981 }
476b8477 1982 if (!s->busy)
ed9eccbe 1983 break;
ed9eccbe
DS
1984 if (s->busy != file) {
1985 retval = -EACCES;
1986 break;
1987 }
1988 continue;
1989 }
1990
1991 m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
476b8477 1992 buf, n);
ed9eccbe
DS
1993 if (m) {
1994 n -= m;
1995 retval = -EFAULT;
1996 }
1997 comedi_buf_write_free(async, n);
1998
1999 count += n;
2000 nbytes -= n;
2001
2002 buf += n;
2003 break; /* makes device work like a pipe */
2004 }
2005 set_current_state(TASK_RUNNING);
2006 remove_wait_queue(&async->wait_head, &wait);
2007
2008done:
476b8477 2009 return count ? count : retval;
ed9eccbe
DS
2010}
2011
92d0127c 2012static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
6705b68d 2013 loff_t *offset)
ed9eccbe 2014{
34c43922 2015 struct comedi_subdevice *s;
d163679c 2016 struct comedi_async *async;
ed9eccbe
DS
2017 int n, m, count = 0, retval = 0;
2018 DECLARE_WAITQUEUE(wait, current);
2019 const unsigned minor = iminor(file->f_dentry->d_inode);
3ffab428
BP
2020 struct comedi_device_file_info *dev_file_info;
2021 struct comedi_device *dev;
2022 dev_file_info = comedi_get_device_file_info(minor);
2023
2024 if (dev_file_info == NULL)
70fe742c 2025 return -ENODEV;
3ffab428
BP
2026 dev = dev_file_info->device;
2027 if (dev == NULL)
70fe742c 2028 return -ENODEV;
ed9eccbe
DS
2029
2030 if (!dev->attached) {
2031 DPRINTK("no driver configured on comedi%i\n", dev->minor);
2032 retval = -ENODEV;
2033 goto done;
2034 }
2035
2036 s = comedi_get_read_subdevice(dev_file_info);
2037 if (s == NULL) {
2038 retval = -EIO;
2039 goto done;
2040 }
2041 async = s->async;
2042 if (!nbytes) {
2043 retval = 0;
2044 goto done;
2045 }
2046 if (!s->busy) {
2047 retval = 0;
2048 goto done;
2049 }
2050 if (s->busy != file) {
2051 retval = -EACCES;
2052 goto done;
2053 }
2054
2055 add_wait_queue(&async->wait_head, &wait);
2056 while (nbytes > 0 && !retval) {
2057 set_current_state(TASK_INTERRUPTIBLE);
2058
2059 n = nbytes;
2060
2061 m = comedi_buf_read_n_available(async);
476b8477
GKH
2062 /* printk("%d available\n",m); */
2063 if (async->buf_read_ptr + m > async->prealloc_bufsz)
ed9eccbe 2064 m = async->prealloc_bufsz - async->buf_read_ptr;
476b8477 2065 /* printk("%d contiguous\n",m); */
ed9eccbe
DS
2066 if (m < n)
2067 n = m;
2068
2069 if (n == 0) {
2070 if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
2071 do_become_nonbusy(dev, s);
2072 if (comedi_get_subdevice_runflags(s) &
476b8477 2073 SRF_ERROR) {
ed9eccbe
DS
2074 retval = -EPIPE;
2075 } else {
2076 retval = 0;
2077 }
2078 break;
2079 }
2080 if (file->f_flags & O_NONBLOCK) {
2081 retval = -EAGAIN;
2082 break;
2083 }
6a9ce6b6 2084 schedule();
ed9eccbe
DS
2085 if (signal_pending(current)) {
2086 retval = -ERESTARTSYS;
2087 break;
2088 }
ed9eccbe
DS
2089 if (!s->busy) {
2090 retval = 0;
2091 break;
2092 }
2093 if (s->busy != file) {
2094 retval = -EACCES;
2095 break;
2096 }
2097 continue;
2098 }
2099 m = copy_to_user(buf, async->prealloc_buf +
476b8477 2100 async->buf_read_ptr, n);
ed9eccbe
DS
2101 if (m) {
2102 n -= m;
2103 retval = -EFAULT;
2104 }
2105
2106 comedi_buf_read_alloc(async, n);
2107 comedi_buf_read_free(async, n);
2108
2109 count += n;
2110 nbytes -= n;
2111
2112 buf += n;
2113 break; /* makes device work like a pipe */
2114 }
2115 if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) &&
476b8477 2116 async->buf_read_count - async->buf_write_count == 0) {
ed9eccbe
DS
2117 do_become_nonbusy(dev, s);
2118 }
2119 set_current_state(TASK_RUNNING);
2120 remove_wait_queue(&async->wait_head, &wait);
2121
2122done:
476b8477 2123 return count ? count : retval;
ed9eccbe
DS
2124}
2125
2126/*
2127 This function restores a subdevice to an idle state.
2128 */
34c43922 2129void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
ed9eccbe 2130{
d163679c 2131 struct comedi_async *async = s->async;
ed9eccbe
DS
2132
2133 comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
ed9eccbe
DS
2134 if (async) {
2135 comedi_reset_async_buf(async);
2136 async->inttrig = NULL;
2137 } else {
476b8477
GKH
2138 printk(KERN_ERR
2139 "BUG: (?) do_become_nonbusy called with async=0\n");
ed9eccbe
DS
2140 }
2141
2142 s->busy = NULL;
2143}
2144
2145static int comedi_open(struct inode *inode, struct file *file)
2146{
ed9eccbe 2147 const unsigned minor = iminor(inode);
476b8477
GKH
2148 struct comedi_device_file_info *dev_file_info =
2149 comedi_get_device_file_info(minor);
0a85b6f0
MT
2150 struct comedi_device *dev =
2151 dev_file_info ? dev_file_info->device : NULL;
97920071 2152
ed9eccbe
DS
2153 if (dev == NULL) {
2154 DPRINTK("invalid minor number\n");
2155 return -ENODEV;
2156 }
2157
2158 /* This is slightly hacky, but we want module autoloading
2159 * to work for root.
2160 * case: user opens device, attached -> ok
2161 * case: user opens device, unattached, in_request_module=0 -> autoload
2162 * case: user opens device, unattached, in_request_module=1 -> fail
2163 * case: root opens device, attached -> ok
2164 * case: root opens device, unattached, in_request_module=1 -> ok
2165 * (typically called from modprobe)
2166 * case: root opens device, unattached, in_request_module=0 -> autoload
2167 *
2168 * The last could be changed to "-> ok", which would deny root
2169 * autoloading.
2170 */
2171 mutex_lock(&dev->mutex);
2172 if (dev->attached)
2173 goto ok;
a8f80e8f 2174 if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
ed9eccbe
DS
2175 DPRINTK("in request module\n");
2176 mutex_unlock(&dev->mutex);
2177 return -ENODEV;
2178 }
a8f80e8f 2179 if (capable(CAP_NET_ADMIN) && dev->in_request_module)
ed9eccbe
DS
2180 goto ok;
2181
2182 dev->in_request_module = 1;
2183
ed9eccbe
DS
2184#ifdef CONFIG_KMOD
2185 mutex_unlock(&dev->mutex);
56d92c60 2186 request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
ed9eccbe
DS
2187 mutex_lock(&dev->mutex);
2188#endif
2189
2190 dev->in_request_module = 0;
2191
a8f80e8f
EP
2192 if (!dev->attached && !capable(CAP_NET_ADMIN)) {
2193 DPRINTK("not attached and not CAP_NET_ADMIN\n");
ed9eccbe
DS
2194 mutex_unlock(&dev->mutex);
2195 return -ENODEV;
2196 }
2197ok:
2198 __module_get(THIS_MODULE);
2199
2200 if (dev->attached) {
2201 if (!try_module_get(dev->driver->module)) {
2202 module_put(THIS_MODULE);
2203 mutex_unlock(&dev->mutex);
2204 return -ENOSYS;
2205 }
2206 }
2207
3c17ba07
IA
2208 if (dev->attached && dev->use_count == 0 && dev->open) {
2209 int rc = dev->open(dev);
2210 if (rc < 0) {
2211 module_put(dev->driver->module);
2212 module_put(THIS_MODULE);
2213 mutex_unlock(&dev->mutex);
2214 return rc;
2215 }
2216 }
ed9eccbe
DS
2217
2218 dev->use_count++;
2219
a5011a26 2220 mutex_unlock(&dev->mutex);
ed9eccbe 2221
a5011a26 2222 return 0;
ed9eccbe
DS
2223}
2224
a5011a26 2225static int comedi_close(struct inode *inode, struct file *file)
ed9eccbe 2226{
a5011a26
HS
2227 const unsigned minor = iminor(inode);
2228 struct comedi_subdevice *s = NULL;
ed9eccbe 2229 int i;
a5011a26
HS
2230 struct comedi_device_file_info *dev_file_info;
2231 struct comedi_device *dev;
2232 dev_file_info = comedi_get_device_file_info(minor);
ed9eccbe 2233
a5011a26
HS
2234 if (dev_file_info == NULL)
2235 return -ENODEV;
2236 dev = dev_file_info->device;
2237 if (dev == NULL)
2238 return -ENODEV;
ed9eccbe 2239
a5011a26
HS
2240 mutex_lock(&dev->mutex);
2241
2242 if (dev->subdevices) {
2243 for (i = 0; i < dev->n_subdevices; i++) {
2244 s = dev->subdevices + i;
2245
2246 if (s->busy == file)
2247 do_cancel(dev, s);
2248 if (s->lock == file)
2249 s->lock = NULL;
2250 }
ed9eccbe 2251 }
a5011a26
HS
2252 if (dev->attached && dev->use_count == 1 && dev->close)
2253 dev->close(dev);
2254
2255 module_put(THIS_MODULE);
2256 if (dev->attached)
2257 module_put(dev->driver->module);
2258
2259 dev->use_count--;
2260
2261 mutex_unlock(&dev->mutex);
2262
2263 if (file->f_flags & FASYNC)
2264 comedi_fasync(-1, file, 0);
ed9eccbe
DS
2265
2266 return 0;
2267}
2268
a5011a26 2269static int comedi_fasync(int fd, struct file *file, int on)
ed9eccbe 2270{
a5011a26
HS
2271 const unsigned minor = iminor(file->f_dentry->d_inode);
2272 struct comedi_device_file_info *dev_file_info;
2273 struct comedi_device *dev;
2274 dev_file_info = comedi_get_device_file_info(minor);
ed9eccbe 2275
a5011a26
HS
2276 if (dev_file_info == NULL)
2277 return -ENODEV;
2278 dev = dev_file_info->device;
476b8477 2279 if (dev == NULL)
a5011a26
HS
2280 return -ENODEV;
2281
2282 return fasync_helper(fd, file, on, &dev->async_queue);
ed9eccbe
DS
2283}
2284
a5011a26
HS
2285const struct file_operations comedi_fops = {
2286 .owner = THIS_MODULE,
2287 .unlocked_ioctl = comedi_unlocked_ioctl,
2288 .compat_ioctl = comedi_compat_ioctl,
2289 .open = comedi_open,
2290 .release = comedi_close,
2291 .read = comedi_read,
2292 .write = comedi_write,
2293 .mmap = comedi_mmap,
2294 .poll = comedi_poll,
2295 .fasync = comedi_fasync,
2296 .llseek = noop_llseek,
2297};
2298
2299struct class *comedi_class;
2300static struct cdev comedi_cdev;
2301
2302static void comedi_cleanup_legacy_minors(void)
ed9eccbe 2303{
ed9eccbe
DS
2304 unsigned i;
2305
a5011a26 2306 for (i = 0; i < comedi_num_legacy_minors; i++)
883db3d9 2307 comedi_free_board_minor(i);
ed9eccbe
DS
2308}
2309
a5011a26 2310static int __init comedi_init(void)
ed9eccbe 2311{
a5011a26
HS
2312 int i;
2313 int retval;
ed9eccbe 2314
a5011a26
HS
2315 printk(KERN_INFO "comedi: version " COMEDI_RELEASE
2316 " - http://www.comedi.org\n");
ed9eccbe 2317
a5011a26
HS
2318 if (comedi_num_legacy_minors < 0 ||
2319 comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
2320 printk(KERN_ERR "comedi: error: invalid value for module "
2321 "parameter \"comedi_num_legacy_minors\". Valid values "
2322 "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
2323 return -EINVAL;
ed9eccbe 2324 }
c43435d7 2325
a5011a26
HS
2326 /*
2327 * comedi is unusable if both comedi_autoconfig and
2328 * comedi_num_legacy_minors are zero, so we might as well adjust the
2329 * defaults in that case
2330 */
2331 if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
2332 comedi_num_legacy_minors = 16;
c43435d7 2333
a5011a26
HS
2334 memset(comedi_file_info_table, 0,
2335 sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
ed9eccbe 2336
a5011a26
HS
2337 retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2338 COMEDI_NUM_MINORS, "comedi");
2339 if (retval)
2340 return -EIO;
2341 cdev_init(&comedi_cdev, &comedi_fops);
2342 comedi_cdev.owner = THIS_MODULE;
2343 kobject_set_name(&comedi_cdev.kobj, "comedi");
2344 if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) {
2345 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2346 COMEDI_NUM_MINORS);
2347 return -EIO;
883db3d9 2348 }
a5011a26
HS
2349 comedi_class = class_create(THIS_MODULE, "comedi");
2350 if (IS_ERR(comedi_class)) {
2351 printk(KERN_ERR "comedi: failed to create class");
2352 cdev_del(&comedi_cdev);
2353 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2354 COMEDI_NUM_MINORS);
2355 return PTR_ERR(comedi_class);
883db3d9 2356 }
a5011a26
HS
2357
2358 /* XXX requires /proc interface */
2359 comedi_proc_init();
2360
2361 /* create devices files for legacy/manual use */
2362 for (i = 0; i < comedi_num_legacy_minors; i++) {
2363 int minor;
2364 minor = comedi_alloc_board_minor(NULL);
2365 if (minor < 0) {
2366 comedi_cleanup_legacy_minors();
2367 cdev_del(&comedi_cdev);
2368 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
2369 COMEDI_NUM_MINORS);
2370 return minor;
2371 }
883db3d9 2372 }
a5011a26
HS
2373
2374 return 0;
ed9eccbe
DS
2375}
2376
a5011a26 2377static void __exit comedi_cleanup(void)
ed9eccbe 2378{
a5011a26 2379 int i;
ed9eccbe 2380
a5011a26
HS
2381 comedi_cleanup_legacy_minors();
2382 for (i = 0; i < COMEDI_NUM_MINORS; ++i)
2383 BUG_ON(comedi_file_info_table[i]);
ed9eccbe 2384
a5011a26
HS
2385 class_destroy(comedi_class);
2386 cdev_del(&comedi_cdev);
2387 unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS);
ed9eccbe 2388
a5011a26 2389 comedi_proc_cleanup();
ed9eccbe
DS
2390}
2391
a5011a26
HS
2392module_init(comedi_init);
2393module_exit(comedi_cleanup);
ed9eccbe 2394
a5011a26
HS
2395void comedi_error(const struct comedi_device *dev, const char *s)
2396{
2397 printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
2398 dev->driver->driver_name, s);
ed9eccbe 2399}
a5011a26 2400EXPORT_SYMBOL(comedi_error);
883db3d9 2401
a5011a26 2402void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
883db3d9 2403{
a5011a26
HS
2404 struct comedi_async *async = s->async;
2405 unsigned runflags = 0;
2406 unsigned runflags_mask = 0;
883db3d9 2407
a5011a26 2408 /* DPRINTK("comedi_event 0x%x\n",mask); */
883db3d9 2409
a5011a26
HS
2410 if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0)
2411 return;
2412
2413 if (s->
2414 async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR |
2415 COMEDI_CB_OVERFLOW)) {
2416 runflags_mask |= SRF_RUNNING;
883db3d9 2417 }
a5011a26
HS
2418 /* remember if an error event has occurred, so an error
2419 * can be returned the next time the user does a read() */
2420 if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) {
2421 runflags_mask |= SRF_ERROR;
2422 runflags |= SRF_ERROR;
883db3d9 2423 }
a5011a26
HS
2424 if (runflags_mask) {
2425 /*sets SRF_ERROR and SRF_RUNNING together atomically */
2426 comedi_set_subdevice_runflags(s, runflags_mask, runflags);
883db3d9
FMH
2427 }
2428
a5011a26
HS
2429 if (async->cb_mask & s->async->events) {
2430 if (comedi_get_subdevice_runflags(s) & SRF_USER) {
2431 wake_up_interruptible(&async->wait_head);
2432 if (s->subdev_flags & SDF_CMD_READ)
2433 kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
2434 if (s->subdev_flags & SDF_CMD_WRITE)
2435 kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
2436 } else {
2437 if (async->cb_func)
2438 async->cb_func(s->async->events, async->cb_arg);
2439 }
2440 }
2441 s->async->events = 0;
883db3d9 2442}
a5011a26 2443EXPORT_SYMBOL(comedi_event);
883db3d9 2444
a5011a26 2445unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
883db3d9 2446{
a5011a26
HS
2447 unsigned long flags;
2448 unsigned runflags;
883db3d9 2449
a5011a26
HS
2450 spin_lock_irqsave(&s->spin_lock, flags);
2451 runflags = s->runflags;
2452 spin_unlock_irqrestore(&s->spin_lock, flags);
2453 return runflags;
883db3d9 2454}
a5011a26 2455EXPORT_SYMBOL(comedi_get_subdevice_runflags);
883db3d9 2456
a5011a26 2457static int is_device_busy(struct comedi_device *dev)
883db3d9 2458{
a5011a26
HS
2459 struct comedi_subdevice *s;
2460 int i;
883db3d9 2461
a5011a26
HS
2462 if (!dev->attached)
2463 return 0;
883db3d9 2464
a5011a26
HS
2465 for (i = 0; i < dev->n_subdevices; i++) {
2466 s = dev->subdevices + i;
2467 if (s->busy)
2468 return 1;
2469 if (s->async && s->async->mmap_count)
2470 return 1;
883db3d9 2471 }
883db3d9 2472
a5011a26 2473 return 0;
883db3d9
FMH
2474}
2475
a5011a26
HS
2476static void comedi_device_init(struct comedi_device *dev)
2477{
2478 memset(dev, 0, sizeof(struct comedi_device));
2479 spin_lock_init(&dev->spinlock);
2480 mutex_init(&dev->mutex);
2481 dev->minor = -1;
2482}
883db3d9 2483
a5011a26 2484static void comedi_device_cleanup(struct comedi_device *dev)
883db3d9 2485{
a5011a26
HS
2486 if (dev == NULL)
2487 return;
2488 mutex_lock(&dev->mutex);
2489 comedi_device_detach(dev);
2490 mutex_unlock(&dev->mutex);
2491 mutex_destroy(&dev->mutex);
2492}
2493
2494int comedi_alloc_board_minor(struct device *hardware_device)
2495{
2496 struct comedi_device_file_info *info;
2497 struct device *csdev;
2498 unsigned i;
2499 int retval;
2500
2501 info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2502 if (info == NULL)
2503 return -ENOMEM;
2504 info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
2505 if (info->device == NULL) {
2506 kfree(info);
2507 return -ENOMEM;
2508 }
2509 info->hardware_device = hardware_device;
2510 comedi_device_init(info->device);
2511 spin_lock(&comedi_file_info_table_lock);
2512 for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
2513 if (comedi_file_info_table[i] == NULL) {
2514 comedi_file_info_table[i] = info;
2515 break;
2516 }
2517 }
2518 spin_unlock(&comedi_file_info_table_lock);
2519 if (i == COMEDI_NUM_BOARD_MINORS) {
2520 comedi_device_cleanup(info->device);
2521 kfree(info->device);
2522 kfree(info);
2523 printk(KERN_ERR
2524 "comedi: error: "
2525 "ran out of minor numbers for board device files.\n");
2526 return -EBUSY;
2527 }
2528 info->device->minor = i;
2529 csdev = device_create(comedi_class, hardware_device,
2530 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
2531 if (!IS_ERR(csdev))
2532 info->device->class_dev = csdev;
2533 dev_set_drvdata(csdev, info);
883db3d9 2534
a5011a26
HS
2535 retval = sysfs_create_group(&csdev->kobj, &comedi_sysfs_files);
2536 if (retval) {
2537 printk(KERN_ERR
2538 "comedi: failed to create sysfs attribute files\n");
2539 comedi_free_board_minor(i);
2540 return retval;
883db3d9 2541 }
883db3d9 2542
a5011a26 2543 return i;
883db3d9
FMH
2544}
2545
a5011a26 2546void comedi_free_board_minor(unsigned minor)
883db3d9 2547{
a5011a26 2548 struct comedi_device_file_info *info;
883db3d9 2549
a5011a26
HS
2550 BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
2551 spin_lock(&comedi_file_info_table_lock);
2552 info = comedi_file_info_table[minor];
2553 comedi_file_info_table[minor] = NULL;
2554 spin_unlock(&comedi_file_info_table_lock);
883db3d9 2555
a5011a26
HS
2556 if (info) {
2557 struct comedi_device *dev = info->device;
2558 if (dev) {
2559 if (dev->class_dev) {
2560 device_destroy(comedi_class,
2561 MKDEV(COMEDI_MAJOR, dev->minor));
2562 }
2563 comedi_device_cleanup(dev);
2564 kfree(dev);
2565 }
2566 kfree(info);
883db3d9 2567 }
883db3d9
FMH
2568}
2569
a5011a26 2570int comedi_find_board_minor(struct device *hardware_device)
883db3d9 2571{
a5011a26
HS
2572 int minor;
2573 struct comedi_device_file_info *info;
883db3d9 2574
a5011a26
HS
2575 for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
2576 spin_lock(&comedi_file_info_table_lock);
2577 info = comedi_file_info_table[minor];
2578 if (info && info->hardware_device == hardware_device) {
2579 spin_unlock(&comedi_file_info_table_lock);
2580 return minor;
2581 }
2582 spin_unlock(&comedi_file_info_table_lock);
883db3d9 2583 }
a5011a26 2584 return -ENODEV;
883db3d9
FMH
2585}
2586
a5011a26
HS
2587int comedi_alloc_subdevice_minor(struct comedi_device *dev,
2588 struct comedi_subdevice *s)
883db3d9 2589{
a5011a26
HS
2590 struct comedi_device_file_info *info;
2591 struct device *csdev;
2592 unsigned i;
2593 int retval;
883db3d9 2594
a5011a26
HS
2595 info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
2596 if (info == NULL)
2597 return -ENOMEM;
2598 info->device = dev;
2599 info->read_subdevice = s;
2600 info->write_subdevice = s;
2601 spin_lock(&comedi_file_info_table_lock);
2602 for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
2603 if (comedi_file_info_table[i] == NULL) {
2604 comedi_file_info_table[i] = info;
2605 break;
2606 }
2607 }
2608 spin_unlock(&comedi_file_info_table_lock);
2609 if (i == COMEDI_NUM_MINORS) {
2610 kfree(info);
2611 printk(KERN_ERR
2612 "comedi: error: "
2613 "ran out of minor numbers for board device files.\n");
2614 return -EBUSY;
2615 }
2616 s->minor = i;
2617 csdev = device_create(comedi_class, dev->class_dev,
2618 MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
2619 dev->minor, (int)(s - dev->subdevices));
2620 if (!IS_ERR(csdev))
2621 s->class_dev = csdev;
2622 dev_set_drvdata(csdev, info);
883db3d9 2623
a5011a26
HS
2624 retval = sysfs_create_group(&csdev->kobj, &comedi_sysfs_files);
2625 if (retval) {
2626 printk(KERN_ERR
2627 "comedi: failed to create sysfs attribute files\n");
2628 comedi_free_subdevice_minor(s);
2629 return retval;
883db3d9 2630 }
883db3d9 2631
a5011a26 2632 return i;
883db3d9
FMH
2633}
2634
a5011a26 2635void comedi_free_subdevice_minor(struct comedi_subdevice *s)
883db3d9 2636{
a5011a26 2637 struct comedi_device_file_info *info;
883db3d9 2638
a5011a26
HS
2639 if (s == NULL)
2640 return;
2641 if (s->minor < 0)
2642 return;
883db3d9 2643
a5011a26
HS
2644 BUG_ON(s->minor >= COMEDI_NUM_MINORS);
2645 BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
883db3d9 2646
a5011a26
HS
2647 spin_lock(&comedi_file_info_table_lock);
2648 info = comedi_file_info_table[s->minor];
2649 comedi_file_info_table[s->minor] = NULL;
2650 spin_unlock(&comedi_file_info_table_lock);
883db3d9 2651
a5011a26
HS
2652 if (s->class_dev) {
2653 device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
2654 s->class_dev = NULL;
883db3d9 2655 }
a5011a26 2656 kfree(info);
883db3d9
FMH
2657}
2658
a5011a26
HS
2659struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
2660{
2661 struct comedi_device_file_info *info;
2662
2663 BUG_ON(minor >= COMEDI_NUM_MINORS);
2664 spin_lock(&comedi_file_info_table_lock);
2665 info = comedi_file_info_table[minor];
2666 spin_unlock(&comedi_file_info_table_lock);
2667 return info;
2668}
2669EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
This page took 0.506984 seconds and 5 git commands to generate.