Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
/*
 * comedidev.h
 * header file for kernel-only structures, variables, and constants
 *
 * COMEDI - Linux Control and Measurement Device Interface
 * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef _COMEDIDEV_H
#define _COMEDIDEV_H

#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <linux/spinlock_types.h>
#include <linux/rwsem.h>
#include <linux/kref.h>

#include "comedi.h"

#define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#define COMEDI_VERSION_CODE COMEDI_VERSION(COMEDI_MAJORVERSION, \
	COMEDI_MINORVERSION, COMEDI_MICROVERSION)
#define COMEDI_RELEASE VERSION

#define COMEDI_NUM_BOARD_MINORS 0x30

/**
 * struct comedi_subdevice - Working data for a COMEDI subdevice
 * @device: COMEDI device to which this subdevice belongs.  (Initialized by
 *	comedi_alloc_subdevices().)
 * @index: Index of this subdevice within device's array of subdevices.
 *	(Initialized by comedi_alloc_subdevices().)
 * @type: Type of subdevice from &enum comedi_subdevice_type.  (Initialized by
 *	the low-level driver.)
 * @n_chan: Number of channels the subdevice supports.  (Initialized by the
 *	low-level driver.)
 * @subdev_flags: Various "SDF" flags indicating aspects of the subdevice to
 *	the COMEDI core and user application.  (Initialized by the low-level
 *	driver.)
 * @len_chanlist: Maximum length of a channel list if the subdevice supports
 *	asynchronous acquisition commands.  (Optionally initialized by the
 *	low-level driver, or changed from 0 to 1 during post-configuration.)
 * @private: Private data pointer which is either set by the low-level driver
 *	itself, or by a call to comedi_alloc_spriv() which allocates storage.
 *	In the latter case, the storage is automatically freed after the
 *	low-level driver's "detach" handler is called for the device.
 *	(Initialized by the low-level driver.)
 * @async: Pointer to &struct comedi_async id the subdevice supports
 *	asynchronous acquisition commands.  (Allocated and initialized during
 *	post-configuration if needed.)
 * @lock: Pointer to a file object that performed a %COMEDI_LOCK ioctl on the
 *	subdevice.  (Initially NULL.)
 * @busy: Pointer to a file object that is performing an asynchronous
 *	acquisition command on the subdevice.  (Initially NULL.)
 * @runflags: Internal flags for use by COMEDI core, mostly indicating whether
 *	an asynchronous acquisition command is running.
 * @spin_lock: Generic spin-lock for use by the COMEDI core and the low-level
 *	driver.  (Initialized by comedi_alloc_subdevices().)
 * @io_bits: Bit-mask indicating the channel directions for a DIO subdevice
 *	with no more than 32 channels.  A '1' at a bit position indicates the
 *	corresponding channel is configured as an output.  (Initialized by the
 *	low-level driver for a DIO subdevice.  Forced to all-outputs during
 *	post-configuration for a digital output subdevice.)
 * @maxdata: If non-zero, this is the maximum raw data value of each channel.
 *	If zero, the maximum data value is channel-specific.  (Initialized by
 *	the low-level driver.)
 * @maxdata_list: If the maximum data value is channel-specific, this points
 *	to an array of maximum data values indexed by channel index.
 *	(Initialized by the low-level driver.)
 * @range_table: If non-NULL, this points to a COMEDI range table for the
 *	subdevice.  If NULL, the range table is channel-specific.  (Initialized
 *	by the low-level driver, will be set to an "invalid" range table during
 *	post-configuration if @range_table and @range_table_list are both
 *	NULL.)
 * @range_table_list: If the COMEDI range table is channel-specific, this
 *	points to an array of pointers to COMEDI range tables indexed by
 *	channel number.  (Initialized by the low-level driver.)
 * @chanlist: Not used.
 * @insn_read: Optional pointer to a handler for the %INSN_READ instruction.
 *	(Initialized by the low-level driver, or set to a default handler
 *	during post-configuration.)
 * @insn_write: Optional pointer to a handler for the %INSN_WRITE instruction.
 *	(Initialized by the low-level driver, or set to a default handler
 *	during post-configuration.)
 * @insn_bits: Optional pointer to a handler for the %INSN_BITS instruction
 *	for a digital input, digital output or digital input/output subdevice.
 *	(Initialized by the low-level driver, or set to a default handler
 *	during post-configuration.)
 * @insn_config: Optional pointer to a handler for the %INSN_CONFIG
 *	instruction.  (Initialized by the low-level driver, or set to a default
 *	handler during post-configuration.)
 * @do_cmd: If the subdevice supports asynchronous acquisition commands, this
 *	points to a handler to set it up in hardware.  (Initialized by the
 *	low-level driver.)
 * @do_cmdtest: If the subdevice supports asynchronous acquisition commands,
 *	this points to a handler used to check and possibly tweak a prospective
 *	acquisition command without setting it up in hardware.  (Initialized by
 *	the low-level driver.)
 * @poll: If the subdevice supports asynchronous acquisition commands, this
 *	is an optional pointer to a handler for the %COMEDI_POLL ioctl which
 *	instructs the low-level driver to synchronize buffers.  (Initialized by
 *	the low-level driver if needed.)
 * @cancel: If the subdevice supports asynchronous acquisition commands, this
 *	points to a handler used to terminate a running command.  (Initialized
 *	by the low-level driver.)
 * @buf_change: If the subdevice supports asynchronous acquisition commands,
 *	this is an optional pointer to a handler that is called when the data
 *	buffer for handling asynchronous commands is allocated or reallocated.
 *	(Initialized by the low-level driver if needed.)
 * @munge: If the subdevice supports asynchronous acquisition commands and
 *	uses DMA to transfer data from the hardware to the acquisition buffer,
 *	this points to a function used to "munge" the data values from the
 *	hardware into the format expected by COMEDI.  (Initialized by the
 *	low-level driver if needed.)
 * @async_dma_dir: If the subdevice supports asynchronous acquisition commands
 *	and uses DMA to transfer data from the hardware to the acquisition
 *	buffer, this sets the DMA direction for the buffer. (initialized to
 *	%DMA_NONE by comedi_alloc_subdevices() and changed by the low-level
 *	driver if necessary.)
 * @state: Handy bit-mask indicating the output states for a DIO or digital
 *	output subdevice with no more than 32 channels. (Initialized by the
 *	low-level driver.)
 * @class_dev: If the subdevice supports asynchronous acquisition commands,
 *	this points to a sysfs comediX_subdY device where X is the minor device
 *	number of the COMEDI device and Y is the subdevice number.  The minor
 *	device number for the sysfs device is allocated dynamically in the
 *	range 48 to 255.  This is used to allow the COMEDI device to be opened
 *	with a different default read or write subdevice.  (Allocated during
 *	post-configuration if needed.)
 * @minor: If @class_dev is set, this is its dynamically allocated minor
 *	device number.  (Set during post-configuration if necessary.)
 * @readback: Optional pointer to memory allocated by
 *	comedi_alloc_subdev_readback() used to hold the values written to
 *	analog output channels so they can be read back.  The storage is
 *	automatically freed after the low-level driver's "detach" handler is
 *	called for the device.  (Initialized by the low-level driver.)
 *
 * This is the main control structure for a COMEDI subdevice.  If the subdevice
 * supports asynchronous acquisition commands, additional information is stored
 * in the &struct comedi_async pointed to by @async.
 *
 * Most of the subdevice is initialized by the low-level driver's "attach" or
 * "auto_attach" handlers but parts of it are initialized by
 * comedi_alloc_subdevices(), and other parts are initialized during
 * post-configuration on return from that handler.
 *
 * A low-level driver that sets @insn_bits for a digital input, digital output,
 * or DIO subdevice may leave @insn_read and @insn_write uninitialized, in
 * which case they will be set to a default handler during post-configuration
 * that uses @insn_bits to emulate the %INSN_READ and %INSN_WRITE instructions.
 */
struct comedi_subdevice {
	struct comedi_device *device;
	int index;
	int type;
	int n_chan;
	int subdev_flags;
	int len_chanlist;	/* maximum length of channel/gain list */

	void *private;

	struct comedi_async *async;

	void *lock;
	void *busy;
	unsigned int runflags;
	spinlock_t spin_lock;	/* generic spin-lock for COMEDI and drivers */

	unsigned int io_bits;

	unsigned int maxdata;	/* if maxdata==0, use list */
	const unsigned int *maxdata_list;	/* list is channel specific */

	const struct comedi_lrange *range_table;
	const struct comedi_lrange *const *range_table_list;

	unsigned int *chanlist;	/* driver-owned chanlist (not used) */

	int (*insn_read)(struct comedi_device *, struct comedi_subdevice *,
			 struct comedi_insn *, unsigned int *);
	int (*insn_write)(struct comedi_device *, struct comedi_subdevice *,
			  struct comedi_insn *, unsigned int *);
	int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *,
			 struct comedi_insn *, unsigned int *);
	int (*insn_config)(struct comedi_device *, struct comedi_subdevice *,
			   struct comedi_insn *, unsigned int *);

	int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *);
	int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *,
			  struct comedi_cmd *);
	int (*poll)(struct comedi_device *, struct comedi_subdevice *);
	int (*cancel)(struct comedi_device *, struct comedi_subdevice *);

	/* called when the buffer changes */
	int (*buf_change)(struct comedi_device *, struct comedi_subdevice *);

	void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s,
		      void *data, unsigned int num_bytes,
		      unsigned int start_chan_index);
	enum dma_data_direction async_dma_dir;

	unsigned int state;

	struct device *class_dev;
	int minor;

	unsigned int *readback;
};

/**
 * struct comedi_buf_page - Describe a page of a COMEDI buffer
 * @virt_addr: Kernel address of page.
 * @dma_addr: DMA address of page if in DMA coherent memory.
 */
struct comedi_buf_page {
	void *virt_addr;
	dma_addr_t dma_addr;
};

/**
 * struct comedi_buf_map - Describe pages in a COMEDI buffer
 * @dma_hw_dev: Low-level hardware &struct device pointer copied from the
 *	COMEDI device's hw_dev member.
 * @page_list: Pointer to array of &struct comedi_buf_page, one for each
 *	page in the buffer.
 * @n_pages: Number of pages in the buffer.
 * @dma_dir: DMA direction used to allocate pages of DMA coherent memory,
 *	or %DMA_NONE if pages allocated from regular memory.
 * @refcount: &struct kref reference counter used to free the buffer.
 *
 * A COMEDI data buffer is allocated as individual pages, either in
 * conventional memory or DMA coherent memory, depending on the attached,
 * low-level hardware device.  (The buffer pages also get mapped into the
 * kernel's contiguous virtual address space pointed to by the 'prealloc_buf'
 * member of &struct comedi_async.)
 *
 * The buffer is normally freed when the COMEDI device is detached from the
 * low-level driver (which may happen due to device removal), but if it happens
 * to be mmapped at the time, the pages cannot be freed until the buffer has
 * been munmapped.  That is what the reference counter is for.  (The virtual
 * address space pointed by 'prealloc_buf' is freed when the COMEDI device is
 * detached.)
 */
struct comedi_buf_map {
	struct device *dma_hw_dev;
	struct comedi_buf_page *page_list;
	unsigned int n_pages;
	enum dma_data_direction dma_dir;
	struct kref refcount;
};

/**
 * struct comedi_async - Control data for asynchronous COMEDI commands
 * @prealloc_buf: Kernel virtual address of allocated acquisition buffer.
 * @prealloc_bufsz: Buffer size (in bytes).
 * @buf_map: Map of buffer pages.
 * @max_bufsize: Maximum allowed buffer size (in bytes).
 * @buf_write_count: "Write completed" count (in bytes, modulo 2**32).
 * @buf_write_alloc_count: "Allocated for writing" count (in bytes,
 *	modulo 2**32).
 * @buf_read_count: "Read completed" count (in bytes, modulo 2**32).
 * @buf_read_alloc_count: "Allocated for reading" count (in bytes,
 *	modulo 2**32).
 * @buf_write_ptr: Buffer position for writer.
 * @buf_read_ptr: Buffer position for reader.
 * @cur_chan: Current position in chanlist for scan (for those drivers that
 *	use it).
 * @scans_done: The number of scans completed.
 * @scan_progress: Amount received or sent for current scan (in bytes).
 * @munge_chan: Current position in chanlist for "munging".
 * @munge_count: "Munge" count (in bytes, modulo 2**32).
 * @munge_ptr: Buffer position for "munging".
 * @events: Bit-vector of events that have occurred.
 * @cmd: Details of comedi command in progress.
 * @wait_head: Task wait queue for file reader or writer.
 * @cb_mask: Bit-vector of events that should wake waiting tasks.
 * @inttrig: Software trigger function for command, or NULL.
 *
 * Note about the ..._count and ..._ptr members:
 *
 * Think of the _Count values being integers of unlimited size, indexing
 * into a buffer of infinite length (though only an advancing portion
 * of the buffer of fixed length prealloc_bufsz is accessible at any
 * time).  Then:
 *
 *   Buf_Read_Count <= Buf_Read_Alloc_Count <= Munge_Count <=
 *   Buf_Write_Count <= Buf_Write_Alloc_Count <=
 *   (Buf_Read_Count + prealloc_bufsz)
 *
 * (Those aren't the actual members, apart from prealloc_bufsz.) When the
 * buffer is reset, those _Count values start at 0 and only increase in value,
 * maintaining the above inequalities until the next time the buffer is
 * reset.  The buffer is divided into the following regions by the inequalities:
 *
 *   [0, Buf_Read_Count):
 *     old region no longer accessible
 *
 *   [Buf_Read_Count, Buf_Read_Alloc_Count):
 *     filled and munged region allocated for reading but not yet read
 *
 *   [Buf_Read_Alloc_Count, Munge_Count):
 *     filled and munged region not yet allocated for reading
 *
 *   [Munge_Count, Buf_Write_Count):
 *     filled region not yet munged
 *
 *   [Buf_Write_Count, Buf_Write_Alloc_Count):
 *     unfilled region allocated for writing but not yet written
 *
 *   [Buf_Write_Alloc_Count, Buf_Read_Count + prealloc_bufsz):
 *     unfilled region not yet allocated for writing
 *
 *   [Buf_Read_Count + prealloc_bufsz, infinity):
 *     unfilled region not yet accessible
 *
 * Data needs to be written into the buffer before it can be read out,
 * and may need to be converted (or "munged") between the two
 * operations.  Extra unfilled buffer space may need to allocated for
 * writing (advancing Buf_Write_Alloc_Count) before new data is written.
 * After writing new data, the newly filled space needs to be released
 * (advancing Buf_Write_Count).  This also results in the new data being
 * "munged" (advancing Munge_Count).  Before data is read out of the
 * buffer, extra space may need to be allocated for reading (advancing
 * Buf_Read_Alloc_Count).  After the data has been read out, the space
 * needs to be released (advancing Buf_Read_Count).
 *
 * The actual members, buf_read_count, buf_read_alloc_count,
 * munge_count, buf_write_count, and buf_write_alloc_count take the
 * value of the corresponding capitalized _Count values modulo 2^32
 * (UINT_MAX+1).  Subtracting a "higher" _count value from a "lower"
 * _count value gives the same answer as subtracting a "higher" _Count
 * value from a lower _Count value because prealloc_bufsz < UINT_MAX+1.
 * The modulo operation is done implicitly.
 *
 * The buf_read_ptr, munge_ptr, and buf_write_ptr members take the value
 * of the corresponding capitalized _Count values modulo prealloc_bufsz.
 * These correspond to byte indices in the physical buffer.  The modulo
 * operation is done by subtracting prealloc_bufsz when the value
 * exceeds prealloc_bufsz (assuming prealloc_bufsz plus the increment is
 * less than or equal to UINT_MAX).
 */
struct comedi_async {
	void *prealloc_buf;
	unsigned int prealloc_bufsz;
	struct comedi_buf_map *buf_map;
	unsigned int max_bufsize;
	unsigned int buf_write_count;
	unsigned int buf_write_alloc_count;
	unsigned int buf_read_count;
	unsigned int buf_read_alloc_count;
	unsigned int buf_write_ptr;
	unsigned int buf_read_ptr;
	unsigned int cur_chan;
	unsigned int scans_done;
	unsigned int scan_progress;
	unsigned int munge_chan;
	unsigned int munge_count;
	unsigned int munge_ptr;
	unsigned int events;
	struct comedi_cmd cmd;
	wait_queue_head_t wait_head;
	unsigned int cb_mask;
	int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s,
		       unsigned int x);
};

/**
 * enum comedi_cb - &struct comedi_async callback "events"
 * @COMEDI_CB_EOS:		end-of-scan
 * @COMEDI_CB_EOA:		end-of-acquisition/output
 * @COMEDI_CB_BLOCK:		data has arrived, wakes up read() / write()
 * @COMEDI_CB_EOBUF:		DEPRECATED: end of buffer
 * @COMEDI_CB_ERROR:		card error during acquisition
 * @COMEDI_CB_OVERFLOW:		buffer overflow/underflow
 * @COMEDI_CB_ERROR_MASK:	events that indicate an error has occurred
 * @COMEDI_CB_CANCEL_MASK:	events that will cancel an async command
 */
enum comedi_cb {
	COMEDI_CB_EOS		= BIT(0),
	COMEDI_CB_EOA		= BIT(1),
	COMEDI_CB_BLOCK		= BIT(2),
	COMEDI_CB_EOBUF		= BIT(3),
	COMEDI_CB_ERROR		= BIT(4),
	COMEDI_CB_OVERFLOW	= BIT(5),
	/* masks */
	COMEDI_CB_ERROR_MASK	= (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW),
	COMEDI_CB_CANCEL_MASK	= (COMEDI_CB_EOA | COMEDI_CB_ERROR_MASK)
};

/**
 * struct comedi_driver - COMEDI driver registration
 * @driver_name: Name of driver.
 * @module: Owning module.
 * @attach: The optional "attach" handler for manually configured COMEDI
 *	devices.
 * @detach: The "detach" handler for deconfiguring COMEDI devices.
 * @auto_attach: The optional "auto_attach" handler for automatically
 *	configured COMEDI devices.
 * @num_names: Optional number of "board names" supported.
 * @board_name: Optional pointer to a pointer to a board name.  The pointer
 *	to a board name is embedded in an element of a driver-defined array
 *	of static, read-only board type information.
 * @offset: Optional size of each element of the driver-defined array of
 *	static, read-only board type information, i.e. the offset between each
 *	pointer to a board name.
 *
 * This is used with comedi_driver_register() and comedi_driver_unregister() to
 * register and unregister a low-level COMEDI driver with the COMEDI core.
 *
 * If @num_names is non-zero, @board_name should be non-NULL, and @offset
 * should be at least sizeof(*board_name).  These are used by the handler for
 * the %COMEDI_DEVCONFIG ioctl to match a hardware device and its driver by
 * board name.  If @num_names is zero, the %COMEDI_DEVCONFIG ioctl matches a
 * hardware device and its driver by driver name.  This is only useful if the
 * @attach handler is set.  If @num_names is non-zero, the driver's @attach
 * handler will be called with the COMEDI device structure's board_ptr member
 * pointing to the matched pointer to a board name within the driver's private
 * array of static, read-only board type information.
 */
struct comedi_driver {
	/* private: */
	struct comedi_driver *next;	/* Next in list of COMEDI drivers. */
	/* public: */
	const char *driver_name;
	struct module *module;
	int (*attach)(struct comedi_device *, struct comedi_devconfig *);
	void (*detach)(struct comedi_device *);
	int (*auto_attach)(struct comedi_device *, unsigned long);
	unsigned int num_names;
	const char *const *board_name;
	int offset;
};

/**
 * struct comedi_device - Working data for a COMEDI device
 * @use_count: Number of open file objects.
 * @driver: Low-level COMEDI driver attached to this COMEDI device.
 * @pacer: Optional pointer to a dynamically allocated acquisition pacer
 *	control.  It is freed automatically after the COMEDI device is
 *	detached from the low-level driver.
 * @private: Optional pointer to private data allocated by the low-level
 *	driver.  It is freed automatically after the COMEDI device is
 *	detached from the low-level driver.
 * @class_dev: Sysfs comediX device.
 * @minor: Minor device number of COMEDI char device (0-47).
 * @detach_count: Counter incremented every time the COMEDI device is detached.
 *	Used for checking a previous attachment is still valid.
 * @hw_dev: Optional pointer to the low-level hardware &struct device.  It is
 *	required for automatically configured COMEDI devices and optional for
 *	COMEDI devices configured by the %COMEDI_DEVCONFIG ioctl, although
 *	the bus-specific COMEDI functions only work if it is set correctly.
 *	It is also passed to dma_alloc_coherent() for COMEDI subdevices that
 *	have their 'async_dma_dir' member set to something other than
 *	%DMA_NONE.
 * @board_name: Pointer to a COMEDI board name or a COMEDI driver name.  When
 *	the low-level driver's "attach" handler is called by the handler for
 *	the %COMEDI_DEVCONFIG ioctl, it either points to a matched board name
 *	string if the 'num_names' member of the &struct comedi_driver is
 *	non-zero, otherwise it points to the low-level driver name string.
 *	When the low-lever driver's "auto_attach" handler is called for an
 *	automatically configured COMEDI device, it points to the low-level
 *	driver name string.  The low-level driver is free to change it in its
 *	"attach" or "auto_attach" handler if it wishes.
 * @board_ptr: Optional pointer to private, read-only board type information in
 *	the low-level driver.  If the 'num_names' member of the &struct
 *	comedi_driver is non-zero, the handler for the %COMEDI_DEVCONFIG ioctl
 *	will point it to a pointer to a matched board name string within the
 *	driver's private array of static, read-only board type information when
 *	calling the driver's "attach" handler.  The low-level driver is free to
 *	change it.
 * @attached: Flag indicating that the COMEDI device is attached to a low-level
 *	driver.
 * @ioenabled: Flag used to indicate that a PCI device has been enabled and
 *	its regions requested.
 * @spinlock: Generic spin-lock for use by the low-level driver.
 * @mutex: Generic mutex for use by the COMEDI core module.
 * @attach_lock: &struct rw_semaphore used to guard against the COMEDI device
 *	being detached while an operation is in progress.  The down_write()
 *	operation is only allowed while @mutex is held and is used when
 *	changing @attached and @detach_count and calling the low-level driver's
 *	"detach" handler.  The down_read() operation is generally used without
 *	holding @mutex.
 * @refcount: &struct kref reference counter for freeing COMEDI device.
 * @n_subdevices: Number of COMEDI subdevices allocated by the low-level
 *	driver for this device.
 * @subdevices: Dynamically allocated array of COMEDI subdevices.
 * @mmio: Optional pointer to a remapped MMIO region set by the low-level
 *	driver.
 * @iobase: Optional base of an I/O port region requested by the low-level
 *	driver.
 * @iolen: Length of I/O port region requested at @iobase.
 * @irq: Optional IRQ number requested by the low-level driver.
 * @read_subdev: Optional pointer to a default COMEDI subdevice operated on by
 *	the read() file operation.  Set by the low-level driver.
 * @write_subdev: Optional pointer to a default COMEDI subdevice operated on by
 *	the write() file operation.  Set by the low-level driver.
 * @async_queue: Storage for fasync_helper().
 * @open: Optional pointer to a function set by the low-level driver to be
 *	called when @use_count changes from 0 to 1.
 * @close: Optional pointer to a function set by the low-level driver to be
 *	called when @use_count changed from 1 to 0.
 *
 * This is the main control data structure for a COMEDI device (as far as the
 * COMEDI core is concerned).  There are two groups of COMEDI devices -
 * "legacy" devices that are configured by the handler for the
 * %COMEDI_DEVCONFIG ioctl, and automatically configured devices resulting
 * from a call to comedi_auto_config() as a result of a bus driver probe in
 * a low-level COMEDI driver.  The "legacy" COMEDI devices are allocated
 * during module initialization if the "comedi_num_legacy_minors" module
 * parameter is non-zero and use minor device numbers from 0 to
 * comedi_num_legacy_minors minus one.  The automatically configured COMEDI
 * devices are allocated on demand and use minor device numbers from
 * comedi_num_legacy_minors to 47.
 */
struct comedi_device {
	int use_count;
	struct comedi_driver *driver;
	struct comedi_8254 *pacer;
	void *private;

	struct device *class_dev;
	int minor;
	unsigned int detach_count;
	struct device *hw_dev;

	const char *board_name;
	const void *board_ptr;
	bool attached:1;
	bool ioenabled:1;
	spinlock_t spinlock;	/* generic spin-lock for low-level driver */
	struct mutex mutex;	/* generic mutex for COMEDI core */
	struct rw_semaphore attach_lock;
	struct kref refcount;

	int n_subdevices;
	struct comedi_subdevice *subdevices;

	/* dumb */
	void __iomem *mmio;
	unsigned long iobase;
	unsigned long iolen;
	unsigned int irq;

	struct comedi_subdevice *read_subdev;
	struct comedi_subdevice *write_subdev;

	struct fasync_struct *async_queue;

	int (*open)(struct comedi_device *dev);
	void (*close)(struct comedi_device *dev);
};

/*
 * function prototypes
 */

void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s);

struct comedi_device *comedi_dev_get_from_minor(unsigned int minor);
int comedi_dev_put(struct comedi_device *dev);

bool comedi_is_subdevice_running(struct comedi_subdevice *s);

void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size);
void comedi_set_spriv_auto_free(struct comedi_subdevice *s);

int comedi_check_chanlist(struct comedi_subdevice *s,
			  int n,
			  unsigned int *chanlist);

/* range stuff */

#define RANGE(a, b)		{(a) * 1e6, (b) * 1e6, 0}
#define RANGE_ext(a, b)		{(a) * 1e6, (b) * 1e6, RF_EXTERNAL}
#define RANGE_mA(a, b)		{(a) * 1e6, (b) * 1e6, UNIT_mA}
#define RANGE_unitless(a, b)	{(a) * 1e6, (b) * 1e6, 0}
#define BIP_RANGE(a)		{-(a) * 1e6, (a) * 1e6, 0}
#define UNI_RANGE(a)		{0, (a) * 1e6, 0}

extern const struct comedi_lrange range_bipolar10;
extern const struct comedi_lrange range_bipolar5;
extern const struct comedi_lrange range_bipolar2_5;
extern const struct comedi_lrange range_unipolar10;
extern const struct comedi_lrange range_unipolar5;
extern const struct comedi_lrange range_unipolar2_5;
extern const struct comedi_lrange range_0_20mA;
extern const struct comedi_lrange range_4_20mA;
extern const struct comedi_lrange range_0_32mA;
extern const struct comedi_lrange range_unknown;

#define range_digital		range_unipolar5

#if __GNUC__ >= 3
#define GCC_ZERO_LENGTH_ARRAY
#else
#define GCC_ZERO_LENGTH_ARRAY 0
#endif

/**
 * struct comedi_lrange - Describes a COMEDI range table
 * @length: Number of entries in the range table.
 * @range: Array of &struct comedi_krange, one for each range.
 *
 * Each element of @range[] describes the minimum and maximum physical range
 * range and the type of units.  Typically, the type of unit is %UNIT_volt
 * (i.e. volts) and the minimum and maximum are in millionths of a volt.
 * There may also be a flag that indicates the minimum and maximum are merely
 * scale factors for an unknown, external reference.
 */
struct comedi_lrange {
	int length;
	struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY];
};

/**
 * comedi_range_is_bipolar() - Test if subdevice range is bipolar
 * @s: COMEDI subdevice.
 * @range: Index of range within a range table.
 *
 * Tests whether a range is bipolar by checking whether its minimum value
 * is negative.
 *
 * Assumes @range is valid.  Does not work for subdevices using a
 * channel-specific range table list.
 *
 * Return:
 *	%true if the range is bipolar.
 *	%false if the range is unipolar.
 */
static inline bool comedi_range_is_bipolar(struct comedi_subdevice *s,
					   unsigned int range)
{
	return s->range_table->range[range].min < 0;
}

/**
 * comedi_range_is_unipolar() - Test if subdevice range is unipolar
 * @s: COMEDI subdevice.
 * @range: Index of range within a range table.
 *
 * Tests whether a range is unipolar by checking whether its minimum value
 * is at least 0.
 *
 * Assumes @range is valid.  Does not work for subdevices using a
 * channel-specific range table list.
 *
 * Return:
 *	%true if the range is unipolar.
 *	%false if the range is bipolar.
 */
static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s,
					    unsigned int range)
{
	return s->range_table->range[range].min >= 0;
}

/**
 * comedi_range_is_external() - Test if subdevice range is external
 * @s: COMEDI subdevice.
 * @range: Index of range within a range table.
 *
 * Tests whether a range is externally reference by checking whether its
 * %RF_EXTERNAL flag is set.
 *
 * Assumes @range is valid.  Does not work for subdevices using a
 * channel-specific range table list.
 *
 * Return:
 *	%true if the range is external.
 *	%false if the range is internal.
 */
static inline bool comedi_range_is_external(struct comedi_subdevice *s,
					    unsigned int range)
{
	return !!(s->range_table->range[range].flags & RF_EXTERNAL);
}

/**
 * comedi_chan_range_is_bipolar() - Test if channel-specific range is bipolar
 * @s: COMEDI subdevice.
 * @chan: The channel number.
 * @range: Index of range within a range table.
 *
 * Tests whether a range is bipolar by checking whether its minimum value
 * is negative.
 *
 * Assumes @chan and @range are valid.  Only works for subdevices with a
 * channel-specific range table list.
 *
 * Return:
 *	%true if the range is bipolar.
 *	%false if the range is unipolar.
 */
static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s,
						unsigned int chan,
						unsigned int range)
{
	return s->range_table_list[chan]->range[range].min < 0;
}

/**
 * comedi_chan_range_is_unipolar() - Test if channel-specific range is unipolar
 * @s: COMEDI subdevice.
 * @chan: The channel number.
 * @range: Index of range within a range table.
 *
 * Tests whether a range is unipolar by checking whether its minimum value
 * is at least 0.
 *
 * Assumes @chan and @range are valid.  Only works for subdevices with a
 * channel-specific range table list.
 *
 * Return:
 *	%true if the range is unipolar.
 *	%false if the range is bipolar.
 */
static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s,
						 unsigned int chan,
						 unsigned int range)
{
	return s->range_table_list[chan]->range[range].min >= 0;
}

/**
 * comedi_chan_range_is_external() - Test if channel-specific range is external
 * @s: COMEDI subdevice.
 * @chan: The channel number.
 * @range: Index of range within a range table.
 *
 * Tests whether a range is externally reference by checking whether its
 * %RF_EXTERNAL flag is set.
 *
 * Assumes @chan and @range are valid.  Only works for subdevices with a
 * channel-specific range table list.
 *
 * Return:
 *	%true if the range is bipolar.
 *	%false if the range is unipolar.
 */
static inline bool comedi_chan_range_is_external(struct comedi_subdevice *s,
						 unsigned int chan,
						 unsigned int range)
{
	return !!(s->range_table_list[chan]->range[range].flags & RF_EXTERNAL);
}

/**
 * comedi_offset_munge() - Convert between offset binary and 2's complement
 * @s: COMEDI subdevice.
 * @val: Value to be converted.
 *
 * Toggles the highest bit of a sample value to toggle between offset binary
 * and 2's complement.  Assumes that @s->maxdata is a power of 2 minus 1.
 *
 * Return: The converted value.
 */
static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s,
					       unsigned int val)
{
	return val ^ s->maxdata ^ (s->maxdata >> 1);
}

/**
 * comedi_bytes_per_sample() - Determine subdevice sample size
 * @s: COMEDI subdevice.
 *
 * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on
 * whether the %SDF_LSAMPL subdevice flag is set or not.
 *
 * Return: The subdevice sample size.
 */
static inline unsigned int comedi_bytes_per_sample(struct comedi_subdevice *s)
{
	return s->subdev_flags & SDF_LSAMPL ? sizeof(int) : sizeof(short);
}

/**
 * comedi_sample_shift() - Determine log2 of subdevice sample size
 * @s: COMEDI subdevice.
 *
 * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on
 * whether the %SDF_LSAMPL subdevice flag is set or not.  The log2 of the
 * sample size will be 2 or 1 and can be used as the right operand of a
 * bit-shift operator to multiply or divide something by the sample size.
 *
 * Return: log2 of the subdevice sample size.
 */
static inline unsigned int comedi_sample_shift(struct comedi_subdevice *s)
{
	return s->subdev_flags & SDF_LSAMPL ? 2 : 1;
}

/**
 * comedi_bytes_to_samples() - Convert a number of bytes to a number of samples
 * @s: COMEDI subdevice.
 * @nbytes: Number of bytes
 *
 * Return: The number of bytes divided by the subdevice sample size.
 */
static inline unsigned int comedi_bytes_to_samples(struct comedi_subdevice *s,
						   unsigned int nbytes)
{
	return nbytes >> comedi_sample_shift(s);
}

/**
 * comedi_samples_to_bytes() - Convert a number of samples to a number of bytes
 * @s: COMEDI subdevice.
 * @nsamples: Number of samples.
 *
 * Return: The number of samples multiplied by the subdevice sample size.
 * (Does not check for arithmetic overflow.)
 */
static inline unsigned int comedi_samples_to_bytes(struct comedi_subdevice *s,
						   unsigned int nsamples)
{
	return nsamples << comedi_sample_shift(s);
}

/**
 * comedi_check_trigger_src() - Trivially validate a comedi_cmd trigger source
 * @src: Pointer to the trigger source to validate.
 * @flags: Bitmask of valid %TRIG_* for the trigger.
 *
 * This is used in "step 1" of the do_cmdtest functions of comedi drivers
 * to validate the comedi_cmd triggers. The mask of the @src against the
 * @flags allows the userspace comedilib to pass all the comedi_cmd
 * triggers as %TRIG_ANY and get back a bitmask of the valid trigger sources.
 *
 * Return:
 *	0 if trigger sources in *@src are all supported.
 *	-EINVAL if any trigger source in *@src is unsupported.
 */
static inline int comedi_check_trigger_src(unsigned int *src,
					   unsigned int flags)
{
	unsigned int orig_src = *src;

	*src = orig_src & flags;
	if (*src == TRIG_INVALID || *src != orig_src)
		return -EINVAL;
	return 0;
}

/**
 * comedi_check_trigger_is_unique() - Make sure a trigger source is unique
 * @src: The trigger source to check.
 *
 * Return:
 *	0 if no more than one trigger source is set.
 *	-EINVAL if more than one trigger source is set.
 */
static inline int comedi_check_trigger_is_unique(unsigned int src)
{
	/* this test is true if more than one _src bit is set */
	if ((src & (src - 1)) != 0)
		return -EINVAL;
	return 0;
}

/**
 * comedi_check_trigger_arg_is() - Trivially validate a trigger argument
 * @arg: Pointer to the trigger arg to validate.
 * @val: The value the argument should be.
 *
 * Forces *@arg to be @val.
 *
 * Return:
 *	0 if *@arg was already @val.
 *	-EINVAL if *@arg differed from @val.
 */
static inline int comedi_check_trigger_arg_is(unsigned int *arg,
					      unsigned int val)
{
	if (*arg != val) {
		*arg = val;
		return -EINVAL;
	}
	return 0;
}

/**
 * comedi_check_trigger_arg_min() - Trivially validate a trigger argument min
 * @arg: Pointer to the trigger arg to validate.
 * @val: The minimum value the argument should be.
 *
 * Forces *@arg to be at least @val, setting it to @val if necessary.
 *
 * Return:
 *	0 if *@arg was already at least @val.
 *	-EINVAL if *@arg was less than @val.
 */
static inline int comedi_check_trigger_arg_min(unsigned int *arg,
					       unsigned int val)
{
	if (*arg < val) {
		*arg = val;
		return -EINVAL;
	}
	return 0;
}

/**
 * comedi_check_trigger_arg_max() - Trivially validate a trigger argument max
 * @arg: Pointer to the trigger arg to validate.
 * @val: The maximum value the argument should be.
 *
 * Forces *@arg to be no more than @val, setting it to @val if necessary.
 *
 * Return:
 *	0 if*@arg was already no more than @val.
 *	-EINVAL if *@arg was greater than @val.
 */
static inline int comedi_check_trigger_arg_max(unsigned int *arg,
					       unsigned int val)
{
	if (*arg > val) {
		*arg = val;
		return -EINVAL;
	}
	return 0;
}

/*
 * Must set dev->hw_dev if you wish to dma directly into comedi's buffer.
 * Also useful for retrieving a previously configured hardware device of
 * known bus type.  Set automatically for auto-configured devices.
 * Automatically set to NULL when detaching hardware device.
 */
int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev);

/**
 * comedi_buf_n_bytes_ready - Determine amount of unread data in buffer
 * @s: COMEDI subdevice.
 *
 * Determines the number of bytes of unread data in the asynchronous
 * acquisition data buffer for a subdevice.  The data in question might not
 * have been fully "munged" yet.
 *
 * Returns: The amount of unread data in bytes.
 */
static inline unsigned int comedi_buf_n_bytes_ready(struct comedi_subdevice *s)
{
	return s->async->buf_write_count - s->async->buf_read_count;
}

unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int n);
unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int n);

unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s);
unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int n);
unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int n);

unsigned int comedi_buf_write_samples(struct comedi_subdevice *s,
				      const void *data, unsigned int nsamples);
unsigned int comedi_buf_read_samples(struct comedi_subdevice *s,
				     void *data, unsigned int nsamples);

/* drivers.c - general comedi driver functions */

#define COMEDI_TIMEOUT_MS	1000

int comedi_timeout(struct comedi_device *, struct comedi_subdevice *,
		   struct comedi_insn *,
		   int (*cb)(struct comedi_device *, struct comedi_subdevice *,
			     struct comedi_insn *, unsigned long context),
		   unsigned long context);

unsigned int comedi_handle_events(struct comedi_device *dev,
				  struct comedi_subdevice *s);

int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
			   struct comedi_insn *, unsigned int *data,
			   unsigned int mask);
unsigned int comedi_dio_update_state(struct comedi_subdevice *,
				     unsigned int *data);
unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s);
unsigned int comedi_nscans_left(struct comedi_subdevice *s,
				unsigned int nscans);
unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
				  unsigned int nsamples);
void comedi_inc_scan_progress(struct comedi_subdevice *s,
			      unsigned int num_bytes);

void *comedi_alloc_devpriv(struct comedi_device *, size_t);
int comedi_alloc_subdevices(struct comedi_device *, int);
int comedi_alloc_subdev_readback(struct comedi_subdevice *);

int comedi_readback_insn_read(struct comedi_device *, struct comedi_subdevice *,
			      struct comedi_insn *, unsigned int *data);

int comedi_load_firmware(struct comedi_device *, struct device *,
			 const char *name,
			 int (*cb)(struct comedi_device *,
				   const u8 *data, size_t size,
				   unsigned long context),
			 unsigned long context);

int __comedi_request_region(struct comedi_device *,
			    unsigned long start, unsigned long len);
int comedi_request_region(struct comedi_device *,
			  unsigned long start, unsigned long len);
void comedi_legacy_detach(struct comedi_device *);

int comedi_auto_config(struct device *, struct comedi_driver *,
		       unsigned long context);
void comedi_auto_unconfig(struct device *);

int comedi_driver_register(struct comedi_driver *);
void comedi_driver_unregister(struct comedi_driver *);

/**
 * module_comedi_driver() - Helper macro for registering a comedi driver
 * @__comedi_driver: comedi_driver struct
 *
 * Helper macro for comedi drivers which do not do anything special in module
 * init/exit. This eliminates a lot of boilerplate. Each module may only use
 * this macro once, and calling it replaces module_init() and module_exit().
 */
#define module_comedi_driver(__comedi_driver) \
	module_driver(__comedi_driver, comedi_driver_register, \
			comedi_driver_unregister)

#endif /* _COMEDIDEV_H */