Merge remote-tracking branch 'upstream' into next
[cascardo/linux.git] / drivers / staging / comedi / drivers.c
1 /*
2     module/drivers.c
3     functions for manipulating drivers
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 #define _GNU_SOURCE
25
26 #define __NO_VERSION__
27 #include <linux/device.h>
28 #include <linux/module.h>
29 #include <linux/pci.h>
30 #include <linux/usb.h>
31 #include <linux/errno.h>
32 #include <linux/kconfig.h>
33 #include <linux/kernel.h>
34 #include <linux/sched.h>
35 #include <linux/fcntl.h>
36 #include <linux/delay.h>
37 #include <linux/ioport.h>
38 #include <linux/mm.h>
39 #include <linux/slab.h>
40 #include <linux/highmem.h>      /* for SuSE brokenness */
41 #include <linux/vmalloc.h>
42 #include <linux/cdev.h>
43 #include <linux/dma-mapping.h>
44 #include <linux/io.h>
45
46 #include "comedidev.h"
47 #include "comedi_internal.h"
48
49 static int postconfig(struct comedi_device *dev);
50 static int insn_rw_emulate_bits(struct comedi_device *dev,
51                                 struct comedi_subdevice *s,
52                                 struct comedi_insn *insn, unsigned int *data);
53 static void *comedi_recognize(struct comedi_driver *driv, const char *name);
54 static void comedi_report_boards(struct comedi_driver *driv);
55 static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s);
56
57 struct comedi_driver *comedi_drivers;
58
59 int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
60 {
61         struct comedi_subdevice *s;
62         int i;
63
64         if (num_subdevices < 1)
65                 return -EINVAL;
66
67         s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL);
68         if (!s)
69                 return -ENOMEM;
70         dev->subdevices = s;
71         dev->n_subdevices = num_subdevices;
72
73         for (i = 0; i < num_subdevices; ++i) {
74                 s = dev->subdevices + i;
75                 s->device = dev;
76                 s->async_dma_dir = DMA_NONE;
77                 spin_lock_init(&s->spin_lock);
78                 s->minor = -1;
79         }
80         return 0;
81 }
82 EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
83
84 static void cleanup_device(struct comedi_device *dev)
85 {
86         int i;
87         struct comedi_subdevice *s;
88
89         if (dev->subdevices) {
90                 for (i = 0; i < dev->n_subdevices; i++) {
91                         s = dev->subdevices + i;
92                         comedi_free_subdevice_minor(s);
93                         if (s->async) {
94                                 comedi_buf_alloc(dev, s, 0);
95                                 kfree(s->async);
96                         }
97                 }
98                 kfree(dev->subdevices);
99                 dev->subdevices = NULL;
100                 dev->n_subdevices = 0;
101         }
102         kfree(dev->private);
103         dev->private = NULL;
104         dev->driver = NULL;
105         dev->board_name = NULL;
106         dev->board_ptr = NULL;
107         dev->iobase = 0;
108         dev->irq = 0;
109         dev->read_subdev = NULL;
110         dev->write_subdev = NULL;
111         dev->open = NULL;
112         dev->close = NULL;
113         comedi_set_hw_dev(dev, NULL);
114 }
115
116 static void __comedi_device_detach(struct comedi_device *dev)
117 {
118         dev->attached = 0;
119         if (dev->driver)
120                 dev->driver->detach(dev);
121         else
122                 printk(KERN_WARNING
123                        "BUG: dev->driver=NULL in comedi_device_detach()\n");
124         cleanup_device(dev);
125 }
126
127 void comedi_device_detach(struct comedi_device *dev)
128 {
129         if (!dev->attached)
130                 return;
131         __comedi_device_detach(dev);
132 }
133
134 /* do a little post-config cleanup */
135 /* called with module refcount incremented, decrements it */
136 static int comedi_device_postconfig(struct comedi_device *dev)
137 {
138         int ret = postconfig(dev);
139         module_put(dev->driver->module);
140         if (ret < 0) {
141                 __comedi_device_detach(dev);
142                 return ret;
143         }
144         if (!dev->board_name) {
145                 printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
146                        dev->board_name);
147                 dev->board_name = "BUG";
148         }
149         smp_wmb();
150         dev->attached = 1;
151         return 0;
152 }
153
154 int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
155 {
156         struct comedi_driver *driv;
157         int ret;
158
159         if (dev->attached)
160                 return -EBUSY;
161
162         for (driv = comedi_drivers; driv; driv = driv->next) {
163                 if (!try_module_get(driv->module)) {
164                         printk(KERN_INFO "comedi: failed to increment module count, skipping\n");
165                         continue;
166                 }
167                 if (driv->num_names) {
168                         dev->board_ptr = comedi_recognize(driv, it->board_name);
169                         if (dev->board_ptr)
170                                 break;
171                 } else if (strcmp(driv->driver_name, it->board_name))
172                         break;
173                 module_put(driv->module);
174         }
175         if (driv == NULL) {
176                 /*  recognize has failed if we get here */
177                 /*  report valid board names before returning error */
178                 for (driv = comedi_drivers; driv; driv = driv->next) {
179                         if (!try_module_get(driv->module)) {
180                                 printk(KERN_INFO
181                                        "comedi: failed to increment module count\n");
182                                 continue;
183                         }
184                         comedi_report_boards(driv);
185                         module_put(driv->module);
186                 }
187                 return -EIO;
188         }
189         /* initialize dev->driver here so
190          * comedi_error() can be called from attach */
191         dev->driver = driv;
192         ret = driv->attach(dev, it);
193         if (ret < 0) {
194                 module_put(dev->driver->module);
195                 __comedi_device_detach(dev);
196                 return ret;
197         }
198         return comedi_device_postconfig(dev);
199 }
200
201 int comedi_driver_register(struct comedi_driver *driver)
202 {
203         driver->next = comedi_drivers;
204         comedi_drivers = driver;
205
206         return 0;
207 }
208 EXPORT_SYMBOL(comedi_driver_register);
209
210 int comedi_driver_unregister(struct comedi_driver *driver)
211 {
212         struct comedi_driver *prev;
213         int i;
214
215         /* check for devices using this driver */
216         for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
217                 struct comedi_device_file_info *dev_file_info =
218                     comedi_get_device_file_info(i);
219                 struct comedi_device *dev;
220
221                 if (dev_file_info == NULL)
222                         continue;
223                 dev = dev_file_info->device;
224
225                 mutex_lock(&dev->mutex);
226                 if (dev->attached && dev->driver == driver) {
227                         if (dev->use_count)
228                                 printk(KERN_WARNING "BUG! detaching device with use_count=%d\n",
229                                                 dev->use_count);
230                         comedi_device_detach(dev);
231                 }
232                 mutex_unlock(&dev->mutex);
233         }
234
235         if (comedi_drivers == driver) {
236                 comedi_drivers = driver->next;
237                 return 0;
238         }
239
240         for (prev = comedi_drivers; prev->next; prev = prev->next) {
241                 if (prev->next == driver) {
242                         prev->next = driver->next;
243                         return 0;
244                 }
245         }
246         return -EINVAL;
247 }
248 EXPORT_SYMBOL(comedi_driver_unregister);
249
250 static int postconfig(struct comedi_device *dev)
251 {
252         int i;
253         struct comedi_subdevice *s;
254         struct comedi_async *async = NULL;
255         int ret;
256
257         for (i = 0; i < dev->n_subdevices; i++) {
258                 s = dev->subdevices + i;
259
260                 if (s->type == COMEDI_SUBD_UNUSED)
261                         continue;
262
263                 if (s->len_chanlist == 0)
264                         s->len_chanlist = 1;
265
266                 if (s->do_cmd) {
267                         unsigned int buf_size;
268
269                         BUG_ON((s->subdev_flags & (SDF_CMD_READ |
270                                                    SDF_CMD_WRITE)) == 0);
271                         BUG_ON(!s->do_cmdtest);
272
273                         async =
274                             kzalloc(sizeof(struct comedi_async), GFP_KERNEL);
275                         if (async == NULL) {
276                                 printk(KERN_INFO
277                                        "failed to allocate async struct\n");
278                                 return -ENOMEM;
279                         }
280                         init_waitqueue_head(&async->wait_head);
281                         async->subdevice = s;
282                         s->async = async;
283
284                         async->max_bufsize =
285                                 comedi_default_buf_maxsize_kb * 1024;
286                         buf_size = comedi_default_buf_size_kb * 1024;
287                         if (buf_size > async->max_bufsize)
288                                 buf_size = async->max_bufsize;
289
290                         async->prealloc_buf = NULL;
291                         async->prealloc_bufsz = 0;
292                         if (comedi_buf_alloc(dev, s, buf_size) < 0) {
293                                 printk(KERN_INFO "Buffer allocation failed\n");
294                                 return -ENOMEM;
295                         }
296                         if (s->buf_change) {
297                                 ret = s->buf_change(dev, s, buf_size);
298                                 if (ret < 0)
299                                         return ret;
300                         }
301                         comedi_alloc_subdevice_minor(dev, s);
302                 }
303
304                 if (!s->range_table && !s->range_table_list)
305                         s->range_table = &range_unknown;
306
307                 if (!s->insn_read && s->insn_bits)
308                         s->insn_read = insn_rw_emulate_bits;
309                 if (!s->insn_write && s->insn_bits)
310                         s->insn_write = insn_rw_emulate_bits;
311
312                 if (!s->insn_read)
313                         s->insn_read = insn_inval;
314                 if (!s->insn_write)
315                         s->insn_write = insn_inval;
316                 if (!s->insn_bits)
317                         s->insn_bits = insn_inval;
318                 if (!s->insn_config)
319                         s->insn_config = insn_inval;
320
321                 if (!s->poll)
322                         s->poll = poll_invalid;
323         }
324
325         return 0;
326 }
327
328 /*
329  * Generic recognize function for drivers that register their supported
330  * board names.
331  *
332  * 'driv->board_name' points to a 'const char *' member within the
333  * zeroth element of an array of some private board information
334  * structure, say 'struct foo_board' containing a member 'const char
335  * *board_name' that is initialized to point to a board name string that
336  * is one of the candidates matched against this function's 'name'
337  * parameter.
338  *
339  * 'driv->offset' is the size of the private board information
340  * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is
341  * the length of the array of private board information structures.
342  *
343  * If one of the board names in the array of private board information
344  * structures matches the name supplied to this function, the function
345  * returns a pointer to the pointer to the board name, otherwise it
346  * returns NULL.  The return value ends up in the 'board_ptr' member of
347  * a 'struct comedi_device' that the low-level comedi driver's
348  * 'attach()' hook can convert to a point to a particular element of its
349  * array of private board information structures by subtracting the
350  * offset of the member that points to the board name.  (No subtraction
351  * is required if the board name pointer is the first member of the
352  * private board information structure, which is generally the case.)
353  */
354 static void *comedi_recognize(struct comedi_driver *driv, const char *name)
355 {
356         char **name_ptr = (char **)driv->board_name;
357         int i;
358
359         for (i = 0; i < driv->num_names; i++) {
360                 if (strcmp(*name_ptr, name) == 0)
361                         return name_ptr;
362                 name_ptr = (void *)name_ptr + driv->offset;
363         }
364
365         return NULL;
366 }
367
368 static void comedi_report_boards(struct comedi_driver *driv)
369 {
370         unsigned int i;
371         const char *const *name_ptr;
372
373         printk(KERN_INFO "comedi: valid board names for %s driver are:\n",
374                driv->driver_name);
375
376         name_ptr = driv->board_name;
377         for (i = 0; i < driv->num_names; i++) {
378                 printk(KERN_INFO " %s\n", *name_ptr);
379                 name_ptr = (const char **)((char *)name_ptr + driv->offset);
380         }
381
382         if (driv->num_names == 0)
383                 printk(KERN_INFO " %s\n", driv->driver_name);
384 }
385
386 static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
387 {
388         return -EINVAL;
389 }
390
391 int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
392                struct comedi_insn *insn, unsigned int *data)
393 {
394         return -EINVAL;
395 }
396
397 static int insn_rw_emulate_bits(struct comedi_device *dev,
398                                 struct comedi_subdevice *s,
399                                 struct comedi_insn *insn, unsigned int *data)
400 {
401         struct comedi_insn new_insn;
402         int ret;
403         static const unsigned channels_per_bitfield = 32;
404
405         unsigned chan = CR_CHAN(insn->chanspec);
406         const unsigned base_bitfield_channel =
407             (chan < channels_per_bitfield) ? 0 : chan;
408         unsigned int new_data[2];
409         memset(new_data, 0, sizeof(new_data));
410         memset(&new_insn, 0, sizeof(new_insn));
411         new_insn.insn = INSN_BITS;
412         new_insn.chanspec = base_bitfield_channel;
413         new_insn.n = 2;
414         new_insn.data = new_data;
415         new_insn.subdev = insn->subdev;
416
417         if (insn->insn == INSN_WRITE) {
418                 if (!(s->subdev_flags & SDF_WRITABLE))
419                         return -EINVAL;
420                 new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */
421                 new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel))
422                               : 0; /* bits */
423         }
424
425         ret = s->insn_bits(dev, s, &new_insn, new_data);
426         if (ret < 0)
427                 return ret;
428
429         if (insn->insn == INSN_READ)
430                 data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1;
431
432         return 1;
433 }
434
435 int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
436                      unsigned long new_size)
437 {
438         struct comedi_async *async = s->async;
439
440         /* Round up new_size to multiple of PAGE_SIZE */
441         new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
442
443         /* if no change is required, do nothing */
444         if (async->prealloc_buf && async->prealloc_bufsz == new_size)
445                 return 0;
446
447         /*  deallocate old buffer */
448         if (async->prealloc_buf) {
449                 vunmap(async->prealloc_buf);
450                 async->prealloc_buf = NULL;
451                 async->prealloc_bufsz = 0;
452         }
453         if (async->buf_page_list) {
454                 unsigned i;
455                 for (i = 0; i < async->n_buf_pages; ++i) {
456                         if (async->buf_page_list[i].virt_addr) {
457                                 clear_bit(PG_reserved,
458                                         &(virt_to_page(async->buf_page_list[i].
459                                                         virt_addr)->flags));
460                                 if (s->async_dma_dir != DMA_NONE) {
461                                         dma_free_coherent(dev->hw_dev,
462                                                           PAGE_SIZE,
463                                                           async->
464                                                           buf_page_list
465                                                           [i].virt_addr,
466                                                           async->
467                                                           buf_page_list
468                                                           [i].dma_addr);
469                                 } else {
470                                         free_page((unsigned long)
471                                                   async->buf_page_list[i].
472                                                   virt_addr);
473                                 }
474                         }
475                 }
476                 vfree(async->buf_page_list);
477                 async->buf_page_list = NULL;
478                 async->n_buf_pages = 0;
479         }
480         /*  allocate new buffer */
481         if (new_size) {
482                 unsigned i = 0;
483                 unsigned n_pages = new_size >> PAGE_SHIFT;
484                 struct page **pages = NULL;
485
486                 async->buf_page_list =
487                     vzalloc(sizeof(struct comedi_buf_page) * n_pages);
488                 if (async->buf_page_list)
489                         pages = vmalloc(sizeof(struct page *) * n_pages);
490
491                 if (pages) {
492                         for (i = 0; i < n_pages; i++) {
493                                 if (s->async_dma_dir != DMA_NONE) {
494                                         async->buf_page_list[i].virt_addr =
495                                             dma_alloc_coherent(dev->hw_dev,
496                                                                PAGE_SIZE,
497                                                                &async->
498                                                                buf_page_list
499                                                                [i].dma_addr,
500                                                                GFP_KERNEL |
501                                                                __GFP_COMP);
502                                 } else {
503                                         async->buf_page_list[i].virt_addr =
504                                             (void *)
505                                             get_zeroed_page(GFP_KERNEL);
506                                 }
507                                 if (async->buf_page_list[i].virt_addr == NULL)
508                                         break;
509
510                                 set_bit(PG_reserved,
511                                         &(virt_to_page(async->buf_page_list[i].
512                                                         virt_addr)->flags));
513                                 pages[i] = virt_to_page(async->buf_page_list[i].
514                                                                 virt_addr);
515                         }
516                 }
517                 if (i == n_pages) {
518                         async->prealloc_buf =
519 #ifdef PAGE_KERNEL_NOCACHE
520                             vmap(pages, n_pages, VM_MAP, PAGE_KERNEL_NOCACHE);
521 #else
522                             vmap(pages, n_pages, VM_MAP, PAGE_KERNEL);
523 #endif
524                 }
525                 vfree(pages);
526
527                 if (async->prealloc_buf == NULL) {
528                         /* Some allocation failed above. */
529                         if (async->buf_page_list) {
530                                 for (i = 0; i < n_pages; i++) {
531                                         if (async->buf_page_list[i].virt_addr ==
532                                             NULL) {
533                                                 break;
534                                         }
535                                         clear_bit(PG_reserved,
536                                                 &(virt_to_page(async->
537                                                         buf_page_list[i].
538                                                         virt_addr)->flags));
539                                         if (s->async_dma_dir != DMA_NONE) {
540                                                 dma_free_coherent(dev->hw_dev,
541                                                                   PAGE_SIZE,
542                                                                   async->
543                                                                   buf_page_list
544                                                                   [i].virt_addr,
545                                                                   async->
546                                                                   buf_page_list
547                                                                   [i].dma_addr);
548                                         } else {
549                                                 free_page((unsigned long)
550                                                           async->buf_page_list
551                                                           [i].virt_addr);
552                                         }
553                                 }
554                                 vfree(async->buf_page_list);
555                                 async->buf_page_list = NULL;
556                         }
557                         return -ENOMEM;
558                 }
559                 async->n_buf_pages = n_pages;
560         }
561         async->prealloc_bufsz = new_size;
562
563         return 0;
564 }
565
566 /* munging is applied to data by core as it passes between user
567  * and kernel space */
568 static unsigned int comedi_buf_munge(struct comedi_async *async,
569                                      unsigned int num_bytes)
570 {
571         struct comedi_subdevice *s = async->subdevice;
572         unsigned int count = 0;
573         const unsigned num_sample_bytes = bytes_per_sample(s);
574
575         if (s->munge == NULL || (async->cmd.flags & CMDF_RAWDATA)) {
576                 async->munge_count += num_bytes;
577                 BUG_ON((int)(async->munge_count - async->buf_write_count) > 0);
578                 return num_bytes;
579         }
580         /* don't munge partial samples */
581         num_bytes -= num_bytes % num_sample_bytes;
582         while (count < num_bytes) {
583                 int block_size;
584
585                 block_size = num_bytes - count;
586                 if (block_size < 0) {
587                         printk(KERN_WARNING
588                                "%s: %s: bug! block_size is negative\n",
589                                __FILE__, __func__);
590                         break;
591                 }
592                 if ((int)(async->munge_ptr + block_size -
593                           async->prealloc_bufsz) > 0)
594                         block_size = async->prealloc_bufsz - async->munge_ptr;
595
596                 s->munge(s->device, s, async->prealloc_buf + async->munge_ptr,
597                          block_size, async->munge_chan);
598
599                 smp_wmb();      /* barrier insures data is munged in buffer
600                                  * before munge_count is incremented */
601
602                 async->munge_chan += block_size / num_sample_bytes;
603                 async->munge_chan %= async->cmd.chanlist_len;
604                 async->munge_count += block_size;
605                 async->munge_ptr += block_size;
606                 async->munge_ptr %= async->prealloc_bufsz;
607                 count += block_size;
608         }
609         BUG_ON((int)(async->munge_count - async->buf_write_count) > 0);
610         return count;
611 }
612
613 unsigned int comedi_buf_write_n_available(struct comedi_async *async)
614 {
615         unsigned int free_end;
616         unsigned int nbytes;
617
618         if (async == NULL)
619                 return 0;
620
621         free_end = async->buf_read_count + async->prealloc_bufsz;
622         nbytes = free_end - async->buf_write_alloc_count;
623         nbytes -= nbytes % bytes_per_sample(async->subdevice);
624         /* barrier insures the read of buf_read_count in this
625            query occurs before any following writes to the buffer which
626            might be based on the return value from this query.
627          */
628         smp_mb();
629         return nbytes;
630 }
631
632 /* allocates chunk for the writer from free buffer space */
633 unsigned int comedi_buf_write_alloc(struct comedi_async *async,
634                                     unsigned int nbytes)
635 {
636         unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
637
638         if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0)
639                 nbytes = free_end - async->buf_write_alloc_count;
640
641         async->buf_write_alloc_count += nbytes;
642         /* barrier insures the read of buf_read_count above occurs before
643            we write data to the write-alloc'ed buffer space */
644         smp_mb();
645         return nbytes;
646 }
647 EXPORT_SYMBOL(comedi_buf_write_alloc);
648
649 /* allocates nothing unless it can completely fulfill the request */
650 unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async,
651                                            unsigned int nbytes)
652 {
653         unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
654
655         if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0)
656                 nbytes = 0;
657
658         async->buf_write_alloc_count += nbytes;
659         /* barrier insures the read of buf_read_count above occurs before
660            we write data to the write-alloc'ed buffer space */
661         smp_mb();
662         return nbytes;
663 }
664
665 /* transfers a chunk from writer to filled buffer space */
666 unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes)
667 {
668         if ((int)(async->buf_write_count + nbytes -
669                   async->buf_write_alloc_count) > 0) {
670                 printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n");
671                 nbytes = async->buf_write_alloc_count - async->buf_write_count;
672         }
673         async->buf_write_count += nbytes;
674         async->buf_write_ptr += nbytes;
675         comedi_buf_munge(async, async->buf_write_count - async->munge_count);
676         if (async->buf_write_ptr >= async->prealloc_bufsz)
677                 async->buf_write_ptr %= async->prealloc_bufsz;
678
679         return nbytes;
680 }
681 EXPORT_SYMBOL(comedi_buf_write_free);
682
683 /* allocates a chunk for the reader from filled (and munged) buffer space */
684 unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes)
685 {
686         if ((int)(async->buf_read_alloc_count + nbytes - async->munge_count) >
687             0) {
688                 nbytes = async->munge_count - async->buf_read_alloc_count;
689         }
690         async->buf_read_alloc_count += nbytes;
691         /* barrier insures read of munge_count occurs before we actually read
692            data out of buffer */
693         smp_rmb();
694         return nbytes;
695 }
696 EXPORT_SYMBOL(comedi_buf_read_alloc);
697
698 /* transfers control of a chunk from reader to free buffer space */
699 unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes)
700 {
701         /* barrier insures data has been read out of
702          * buffer before read count is incremented */
703         smp_mb();
704         if ((int)(async->buf_read_count + nbytes -
705                   async->buf_read_alloc_count) > 0) {
706                 printk(KERN_INFO
707                        "comedi: attempted to read-free more bytes than have been read-allocated.\n");
708                 nbytes = async->buf_read_alloc_count - async->buf_read_count;
709         }
710         async->buf_read_count += nbytes;
711         async->buf_read_ptr += nbytes;
712         async->buf_read_ptr %= async->prealloc_bufsz;
713         return nbytes;
714 }
715 EXPORT_SYMBOL(comedi_buf_read_free);
716
717 void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
718                           const void *data, unsigned int num_bytes)
719 {
720         unsigned int write_ptr = async->buf_write_ptr + offset;
721
722         if (write_ptr >= async->prealloc_bufsz)
723                 write_ptr %= async->prealloc_bufsz;
724
725         while (num_bytes) {
726                 unsigned int block_size;
727
728                 if (write_ptr + num_bytes > async->prealloc_bufsz)
729                         block_size = async->prealloc_bufsz - write_ptr;
730                 else
731                         block_size = num_bytes;
732
733                 memcpy(async->prealloc_buf + write_ptr, data, block_size);
734
735                 data += block_size;
736                 num_bytes -= block_size;
737
738                 write_ptr = 0;
739         }
740 }
741 EXPORT_SYMBOL(comedi_buf_memcpy_to);
742
743 void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
744                             void *dest, unsigned int nbytes)
745 {
746         void *src;
747         unsigned int read_ptr = async->buf_read_ptr + offset;
748
749         if (read_ptr >= async->prealloc_bufsz)
750                 read_ptr %= async->prealloc_bufsz;
751
752         while (nbytes) {
753                 unsigned int block_size;
754
755                 src = async->prealloc_buf + read_ptr;
756
757                 if (nbytes >= async->prealloc_bufsz - read_ptr)
758                         block_size = async->prealloc_bufsz - read_ptr;
759                 else
760                         block_size = nbytes;
761
762                 memcpy(dest, src, block_size);
763                 nbytes -= block_size;
764                 dest += block_size;
765                 read_ptr = 0;
766         }
767 }
768 EXPORT_SYMBOL(comedi_buf_memcpy_from);
769
770 unsigned int comedi_buf_read_n_available(struct comedi_async *async)
771 {
772         unsigned num_bytes;
773
774         if (async == NULL)
775                 return 0;
776         num_bytes = async->munge_count - async->buf_read_count;
777         /* barrier insures the read of munge_count in this
778            query occurs before any following reads of the buffer which
779            might be based on the return value from this query.
780          */
781         smp_rmb();
782         return num_bytes;
783 }
784 EXPORT_SYMBOL(comedi_buf_read_n_available);
785
786 int comedi_buf_get(struct comedi_async *async, short *x)
787 {
788         unsigned int n = comedi_buf_read_n_available(async);
789
790         if (n < sizeof(short))
791                 return 0;
792         comedi_buf_read_alloc(async, sizeof(short));
793         *x = *(short *)(async->prealloc_buf + async->buf_read_ptr);
794         comedi_buf_read_free(async, sizeof(short));
795         return 1;
796 }
797 EXPORT_SYMBOL(comedi_buf_get);
798
799 int comedi_buf_put(struct comedi_async *async, short x)
800 {
801         unsigned int n = comedi_buf_write_alloc_strict(async, sizeof(short));
802
803         if (n < sizeof(short)) {
804                 async->events |= COMEDI_CB_ERROR;
805                 return 0;
806         }
807         *(short *)(async->prealloc_buf + async->buf_write_ptr) = x;
808         comedi_buf_write_free(async, sizeof(short));
809         return 1;
810 }
811 EXPORT_SYMBOL(comedi_buf_put);
812
813 void comedi_reset_async_buf(struct comedi_async *async)
814 {
815         async->buf_write_alloc_count = 0;
816         async->buf_write_count = 0;
817         async->buf_read_alloc_count = 0;
818         async->buf_read_count = 0;
819
820         async->buf_write_ptr = 0;
821         async->buf_read_ptr = 0;
822
823         async->cur_chan = 0;
824         async->scan_progress = 0;
825         async->munge_chan = 0;
826         async->munge_count = 0;
827         async->munge_ptr = 0;
828
829         async->events = 0;
830 }
831
832 static int
833 comedi_auto_config_helper(struct device *hardware_device,
834                           struct comedi_driver *driver,
835                           int (*attach_wrapper) (struct comedi_device *,
836                                                  void *), void *context)
837 {
838         int minor;
839         struct comedi_device_file_info *dev_file_info;
840         struct comedi_device *comedi_dev;
841         int ret;
842
843         if (!comedi_autoconfig)
844                 return 0;
845
846         minor = comedi_alloc_board_minor(hardware_device);
847         if (minor < 0)
848                 return minor;
849
850         dev_file_info = comedi_get_device_file_info(minor);
851         comedi_dev = dev_file_info->device;
852
853         mutex_lock(&comedi_dev->mutex);
854         if (comedi_dev->attached)
855                 ret = -EBUSY;
856         else if (!try_module_get(driver->module)) {
857                 printk(KERN_INFO "comedi: failed to increment module count\n");
858                 ret = -EIO;
859         } else {
860                 /* set comedi_dev->driver here for attach wrapper */
861                 comedi_dev->driver = driver;
862                 ret = (*attach_wrapper)(comedi_dev, context);
863                 if (ret < 0) {
864                         module_put(driver->module);
865                         __comedi_device_detach(comedi_dev);
866                 } else {
867                         ret = comedi_device_postconfig(comedi_dev);
868                 }
869         }
870         mutex_unlock(&comedi_dev->mutex);
871
872         if (ret < 0)
873                 comedi_free_board_minor(minor);
874         return ret;
875 }
876
877 static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context)
878 {
879         struct comedi_devconfig *it = context;
880         struct comedi_driver *driv = dev->driver;
881
882         if (driv->num_names) {
883                 /* look for generic board entry matching driver name, which
884                  * has already been copied to it->board_name */
885                 dev->board_ptr = comedi_recognize(driv, it->board_name);
886                 if (dev->board_ptr == NULL) {
887                         printk(KERN_WARNING
888                                "comedi: auto config failed to find board entry"
889                                " '%s' for driver '%s'\n", it->board_name,
890                                driv->driver_name);
891                         comedi_report_boards(driv);
892                         return -EINVAL;
893                 }
894         }
895         return driv->attach(dev, it);
896 }
897
898 static int comedi_auto_config(struct device *hardware_device,
899                               struct comedi_driver *driver, const int *options,
900                               unsigned num_options)
901 {
902         struct comedi_devconfig it;
903
904         memset(&it, 0, sizeof(it));
905         strncpy(it.board_name, driver->driver_name, COMEDI_NAMELEN);
906         it.board_name[COMEDI_NAMELEN - 1] = '\0';
907         BUG_ON(num_options > COMEDI_NDEVCONFOPTS);
908         memcpy(it.options, options, num_options * sizeof(int));
909         return comedi_auto_config_helper(hardware_device, driver,
910                                          comedi_auto_config_wrapper, &it);
911 }
912
913 static void comedi_auto_unconfig(struct device *hardware_device)
914 {
915         int minor;
916
917         if (hardware_device == NULL)
918                 return;
919         minor = comedi_find_board_minor(hardware_device);
920         if (minor < 0)
921                 return;
922         BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
923         comedi_free_board_minor(minor);
924 }
925
926 /**
927  * comedi_pci_enable() - Enable the PCI device and request the regions.
928  * @pdev: pci_dev struct
929  * @res_name: name for the requested reqource
930  */
931 int comedi_pci_enable(struct pci_dev *pdev, const char *res_name)
932 {
933         int rc;
934
935         rc = pci_enable_device(pdev);
936         if (rc < 0)
937                 return rc;
938
939         rc = pci_request_regions(pdev, res_name);
940         if (rc < 0)
941                 pci_disable_device(pdev);
942
943         return rc;
944 }
945 EXPORT_SYMBOL_GPL(comedi_pci_enable);
946
947 /**
948  * comedi_pci_disable() - Release the regions and disable the PCI device.
949  * @pdev: pci_dev struct
950  *
951  * This must be matched with a previous successful call to comedi_pci_enable().
952  */
953 void comedi_pci_disable(struct pci_dev *pdev)
954 {
955         pci_release_regions(pdev);
956         pci_disable_device(pdev);
957 }
958 EXPORT_SYMBOL_GPL(comedi_pci_disable);
959
960 static int comedi_old_pci_auto_config(struct pci_dev *pcidev,
961                                       struct comedi_driver *driver)
962 {
963         int options[2];
964
965         /*  pci bus */
966         options[0] = pcidev->bus->number;
967         /*  pci slot */
968         options[1] = PCI_SLOT(pcidev->devfn);
969
970         return comedi_auto_config(&pcidev->dev, driver,
971                                   options, ARRAY_SIZE(options));
972 }
973
974 static int comedi_pci_attach_wrapper(struct comedi_device *dev, void *pcidev)
975 {
976         return dev->driver->attach_pci(dev, pcidev);
977 }
978
979 static int comedi_new_pci_auto_config(struct pci_dev *pcidev,
980                                       struct comedi_driver *driver)
981 {
982         return comedi_auto_config_helper(&pcidev->dev, driver,
983                                          comedi_pci_attach_wrapper, pcidev);
984 }
985
986 int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver)
987 {
988
989         if (driver->attach_pci)
990                 return comedi_new_pci_auto_config(pcidev, driver);
991         else
992                 return comedi_old_pci_auto_config(pcidev, driver);
993 }
994 EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
995
996 void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
997 {
998         comedi_auto_unconfig(&pcidev->dev);
999 }
1000 EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
1001
1002 int comedi_pci_driver_register(struct comedi_driver *comedi_driver,
1003                 struct pci_driver *pci_driver)
1004 {
1005         int ret;
1006
1007         ret = comedi_driver_register(comedi_driver);
1008         if (ret < 0)
1009                 return ret;
1010
1011         /* FIXME: Remove this test after auditing all comedi pci drivers */
1012         if (!pci_driver->name)
1013                 pci_driver->name = comedi_driver->driver_name;
1014
1015         ret = pci_register_driver(pci_driver);
1016         if (ret < 0) {
1017                 comedi_driver_unregister(comedi_driver);
1018                 return ret;
1019         }
1020
1021         return 0;
1022 }
1023 EXPORT_SYMBOL_GPL(comedi_pci_driver_register);
1024
1025 void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver,
1026                 struct pci_driver *pci_driver)
1027 {
1028         pci_unregister_driver(pci_driver);
1029         comedi_driver_unregister(comedi_driver);
1030 }
1031 EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister);
1032
1033 #if IS_ENABLED(CONFIG_USB)
1034
1035 static int comedi_old_usb_auto_config(struct usb_interface *intf,
1036                                       struct comedi_driver *driver)
1037 {
1038         return comedi_auto_config(&intf->dev, driver, NULL, 0);
1039 }
1040
1041 static int comedi_usb_attach_wrapper(struct comedi_device *dev, void *intf)
1042 {
1043         return dev->driver->attach_usb(dev, intf);
1044 }
1045
1046 static int comedi_new_usb_auto_config(struct usb_interface *intf,
1047                                       struct comedi_driver *driver)
1048 {
1049         return comedi_auto_config_helper(&intf->dev, driver,
1050                                          comedi_usb_attach_wrapper, intf);
1051 }
1052
1053 int comedi_usb_auto_config(struct usb_interface *intf,
1054                            struct comedi_driver *driver)
1055 {
1056         BUG_ON(intf == NULL);
1057         if (driver->attach_usb)
1058                 return comedi_new_usb_auto_config(intf, driver);
1059         else
1060                 return comedi_old_usb_auto_config(intf, driver);
1061 }
1062 EXPORT_SYMBOL_GPL(comedi_usb_auto_config);
1063
1064 void comedi_usb_auto_unconfig(struct usb_interface *intf)
1065 {
1066         BUG_ON(intf == NULL);
1067         comedi_auto_unconfig(&intf->dev);
1068 }
1069 EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig);
1070
1071 int comedi_usb_driver_register(struct comedi_driver *comedi_driver,
1072                 struct usb_driver *usb_driver)
1073 {
1074         int ret;
1075
1076         ret = comedi_driver_register(comedi_driver);
1077         if (ret < 0)
1078                 return ret;
1079
1080         ret = usb_register(usb_driver);
1081         if (ret < 0) {
1082                 comedi_driver_unregister(comedi_driver);
1083                 return ret;
1084         }
1085
1086         return 0;
1087 }
1088 EXPORT_SYMBOL_GPL(comedi_usb_driver_register);
1089
1090 void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver,
1091                 struct usb_driver *usb_driver)
1092 {
1093         usb_deregister(usb_driver);
1094         comedi_driver_unregister(comedi_driver);
1095 }
1096 EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister);
1097
1098 #endif