Pārlūkot izejas kodu

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6: (714 commits)
  Staging: sxg: slicoss: Specify the license for Sahara SXG and Slicoss drivers
  Staging: serqt_usb: fix build due to proc tty changes
  Staging: serqt_usb: fix checkpatch errors
  Staging: serqt_usb: add TODO file
  Staging: serqt_usb: Lindent the code
  Staging: add USB serial Quatech driver
  staging: document that the wifi staging drivers a bit better
  Staging: echo cleanup
  Staging: BUG to BUG_ON changes
  Staging: remove some pointless conditionals before kfree_skb()
  Staging: line6: fix build error, select SND_RAWMIDI
  Staging: line6: fix checkpatch errors in variax.c
  Staging: line6: fix checkpatch errors in toneport.c
  Staging: line6: fix checkpatch errors in pcm.c
  Staging: line6: fix checkpatch errors in midibuf.c
  Staging: line6: fix checkpatch errors in midi.c
  Staging: line6: fix checkpatch errors in dumprequest.c
  Staging: line6: fix checkpatch errors in driver.c
  Staging: line6: fix checkpatch errors in audio.c
  Staging: line6: fix checkpatch errors in pod.c
  ...
Linus Torvalds 16 gadi atpakaļ
vecāks
revīzija
3516c6a8dc
100 mainītis faili ar 47653 papildinājumiem un 830 dzēšanām
  1. 70 0
      Documentation/filesystems/pohmelfs/design_notes.txt
  2. 86 0
      Documentation/filesystems/pohmelfs/info.txt
  3. 227 0
      Documentation/filesystems/pohmelfs/network_protocol.txt
  4. 22 0
      drivers/staging/Kconfig
  5. 11 0
      drivers/staging/Makefile
  6. 7 7
      drivers/staging/agnx/agnx.h
  7. 10 11
      drivers/staging/agnx/debug.h
  8. 37 38
      drivers/staging/agnx/pci.c
  9. 16 16
      drivers/staging/agnx/phy.c
  10. 11 12
      drivers/staging/agnx/rf.c
  11. 10 11
      drivers/staging/agnx/sta.c
  12. 1 1
      drivers/staging/agnx/sta.h
  13. 6 6
      drivers/staging/agnx/table.c
  14. 116 100
      drivers/staging/agnx/xmit.c
  15. 41 39
      drivers/staging/altpciechdma/altpciechdma.c
  16. 15 3
      drivers/staging/android/binder.c
  17. 4 4
      drivers/staging/android/ram_console.c
  18. 86 63
      drivers/staging/asus_oled/asus_oled.c
  19. 7 2
      drivers/staging/at76_usb/TODO
  20. 10 11
      drivers/staging/at76_usb/at76_usb.c
  21. 87 0
      drivers/staging/at76_usb/at76_usb.h
  22. 9 0
      drivers/staging/b3dfg/Kconfig
  23. 1 0
      drivers/staging/b3dfg/Makefile
  24. 4 0
      drivers/staging/b3dfg/TODO
  25. 1119 0
      drivers/staging/b3dfg/b3dfg.c
  26. 14 0
      drivers/staging/comedi/Kconfig
  27. 34 49
      drivers/staging/comedi/comedi.h
  28. 59 69
      drivers/staging/comedi/comedi_compat32.c
  29. 159 134
      drivers/staging/comedi/comedi_fops.c
  30. 1 0
      drivers/staging/comedi/comedi_fops.h
  31. 7 5
      drivers/staging/comedi/comedi_ksyms.c
  32. 4 5
      drivers/staging/comedi/comedi_rt.h
  33. 97 105
      drivers/staging/comedi/comedidev.h
  34. 56 58
      drivers/staging/comedi/comedilib.h
  35. 108 79
      drivers/staging/comedi/drivers.c
  36. 420 0
      drivers/staging/comedi/drivers/8253.h
  37. 442 0
      drivers/staging/comedi/drivers/8255.c
  38. 57 0
      drivers/staging/comedi/drivers/8255.h
  39. 111 2
      drivers/staging/comedi/drivers/Makefile
  40. 149 0
      drivers/staging/comedi/drivers/acl7225b.c
  41. 1047 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c
  42. 73 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h
  43. 2032 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
  44. 74 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h
  45. 1020 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
  46. 46 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h
  47. 5363 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
  48. 271 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h
  49. 861 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
  50. 47 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h
  51. 3588 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
  52. 76 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h
  53. 848 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
  54. 43 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h
  55. 2049 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
  56. 57 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h
  57. 1038 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
  58. 44 0
      drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h
  59. 203 0
      drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c
  60. 27 0
      drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h
  61. 476 0
      drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h
  62. 3062 0
      drivers/staging/comedi/drivers/addi-data/addi_common.c
  63. 462 0
      drivers/staging/comedi/drivers/addi-data/addi_common.h
  64. 1158 0
      drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
  65. 457 0
      drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h
  66. 1265 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
  67. 71 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h
  68. 600 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c
  69. 123 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h
  70. 285 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c
  71. 63 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h
  72. 3045 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
  73. 165 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h
  74. 542 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c
  75. 64 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h
  76. 1105 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c
  77. 119 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h
  78. 780 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c
  79. 94 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.h
  80. 460 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c
  81. 70 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h
  82. 579 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c
  83. 81 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h
  84. 549 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c
  85. 61 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h
  86. 2697 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
  87. 241 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h
  88. 3642 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
  89. 187 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h
  90. 742 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
  91. 94 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h
  92. 1691 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c
  93. 62 0
      drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.h
  94. 5 0
      drivers/staging/comedi/drivers/addi_apci_035.c
  95. 3 0
      drivers/staging/comedi/drivers/addi_apci_1032.c
  96. 3 0
      drivers/staging/comedi/drivers/addi_apci_1500.c
  97. 3 0
      drivers/staging/comedi/drivers/addi_apci_1516.c
  98. 3 0
      drivers/staging/comedi/drivers/addi_apci_1564.c
  99. 3 0
      drivers/staging/comedi/drivers/addi_apci_16xx.c
  100. 3 0
      drivers/staging/comedi/drivers/addi_apci_1710.c

+ 70 - 0
Documentation/filesystems/pohmelfs/design_notes.txt

@@ -0,0 +1,70 @@
+POHMELFS: Parallel Optimized Host Message Exchange Layered File System.
+
+		Evgeniy Polyakov <zbr@ioremap.net>
+
+Homepage: http://www.ioremap.net/projects/pohmelfs
+
+POHMELFS first began as a network filesystem with coherent local data and
+metadata caches but is now evolving into a parallel distributed filesystem.
+
+Main features of this FS include:
+ * Locally coherent cache for data and metadata with (potentially) byte-range locks.
+	Since all Linux filesystems lock the whole inode during writing, algorithm
+	is very simple and does not use byte-ranges, although they are sent in
+	locking messages.
+ * Completely async processing of all events except creation of hard and symbolic
+	links, and rename events.
+	Object creation and data reading and writing are processed asynchronously.
+ * Flexible object architecture optimized for network processing.
+	Ability to create long paths to objects and remove arbitrarily huge
+	directories with a single network command.
+	(like removing the whole kernel tree via a single network command).
+ * Very high performance.
+ * Fast and scalable multithreaded userspace server. Being in userspace it works
+	with any underlying filesystem and still is much faster than async in-kernel NFS one.
+ * Client is able to switch between different servers (if one goes down, client
+	automatically reconnects to second and so on).
+ * Transactions support. Full failover for all operations.
+	Resending transactions to different servers on timeout or error.
+ * Read request (data read, directory listing, lookup requests) balancing between multiple servers.
+ * Write requests are replicated to multiple servers and completed only when all of them are acked.
+ * Ability to add and/or remove servers from the working set at run-time.
+ * Strong authentification and possible data encryption in network channel.
+ * Extended attributes support.
+
+POHMELFS is based on transactions, which are potentially long-standing objects that live
+in the client's memory. Each transaction contains all the information needed to process a given
+command (or set of commands, which is frequently used during data writing: single transactions
+can contain creation and data writing commands). Transactions are committed by all the servers
+to which they are sent and, in case of failures, are eventually resent or dropped with an error.
+For example, reading will return an error if no servers are available.
+
+POHMELFS uses a asynchronous approach to data processing. Courtesy of transactions, it is
+possible to detach replies from requests and, if the command requires data to be received, the
+caller sleeps waiting for it. Thus, it is possible to issue multiple read commands to different
+servers and async threads will pick up replies in parallel, find appropriate transactions in the
+system and put the data where it belongs (like the page or inode cache).
+
+The main feature of POHMELFS is writeback data and the metadata cache.
+Only a few non-performance critical operations use the write-through cache and
+are synchronous: hard and symbolic link creation, and object rename. Creation,
+removal of objects and data writing are asynchronous and are sent to
+the server during system writeback. Only one writer at a time is allowed for any
+given inode, which is guarded by an appropriate locking protocol.
+Because of this feature, POHMELFS is extremely fast at metadata intensive
+workloads and can fully utilize the bandwidth to the servers when doing bulk
+data transfers.
+
+POHMELFS clients operate with a working set of servers and are capable of balancing read-only
+operations (like lookups or directory listings) between them.
+Administrators can add or remove servers from the set at run-time via special commands (described
+in Documentation/pohmelfs/info.txt file). Writes are replicated to all servers.
+
+POHMELFS is capable of full data channel encryption and/or strong crypto hashing.
+One can select any kernel supported cipher, encryption mode, hash type and operation mode
+(hmac or digest). It is also possible to use both or neither (default). Crypto configuration
+is checked during mount time and, if the server does not support it, appropriate capabilities
+will be disabled or mount will fail (if 'crypto_fail_unsupported' mount option is specified).
+Crypto performance heavily depends on the number of crypto threads, which asynchronously perform
+crypto operations and send the resulting data to server or submit it up the stack. This number
+can be controlled via a mount option.

+ 86 - 0
Documentation/filesystems/pohmelfs/info.txt

@@ -0,0 +1,86 @@
+POHMELFS usage information.
+
+Mount options:
+idx=%u
+ Each mountpoint is associated with a special index via this option.
+ Administrator can add or remove servers from the given index, so all mounts,
+ which were attached to it, are updated.
+ Default it is 0.
+
+trans_scan_timeout=%u
+ This timeout, expressed in milliseconds, specifies time to scan transaction
+ trees looking for stale requests, which have to be resent, or if number of
+ retries exceed specified limit, dropped with error.
+ Default is 5 seconds.
+
+drop_scan_timeout=%u
+ Internal timeout, expressed in milliseconds, which specifies how frequently
+ inodes marked to be dropped are freed. It also specifies how frequently
+ the system checks that servers have to be added or removed from current working set.
+ Default is 1 second.
+
+wait_on_page_timeout=%u
+ Number of milliseconds to wait for reply from remote server for data reading command.
+ If this timeout is exceeded, reading returns an error.
+ Default is 5 seconds.
+
+trans_retries=%u
+ This is the number of times that a transaction will be resent to a server that did
+ not answer for the last @trans_scan_timeout milliseconds.
+ When the number of resends exceeds this limit, the transaction is completed with error.
+ Default is 5 resends.
+
+crypto_thread_num=%u
+ Number of crypto processing threads. Threads are used both for RX and TX traffic.
+ Default is 2, or no threads if crypto operations are not supported.
+
+trans_max_pages=%u
+ Maximum number of pages in a single transaction. This parameter also controls
+ the number of pages,  allocated for crypto processing (each crypto thread has
+ pool of pages, the number of which is equal to 'trans_max_pages'.
+ Default is 100 pages.
+
+crypto_fail_unsupported
+ If specified, mount will fail if the server does not support requested crypto operations.
+ By default mount will disable non-matching crypto operations.
+
+mcache_timeout=%u
+ Maximum number of milliseconds to wait for the mcache objects to be processed.
+ Mcache includes locks (given lock should be granted by server), attributes (they should be
+ fully received in the given timeframe).
+ Default is 5 seconds.
+
+Usage examples.
+
+Add (or remove if it already exists) server server1.net:1025 into the working set with index $idx
+with appropriate hash algorithm and key file and cipher algorithm, mode and key file:
+$cfg -a server1.net -p 1025 -i $idx -K $hash_key -k $cipher_key
+
+Mount filesystem with given index $idx to /mnt mountpoint.
+Client will connect to all servers specified in the working set via previous command:
+mount -t pohmel -o idx=$idx q /mnt
+
+One can add or remove servers from working set after mounting too.
+
+
+Server installation.
+
+Creating a server, which listens at port 1025 and 0.0.0.0 address.
+Working root directory (note, that server chroots there, so you have to have appropriate permissions)
+is set to /mnt, server will negotiate hash/cipher with client, in case client requested it, there
+are appropriate key files.
+Number of working threads is set to 10.
+
+# ./fserver -a 0.0.0.0 -p 1025 -r /mnt -w 10 -K hash_key -k cipher_key
+
+ -A 6			 - listen on ipv6 address. Default: Disabled.
+ -r root                 - path to root directory. Default: /tmp.
+ -a addr                 - listen address. Default: 0.0.0.0.
+ -p port                 - listen port. Default: 1025.
+ -w workers              - number of workers per connected client. Default: 1.
+ -K file		 - hash key size. Default: none.
+ -k file		 - cipher key size. Default: none.
+ -h                      - this help.
+
+Number of worker threads specifies how many workers will be created for each client.
+Bulk single-client transafers usually are better handled with smaller number (like 1-3).

+ 227 - 0
Documentation/filesystems/pohmelfs/network_protocol.txt

@@ -0,0 +1,227 @@
+POHMELFS network protocol.
+
+Basic structure used in network communication is following command:
+
+struct netfs_cmd
+{
+	__u16			cmd;	/* Command number */
+	__u16			csize;	/* Attached crypto information size */
+	__u16			cpad;	/* Attached padding size */
+	__u16			ext;	/* External flags */
+	__u32			size;	/* Size of the attached data */
+	__u32			trans;	/* Transaction id */
+	__u64			id;	/* Object ID to operate on. Used for feedback.*/
+	__u64			start;	/* Start of the object. */
+	__u64			iv;	/* IV sequence */
+	__u8			data[0];
+};
+
+Commands can be embedded into transaction command (which in turn has own command),
+so one can extend protocol as needed without breaking backward compatibility as long
+as old commands are supported. All string lengths include tail 0 byte.
+
+All commans are transfered over the network in big-endian. CPU endianess is used at the end peers.
+
+@cmd - command number, which specifies command to be processed. Following
+	commands are used currently:
+
+	NETFS_READDIR	= 1,	/* Read directory for given inode number */
+	NETFS_READ_PAGE,	/* Read data page from the server */
+	NETFS_WRITE_PAGE,	/* Write data page to the server */
+	NETFS_CREATE,		/* Create directory entry */
+	NETFS_REMOVE,		/* Remove directory entry */
+	NETFS_LOOKUP,		/* Lookup single object */
+	NETFS_LINK,		/* Create a link */
+	NETFS_TRANS,		/* Transaction */
+	NETFS_OPEN,		/* Open intent */
+	NETFS_INODE_INFO,	/* Metadata cache coherency synchronization message */
+	NETFS_PAGE_CACHE,	/* Page cache invalidation message */
+	NETFS_READ_PAGES,	/* Read multiple contiguous pages in one go */
+	NETFS_RENAME,		/* Rename object */
+	NETFS_CAPABILITIES,	/* Capabilities of the client, for example supported crypto */
+	NETFS_LOCK,		/* Distributed lock message */
+	NETFS_XATTR_SET,	/* Set extended attribute */
+	NETFS_XATTR_GET,	/* Get extended attribute */
+
+@ext - external flags. Used by different commands to specify some extra arguments
+	like partial size of the embedded objects or creation flags.
+
+@size - size of the attached data. For NETFS_READ_PAGE and NETFS_READ_PAGES no data is attached,
+	but size of the requested data is incorporated here. It does not include size of the command
+	header (struct netfs_cmd) itself.
+
+@id - id of the object this command operates on. Each command can use it for own purpose.
+
+@start - start of the object this command operates on. Each command can use it for own purpose.
+
+@csize, @cpad - size and padding size of the (attached if needed) crypto information.
+
+Command specifications.
+
+@NETFS_READDIR
+This command is used to sync content of the remote dir to the client.
+
+@ext - length of the path to object.
+@size - the same.
+@id - local inode number of the directory to read.
+@start - zero.
+
+
+@NETFS_READ_PAGE
+This command is used to read data from remote server.
+Data size does not exceed local page cache size.
+
+@id - inode number.
+@start - first byte offset.
+@size - number of bytes to read plus length of the path to object.
+@ext - object path length.
+
+
+@NETFS_CREATE
+Used to create object.
+It does not require that all directories on top of the object were
+already created, it will create them automatically. Each object has
+associated @netfs_path_entry data structure, which contains creation
+mode (permissions and type) and length of the name as long as name itself.
+
+@start - 0
+@size - size of the all data structures needed to create a path
+@id - local inode number
+@ext - 0
+
+
+@NETFS_REMOVE
+Used to remove object.
+
+@ext - length of the path to object.
+@size - the same.
+@id - local inode number.
+@start - zero.
+
+
+@NETFS_LOOKUP
+Lookup information about object on server.
+
+@ext - length of the path to object.
+@size - the same.
+@id - local inode number of the directory to look object in.
+@start - local inode number of the object to look at.
+
+
+@NETFS_LINK
+Create hard of symlink.
+Command is sent as "object_path|target_path".
+
+@size - size of the above string.
+@id - parent local inode number.
+@start - 1 for symlink, 0 for hardlink.
+@ext - size of the "object_path" above.
+
+
+@NETFS_TRANS
+Transaction header.
+
+@size - incorporates all embedded command sizes including theirs header sizes.
+@start - transaction generation number - unique id used to find transaction.
+@ext - transaction flags. Unused at the moment.
+@id - 0.
+
+
+@NETFS_OPEN
+Open intent for given transaction.
+
+@id - local inode number.
+@start - 0.
+@size - path length to the object.
+@ext - open flags (O_RDWR and so on).
+
+
+@NETFS_INODE_INFO
+Metadata update command.
+It is sent to servers when attributes of the object are changed and received
+when data or metadata were updated. It operates with the following structure:
+
+struct netfs_inode_info
+{
+	unsigned int		mode;
+	unsigned int		nlink;
+	unsigned int		uid;
+	unsigned int		gid;
+	unsigned int		blocksize;
+	unsigned int		padding;
+	__u64			ino;
+	__u64			blocks;
+	__u64			rdev;
+	__u64			size;
+	__u64			version;
+};
+
+It effectively mirrors stat(2) returned data.
+
+
+@ext - path length to the object.
+@size - the same plus size of the netfs_inode_info structure.
+@id - local inode number.
+@start - 0.
+
+
+@NETFS_PAGE_CACHE
+Command is only received by clients. It contains information about
+page to be marked as not up-to-date.
+
+@id - client's inode number.
+@start - last byte of the page to be invalidated. If it is not equal to
+	current inode size, it will be vmtruncated().
+@size - 0
+@ext - 0
+
+
+@NETFS_READ_PAGES
+Used to read multiple contiguous pages in one go.
+
+@start - first byte of the contiguous region to read.
+@size - contains of two fields: lower 8 bits are used to represent page cache shift
+	used by client, another 3 bytes are used to get number of pages.
+@id - local inode number.
+@ext - path length to the object.
+
+
+@NETFS_RENAME
+Used to rename object.
+Attached data is formed into following string: "old_path|new_path".
+
+@id - local inode number.
+@start - parent inode number.
+@size - length of the above string.
+@ext - length of the old path part.
+
+
+@NETFS_CAPABILITIES
+Used to exchange crypto capabilities with server.
+If crypto capabilities are not supported by server, then client will disable it
+or fail (if 'crypto_fail_unsupported' mount options was specified).
+
+@id - superblock index. Used to specify crypto information for group of servers.
+@size - size of the attached capabilities structure.
+@start - 0.
+@size - 0.
+@scsize - 0.
+
+@NETFS_LOCK
+Used to send lock request/release messages. Although it sends byte range request
+and is capable of flushing pages based on that, it is not used, since all Linux
+filesystems lock the whole inode.
+
+@id - lock generation number.
+@start - start of the locked range.
+@size - size of the locked range.
+@ext - lock type: read/write. Not used actually. 15'th bit is used to determine,
+	if it is lock request (1) or release (0).
+
+@NETFS_XATTR_SET
+@NETFS_XATTR_GET
+Used to set/get extended attributes for given inode.
+@id - attribute generation number or xattr setting type
+@start - size of the attribute (request or attached)
+@size - name length, path len and data size for given attribute
+@ext - path length for given object

+ 22 - 0
drivers/staging/Kconfig

@@ -73,6 +73,8 @@ source "drivers/staging/rt2860/Kconfig"
 
 
 source "drivers/staging/rt2870/Kconfig"
 source "drivers/staging/rt2870/Kconfig"
 
 
+source "drivers/staging/rt3070/Kconfig"
+
 source "drivers/staging/comedi/Kconfig"
 source "drivers/staging/comedi/Kconfig"
 
 
 source "drivers/staging/asus_oled/Kconfig"
 source "drivers/staging/asus_oled/Kconfig"
@@ -93,5 +95,25 @@ source "drivers/staging/epl/Kconfig"
 
 
 source "drivers/staging/android/Kconfig"
 source "drivers/staging/android/Kconfig"
 
 
+source "drivers/staging/dst/Kconfig"
+
+source "drivers/staging/pohmelfs/Kconfig"
+
+source "drivers/staging/stlc45xx/Kconfig"
+
+source "drivers/staging/uc2322/Kconfig"
+
+source "drivers/staging/b3dfg/Kconfig"
+
+source "drivers/staging/phison/Kconfig"
+
+source "drivers/staging/p9auth/Kconfig"
+
+source "drivers/staging/heci/Kconfig"
+
+source "drivers/staging/line6/Kconfig"
+
+source "drivers/staging/serqt_usb/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
 endif # STAGING

+ 11 - 0
drivers/staging/Makefile

@@ -19,6 +19,7 @@ obj-$(CONFIG_AGNX)		+= agnx/
 obj-$(CONFIG_OTUS)		+= otus/
 obj-$(CONFIG_OTUS)		+= otus/
 obj-$(CONFIG_RT2860)		+= rt2860/
 obj-$(CONFIG_RT2860)		+= rt2860/
 obj-$(CONFIG_RT2870)		+= rt2870/
 obj-$(CONFIG_RT2870)		+= rt2870/
+obj-$(CONFIG_RT3070)		+= rt3070/
 obj-$(CONFIG_COMEDI)		+= comedi/
 obj-$(CONFIG_COMEDI)		+= comedi/
 obj-$(CONFIG_ASUS_OLED)		+= asus_oled/
 obj-$(CONFIG_ASUS_OLED)		+= asus_oled/
 obj-$(CONFIG_PANEL)		+= panel/
 obj-$(CONFIG_PANEL)		+= panel/
@@ -29,3 +30,13 @@ obj-$(CONFIG_INPUT_MIMIO)	+= mimio/
 obj-$(CONFIG_TRANZPORT)		+= frontier/
 obj-$(CONFIG_TRANZPORT)		+= frontier/
 obj-$(CONFIG_EPL)		+= epl/
 obj-$(CONFIG_EPL)		+= epl/
 obj-$(CONFIG_ANDROID)		+= android/
 obj-$(CONFIG_ANDROID)		+= android/
+obj-$(CONFIG_DST)		+= dst/
+obj-$(CONFIG_POHMELFS)		+= pohmelfs/
+obj-$(CONFIG_STLC45XX)		+= stlc45xx/
+obj-$(CONFIG_USB_SERIAL_ATEN2011)	+= uc2322/
+obj-$(CONFIG_B3DFG)		+= b3dfg/
+obj-$(CONFIG_IDE_PHISON)	+= phison/
+obj-$(CONFIG_PLAN9AUTH)		+= p9auth/
+obj-$(CONFIG_HECI)		+= heci/
+obj-$(CONFIG_LINE6_USB)		+= line6/
+obj-$(CONFIG_USB_SERIAL_QUATECH_ESU100)	+= serqt_usb/

+ 7 - 7
drivers/staging/agnx/agnx.h

@@ -41,16 +41,16 @@ static const struct ieee80211_rate agnx_rates_80211g[] = {
 /* 	{ .bitrate = 20, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
 /* 	{ .bitrate = 20, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
 /* 	{ .bitrate = 55, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
 /* 	{ .bitrate = 55, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
 /* 	{ .bitrate = 110, .hw_value = 4, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
 /* 	{ .bitrate = 110, .hw_value = 4, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
- 	{ .bitrate = 10, .hw_value = 1, },
- 	{ .bitrate = 20, .hw_value = 2, },
- 	{ .bitrate = 55, .hw_value = 3, },
- 	{ .bitrate = 110, .hw_value = 4,},
+	{ .bitrate = 10, .hw_value = 1, },
+	{ .bitrate = 20, .hw_value = 2, },
+	{ .bitrate = 55, .hw_value = 3, },
+	{ .bitrate = 110, .hw_value = 4,},
 
 
 	{ .bitrate = 60, .hw_value = 0xB, },
 	{ .bitrate = 60, .hw_value = 0xB, },
 	{ .bitrate = 90, .hw_value = 0xF, },
 	{ .bitrate = 90, .hw_value = 0xF, },
 	{ .bitrate = 120, .hw_value = 0xA },
 	{ .bitrate = 120, .hw_value = 0xA },
 	{ .bitrate = 180, .hw_value = 0xE, },
 	{ .bitrate = 180, .hw_value = 0xE, },
-//	{ .bitrate = 240, .hw_value = 0xd, },
+/*	{ .bitrate = 240, .hw_value = 0xd, }, */
 	{ .bitrate = 360, .hw_value = 0xD, },
 	{ .bitrate = 360, .hw_value = 0xD, },
 	{ .bitrate = 480, .hw_value = 0x8, },
 	{ .bitrate = 480, .hw_value = 0x8, },
 	{ .bitrate = 540, .hw_value = 0xC, },
 	{ .bitrate = 540, .hw_value = 0xC, },
@@ -110,10 +110,10 @@ struct agnx_priv {
 	/* Need volatile? */
 	/* Need volatile? */
 	u32 irq_status;
 	u32 irq_status;
 
 
-        struct delayed_work periodic_work; /* Periodic tasks like recalibrate*/
+	struct delayed_work periodic_work; /* Periodic tasks like recalibrate */
 	struct ieee80211_low_level_stats stats;
 	struct ieee80211_low_level_stats stats;
 
 
-//        unsigned int phymode;
+	/* unsigned int phymode; */
 	int mode;
 	int mode;
 	int channel;
 	int channel;
 	u8 bssid[ETH_ALEN];
 	u8 bssid[ETH_ALEN];

+ 10 - 11
drivers/staging/agnx/debug.h

@@ -23,7 +23,7 @@ static inline void agnx_bug(char *reason)
 
 
 static inline void agnx_print_desc(struct agnx_desc *desc)
 static inline void agnx_print_desc(struct agnx_desc *desc)
 {
 {
-        u32 reg = be32_to_cpu(desc->frag);
+	u32 reg = be32_to_cpu(desc->frag);
 
 
 	PRINTK_BITS(DESC, PACKET_LEN);
 	PRINTK_BITS(DESC, PACKET_LEN);
 
 
@@ -291,7 +291,7 @@ static inline void agnx_print_sta(struct agnx_priv *priv, unsigned int sta_idx)
 	PRINTK_LE32(STA, sta->phy_stats_high);
 	PRINTK_LE32(STA, sta->phy_stats_high);
 	PRINTK_LE32(STA, sta->phy_stats_low);
 	PRINTK_LE32(STA, sta->phy_stats_low);
 
 
-//	for (i = 0; i < 8; i++)
+	/* for (i = 0; i < 8; i++) */
 	agnx_print_sta_traffic(sta->traffic + 0);
 	agnx_print_sta_traffic(sta->traffic + 0);
 
 
 	PRINTK_LE16(STA, sta->traffic_class0_frag_success);
 	PRINTK_LE16(STA, sta->traffic_class0_frag_success);
@@ -311,10 +311,10 @@ static inline void agnx_print_sta(struct agnx_priv *priv, unsigned int sta_idx)
 static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag)
 static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag)
 {
 {
 	u16 fctl;
 	u16 fctl;
-        int hdrlen;
+	int hdrlen;
 	DECLARE_MAC_BUF(mac);
 	DECLARE_MAC_BUF(mac);
 
 
-        fctl = le16_to_cpu(hdr->frame_control);
+	fctl = le16_to_cpu(hdr->frame_control);
 	switch (fctl & IEEE80211_FCTL_FTYPE) {
 	switch (fctl & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_DATA:
 	case IEEE80211_FTYPE_DATA:
 		printk(PFX "%s DATA ", tag);
 		printk(PFX "%s DATA ", tag);
@@ -324,7 +324,7 @@ static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag)
 		break;
 		break;
 	case IEEE80211_FTYPE_MGMT:
 	case IEEE80211_FTYPE_MGMT:
 		printk(PFX "%s MGMT ", tag);
 		printk(PFX "%s MGMT ", tag);
-		switch(fctl & IEEE80211_FCTL_STYPE) {
+		switch (fctl & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_ASSOC_REQ:
 		case IEEE80211_STYPE_ASSOC_REQ:
 			printk("SubType: ASSOC_REQ ");
 			printk("SubType: ASSOC_REQ ");
 			break;
 			break;
@@ -369,7 +369,7 @@ static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag)
 		printk(PFX "%s Packet type: Unknow\n", tag);
 		printk(PFX "%s Packet type: Unknow\n", tag);
 	}
 	}
 
 
-        hdrlen = ieee80211_hdrlen(fctl);
+	hdrlen = ieee80211_hdrlen(fctl);
 
 
 	if (hdrlen >= 4)
 	if (hdrlen >= 4)
 		printk("FC=0x%04x DUR=0x%04x",
 		printk("FC=0x%04x DUR=0x%04x",
@@ -389,29 +389,28 @@ static inline void dump_txm_registers(struct agnx_priv *priv)
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	int i;
 	int i;
-	for (i = 0; i <=0x1e8; i += 4) {
+	for (i = 0; i <= 0x1e8; i += 4)
 		printk(KERN_DEBUG PFX "TXM: %x---> 0x%.8x\n", i, ioread32(ctl + i));
 		printk(KERN_DEBUG PFX "TXM: %x---> 0x%.8x\n", i, ioread32(ctl + i));
-	}
 }
 }
 static inline void dump_rxm_registers(struct agnx_priv *priv)
 static inline void dump_rxm_registers(struct agnx_priv *priv)
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	int i;
 	int i;
-	for (i = 0; i <=0x108; i += 4)
+	for (i = 0; i <= 0x108; i += 4)
 		printk(KERN_DEBUG PFX "RXM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2000 + i));
 		printk(KERN_DEBUG PFX "RXM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2000 + i));
 }
 }
 static inline void dump_bm_registers(struct agnx_priv *priv)
 static inline void dump_bm_registers(struct agnx_priv *priv)
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	int i;
 	int i;
-	for (i = 0; i <=0x90; i += 4)
+	for (i = 0; i <= 0x90; i += 4)
 		printk(KERN_DEBUG PFX "BM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2c00 + i));
 		printk(KERN_DEBUG PFX "BM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2c00 + i));
 }
 }
 static inline void dump_cir_registers(struct agnx_priv *priv)
 static inline void dump_cir_registers(struct agnx_priv *priv)
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	int i;
 	int i;
-	for (i = 0; i <=0xb8; i += 4)
+	for (i = 0; i <= 0xb8; i += 4)
 		printk(KERN_DEBUG PFX "CIR: %x---> 0x%.8x\n", i, ioread32(ctl + 0x3000 + i));
 		printk(KERN_DEBUG PFX "CIR: %x---> 0x%.8x\n", i, ioread32(ctl + 0x3000 + i));
 }
 }
 
 

+ 37 - 38
drivers/staging/agnx/pci.c

@@ -39,34 +39,34 @@ static inline void agnx_interrupt_ack(struct agnx_priv *priv, u32 *reason)
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	u32 reg;
 	u32 reg;
 
 
-	if ( *reason & AGNX_STAT_RX ) {
+	if (*reason & AGNX_STAT_RX) {
 		/* Mark complete RX */
 		/* Mark complete RX */
 		reg = ioread32(ctl + AGNX_CIR_RXCTL);
 		reg = ioread32(ctl + AGNX_CIR_RXCTL);
 		reg |= 0x4;
 		reg |= 0x4;
 		iowrite32(reg, ctl + AGNX_CIR_RXCTL);
 		iowrite32(reg, ctl + AGNX_CIR_RXCTL);
 		/* disable Rx interrupt */
 		/* disable Rx interrupt */
 	}
 	}
-	if ( *reason & AGNX_STAT_TX ) {
+	if (*reason & AGNX_STAT_TX) {
 		reg = ioread32(ctl + AGNX_CIR_TXDCTL);
 		reg = ioread32(ctl + AGNX_CIR_TXDCTL);
 		if (reg & 0x4) {
 		if (reg & 0x4) {
 			iowrite32(reg, ctl + AGNX_CIR_TXDCTL);
 			iowrite32(reg, ctl + AGNX_CIR_TXDCTL);
 			*reason |= AGNX_STAT_TXD;
 			*reason |= AGNX_STAT_TXD;
 		}
 		}
- 		reg = ioread32(ctl + AGNX_CIR_TXMCTL);
+		reg = ioread32(ctl + AGNX_CIR_TXMCTL);
 		if (reg & 0x4) {
 		if (reg & 0x4) {
 			iowrite32(reg, ctl + AGNX_CIR_TXMCTL);
 			iowrite32(reg, ctl + AGNX_CIR_TXMCTL);
 			*reason |= AGNX_STAT_TXM;
 			*reason |= AGNX_STAT_TXM;
 		}
 		}
 	}
 	}
-	if ( *reason & AGNX_STAT_X ) {
-/* 		reg = ioread32(ctl + AGNX_INT_STAT); */
-/* 		iowrite32(reg, ctl + AGNX_INT_STAT); */
-/* 		/\* FIXME reinit interrupt mask *\/ */
-/* 		reg = 0xc390bf9 & ~IRQ_TX_BEACON; */
-/* 		reg &= ~IRQ_TX_DISABLE; */
-/* 		iowrite32(reg, ctl + AGNX_INT_MASK); */
-/* 		iowrite32(0x800, ctl + AGNX_CIR_BLKCTL); */
-	}
+/*	if (*reason & AGNX_STAT_X) {
+		reg = ioread32(ctl + AGNX_INT_STAT);
+		iowrite32(reg, ctl + AGNX_INT_STAT);
+		/* FIXME reinit interrupt mask *\/
+		reg = 0xc390bf9 & ~IRQ_TX_BEACON;
+		reg &= ~IRQ_TX_DISABLE;
+		iowrite32(reg, ctl + AGNX_INT_MASK);
+		iowrite32(0x800, ctl + AGNX_CIR_BLKCTL);
+	} */
 } /* agnx_interrupt_ack */
 } /* agnx_interrupt_ack */
 
 
 static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
 static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
@@ -79,7 +79,7 @@ static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
 
 
 	spin_lock(&priv->lock);
 	spin_lock(&priv->lock);
 
 
-//	printk(KERN_ERR PFX "Get a interrupt %s\n", __func__);
+/*	printk(KERN_ERR PFX "Get a interrupt %s\n", __func__); */
 
 
 	if (priv->init_status != AGNX_START)
 	if (priv->init_status != AGNX_START)
 		goto out;
 		goto out;
@@ -92,7 +92,7 @@ static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
 	ret = IRQ_HANDLED;
 	ret = IRQ_HANDLED;
 	priv->irq_status = ioread32(ctl + AGNX_INT_STAT);
 	priv->irq_status = ioread32(ctl + AGNX_INT_STAT);
 
 
-//	printk(PFX "Interrupt reason is 0x%x\n", irq_reason);
+/*	printk(PFX "Interrupt reason is 0x%x\n", irq_reason); */
 	/* Make sure the txm and txd flags don't conflict with other unknown
 	/* Make sure the txm and txd flags don't conflict with other unknown
 	   interrupt flag, maybe is not necessary */
 	   interrupt flag, maybe is not necessary */
 	irq_reason &= 0xF;
 	irq_reason &= 0xF;
@@ -101,13 +101,13 @@ static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
 	/* TODO Make sure the card finished initialized */
 	/* TODO Make sure the card finished initialized */
 	agnx_interrupt_ack(priv, &irq_reason);
 	agnx_interrupt_ack(priv, &irq_reason);
 
 
-	if ( irq_reason & AGNX_STAT_RX )
+	if (irq_reason & AGNX_STAT_RX)
 		handle_rx_irq(priv);
 		handle_rx_irq(priv);
-	if ( irq_reason & AGNX_STAT_TXD )
+	if (irq_reason & AGNX_STAT_TXD)
 		handle_txd_irq(priv);
 		handle_txd_irq(priv);
-	if ( irq_reason & AGNX_STAT_TXM )
+	if (irq_reason & AGNX_STAT_TXM)
 		handle_txm_irq(priv);
 		handle_txm_irq(priv);
-	if ( irq_reason & AGNX_STAT_X )
+	if (irq_reason & AGNX_STAT_X)
 		handle_other_irq(priv);
 		handle_other_irq(priv);
 
 
 	enable_rx_interrupt(priv);
 	enable_rx_interrupt(priv);
@@ -171,7 +171,7 @@ static int agnx_alloc_rings(struct agnx_priv *priv)
 
 
 	len = priv->rx.size + priv->txm.size + priv->txd.size;
 	len = priv->rx.size + priv->txm.size + priv->txd.size;
 
 
-//	priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL);
+/*	priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL); */
 	priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_ATOMIC);
 	priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_ATOMIC);
 	if (!priv->rx.info)
 	if (!priv->rx.info)
 		return -ENOMEM;
 		return -ENOMEM;
@@ -210,28 +210,27 @@ static void rings_free(struct agnx_priv *priv)
 #if 0
 #if 0
 static void agnx_periodic_work_handler(struct work_struct *work)
 static void agnx_periodic_work_handler(struct work_struct *work)
 {
 {
-	struct agnx_priv *priv = container_of(work, struct agnx_priv,
-                                             periodic_work.work);
-//	unsigned long flags;
+	struct agnx_priv *priv = container_of(work, struct agnx_priv, periodic_work.work);
+/*	unsigned long flags; */
 	unsigned long delay;
 	unsigned long delay;
 
 
 	/* fixme: using mutex?? */
 	/* fixme: using mutex?? */
-//	spin_lock_irqsave(&priv->lock, flags);
+/*	spin_lock_irqsave(&priv->lock, flags); */
 
 
 	/* TODO Recalibrate*/
 	/* TODO Recalibrate*/
-//	calibrate_oscillator(priv);
-//	antenna_calibrate(priv);
-//	agnx_send_packet(priv, 997);
+/*	calibrate_oscillator(priv); */
+/*	antenna_calibrate(priv); */
+/*	agnx_send_packet(priv, 997); /
 	/* FIXME */
 	/* FIXME */
 /* 	if (debug == 3) */
 /* 	if (debug == 3) */
 /*                 delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
 /*                 delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
 /* 	else */
 /* 	else */
 	delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY);
 	delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY);
-//		delay = round_jiffies(HZ * 15);
+/*	delay = round_jiffies(HZ * 15); */
 
 
 	queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay);
 	queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay);
 
 
-//	spin_unlock_irqrestore(&priv->lock, flags);
+/*	spin_unlock_irqrestore(&priv->lock, flags); */
 }
 }
 #endif
 #endif
 
 
@@ -255,12 +254,12 @@ static int agnx_start(struct ieee80211_hw *dev)
 		goto out;
 		goto out;
 	}
 	}
 
 
-//	mdelay(500);
+/*	mdelay(500); */
 
 
 	might_sleep();
 	might_sleep();
 	agnx_hw_init(priv);
 	agnx_hw_init(priv);
 
 
-//	mdelay(500);
+/*	mdelay(500); */
 	might_sleep();
 	might_sleep();
 
 
 	priv->init_status = AGNX_START;
 	priv->init_status = AGNX_START;
@@ -280,16 +279,16 @@ static void agnx_stop(struct ieee80211_hw *dev)
 	/* make sure hardware will not generate irq */
 	/* make sure hardware will not generate irq */
 	agnx_hw_reset(priv);
 	agnx_hw_reset(priv);
 	free_irq(priv->pdev->irq, dev);
 	free_irq(priv->pdev->irq, dev);
-        flush_workqueue(priv->hw->workqueue);
-//	cancel_delayed_work_sync(&priv->periodic_work);
+	flush_workqueue(priv->hw->workqueue);
+/*	cancel_delayed_work_sync(&priv->periodic_work); */
 	unfill_rings(priv);
 	unfill_rings(priv);
 	rings_free(priv);
 	rings_free(priv);
 }
 }
 
 
-static int agnx_config(struct ieee80211_hw *dev,
-		       struct ieee80211_conf *conf)
+static int agnx_config(struct ieee80211_hw *dev, u32 changed)
 {
 {
 	struct agnx_priv *priv = dev->priv;
 	struct agnx_priv *priv = dev->priv;
+	struct ieee80211_conf *conf = &dev->conf;
 	int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 	int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
 	AGNX_TRACE;
 	AGNX_TRACE;
 
 
@@ -315,7 +314,6 @@ static int agnx_config_interface(struct ieee80211_hw *dev,
 	spin_lock(&priv->lock);
 	spin_lock(&priv->lock);
 
 
 	if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
 	if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
-//		u32 reghi, reglo;
 		agnx_set_bssid(priv, conf->bssid);
 		agnx_set_bssid(priv, conf->bssid);
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 		hash_write(priv, conf->bssid, BSSID_STAID);
 		hash_write(priv, conf->bssid, BSSID_STAID);
@@ -425,7 +423,7 @@ static struct ieee80211_ops agnx_ops = {
 	.remove_interface	= agnx_remove_interface,
 	.remove_interface	= agnx_remove_interface,
 	.config			= agnx_config,
 	.config			= agnx_config,
 	.config_interface	= agnx_config_interface,
 	.config_interface	= agnx_config_interface,
- 	.configure_filter	= agnx_configure_filter,
+	.configure_filter	= agnx_configure_filter,
 	.get_stats		= agnx_get_stats,
 	.get_stats		= agnx_get_stats,
 	.get_tx_stats		= agnx_get_tx_stats,
 	.get_tx_stats		= agnx_get_tx_stats,
 	.get_tsf		= agnx_get_tsft
 	.get_tsf		= agnx_get_tsft
@@ -434,11 +432,12 @@ static struct ieee80211_ops agnx_ops = {
 static void __devexit agnx_pci_remove(struct pci_dev *pdev)
 static void __devexit agnx_pci_remove(struct pci_dev *pdev)
 {
 {
 	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
 	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-	struct agnx_priv *priv = dev->priv;
+	struct agnx_priv *priv;
 	AGNX_TRACE;
 	AGNX_TRACE;
 
 
 	if (!dev)
 	if (!dev)
 		return;
 		return;
+	priv = dev->priv;
 	ieee80211_unregister_hw(dev);
 	ieee80211_unregister_hw(dev);
 	pci_iounmap(pdev, priv->ctl);
 	pci_iounmap(pdev, priv->ctl);
 	pci_iounmap(pdev, priv->data);
 	pci_iounmap(pdev, priv->data);
@@ -504,7 +503,7 @@ static int __devinit agnx_pci_probe(struct pci_dev *pdev,
 
 
 	/* Map mem #1 and #2 */
 	/* Map mem #1 and #2 */
 	priv->ctl = pci_iomap(pdev, 0, mem_len0);
 	priv->ctl = pci_iomap(pdev, 0, mem_len0);
-//	printk(KERN_DEBUG PFX"MEM1 mapped address is 0x%p\n", priv->ctl);
+/*	printk(KERN_DEBUG PFX"MEM1 mapped address is 0x%p\n", priv->ctl); */
 	if (!priv->ctl) {
 	if (!priv->ctl) {
 		printk(KERN_ERR PFX "Can't map device memory\n");
 		printk(KERN_ERR PFX "Can't map device memory\n");
 		goto err_free_dev;
 		goto err_free_dev;

+ 16 - 16
drivers/staging/agnx/phy.c

@@ -114,7 +114,7 @@ static void mac_address_set(struct agnx_priv *priv)
 	/* FIXME */
 	/* FIXME */
 	reg = (mac_addr[0] << 24) | (mac_addr[1] << 16) | mac_addr[2] << 8 | mac_addr[3];
 	reg = (mac_addr[0] << 24) | (mac_addr[1] << 16) | mac_addr[2] << 8 | mac_addr[3];
 	iowrite32(reg, ctl + AGNX_RXM_MACHI);
 	iowrite32(reg, ctl + AGNX_RXM_MACHI);
- 	reg = (mac_addr[4] << 8) | mac_addr[5];
+	reg = (mac_addr[4] << 8) | mac_addr[5];
 	iowrite32(reg, ctl + AGNX_RXM_MACLO);
 	iowrite32(reg, ctl + AGNX_RXM_MACLO);
 }
 }
 
 
@@ -127,7 +127,7 @@ static void receiver_bssid_set(struct agnx_priv *priv, u8 *bssid)
 	/* FIXME */
 	/* FIXME */
 	reg = bssid[0] << 24 | (bssid[1] << 16) | (bssid[2] << 8) | bssid[3];
 	reg = bssid[0] << 24 | (bssid[1] << 16) | (bssid[2] << 8) | bssid[3];
 	iowrite32(reg, ctl + AGNX_RXM_BSSIDHI);
 	iowrite32(reg, ctl + AGNX_RXM_BSSIDHI);
- 	reg = (bssid[4] << 8) | bssid[5];
+	reg = (bssid[4] << 8) | bssid[5];
 	iowrite32(reg, ctl + AGNX_RXM_BSSIDLO);
 	iowrite32(reg, ctl + AGNX_RXM_BSSIDLO);
 
 
 	/* Enable the receiver */
 	/* Enable the receiver */
@@ -401,9 +401,9 @@ static void rx_management_init(struct agnx_priv *priv)
 		agnx_write32(ctl, 0x2074, 0x1f171710);
 		agnx_write32(ctl, 0x2074, 0x1f171710);
 		agnx_write32(ctl, 0x2078, 0x10100d0d);
 		agnx_write32(ctl, 0x2078, 0x10100d0d);
 		agnx_write32(ctl, 0x207c, 0x11111010);
 		agnx_write32(ctl, 0x207c, 0x11111010);
-	}
-	else
+	} else {
 		agnx_write32(ctl, AGNX_RXM_DELAY11, 0x0);
 		agnx_write32(ctl, AGNX_RXM_DELAY11, 0x0);
+	}
 	agnx_write32(ctl, AGNX_RXM_REQRATE, 0x8195e00);
 	agnx_write32(ctl, AGNX_RXM_REQRATE, 0x8195e00);
 }
 }
 
 
@@ -476,7 +476,7 @@ static void gain_ctlcnt_init(struct agnx_priv *priv)
 	/* It seemed if we set other bit to 1 the bit 0 will
 	/* It seemed if we set other bit to 1 the bit 0 will
 	   be auto change to 0 */
 	   be auto change to 0 */
 	agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x2 | 0x1);
 	agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x2 | 0x1);
-//	agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x1);
+/*	agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x1); */
 } /* gain_ctlcnt_init */
 } /* gain_ctlcnt_init */
 
 
 
 
@@ -490,7 +490,7 @@ static void phy_init(struct agnx_priv *priv)
 	/* Load InitialGainTable */
 	/* Load InitialGainTable */
 	gain_table_init(priv);
 	gain_table_init(priv);
 
 
-  	agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x2000000);
+	agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x2000000);
 
 
 	/* Clear the following offsets in Memory Range #2: */
 	/* Clear the following offsets in Memory Range #2: */
 	memset_io(data + 0x5040, 0, 0xa * 4);
 	memset_io(data + 0x5040, 0, 0xa * 4);
@@ -586,7 +586,7 @@ static void phy_init(struct agnx_priv *priv)
 		agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28);
 		agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28);
 		agnx_write32(ctl, AGNX_GCR_CWDETEC, 0x0);
 		agnx_write32(ctl, AGNX_GCR_CWDETEC, 0x0);
 		agnx_write32(ctl, AGNX_GCR_0X38, 0x1e);
 		agnx_write32(ctl, AGNX_GCR_0X38, 0x1e);
-//		agnx_write32(ctl, AGNX_GCR_BOACT, 0x26);
+/*		agnx_write32(ctl, AGNX_GCR_BOACT, 0x26);*/
 		agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
 		agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
 
 
 		agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x32);
 		agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x32);
@@ -810,10 +810,10 @@ static void card_interface_init(struct agnx_priv *priv)
 		}
 		}
 		print_hex_dump_bytes(PFX "EEPROM: ", DUMP_PREFIX_NONE, eeprom,
 		print_hex_dump_bytes(PFX "EEPROM: ", DUMP_PREFIX_NONE, eeprom,
 				     ARRAY_SIZE(eeprom));
 				     ARRAY_SIZE(eeprom));
-	} while(0);
+	} while (0);
 
 
 	spi_rc_write(ctl, RF_CHIP0, 0x26);
 	spi_rc_write(ctl, RF_CHIP0, 0x26);
-        reg = agnx_read32(ctl, AGNX_SPI_RLSW);
+	reg = agnx_read32(ctl, AGNX_SPI_RLSW);
 
 
 	/* Initialize the system interface */
 	/* Initialize the system interface */
 	system_itf_init(priv);
 	system_itf_init(priv);
@@ -874,19 +874,19 @@ static void card_interface_init(struct agnx_priv *priv)
 	/* FIXME Enable the request */
 	/* FIXME Enable the request */
 	/* Check packet length */
 	/* Check packet length */
 	/* Set maximum packet length */
 	/* Set maximum packet length */
-/* 	agnx_write32(ctl, AGNX_RXM_REQRATE, 0x88195e00); */
-/* 	enable_receiver(priv); */
+/*	agnx_write32(ctl, AGNX_RXM_REQRATE, 0x88195e00); */
+/*	enable_receiver(priv); */
 
 
 	/* Set the Receiver BSSID */
 	/* Set the Receiver BSSID */
 	receiver_bssid_set(priv, bssid);
 	receiver_bssid_set(priv, bssid);
 
 
 	/* FIXME Set to managed mode */
 	/* FIXME Set to managed mode */
 	set_managed_mode(priv);
 	set_managed_mode(priv);
-//	set_promiscuous_mode(priv);
-/* 	set_scan_mode(priv); */
-/* 	set_learn_mode(priv); */
-// 	set_promis_and_managed(priv);
-// 	set_adhoc_mode(priv);
+/*	set_promiscuous_mode(priv); */
+/*	set_scan_mode(priv); */
+/*	set_learn_mode(priv); */
+/*	set_promis_and_managed(priv); */
+/*	set_adhoc_mode(priv); */
 
 
 	/* Set the recieve request rate */
 	/* Set the recieve request rate */
 	/* Check packet length */
 	/* Check packet length */

+ 11 - 12
drivers/staging/agnx/rf.c

@@ -109,12 +109,12 @@ void rf_chips_init(struct agnx_priv *priv)
 	}
 	}
 
 
 	/* Set SPI clock speed to 200NS */
 	/* Set SPI clock speed to 200NS */
-        reg = agnx_read32(ctl, AGNX_SPI_CFG);
-        reg &= ~0xF;
-        reg |= 0x3;
-        agnx_write32(ctl, AGNX_SPI_CFG, reg);
+	reg = agnx_read32(ctl, AGNX_SPI_CFG);
+	reg &= ~0xF;
+	reg |= 0x3;
+	agnx_write32(ctl, AGNX_SPI_CFG, reg);
 
 
-        /* Set SPI clock speed to 50NS */
+	/* Set SPI clock speed to 50NS */
 	reg = agnx_read32(ctl, AGNX_SPI_CFG);
 	reg = agnx_read32(ctl, AGNX_SPI_CFG);
 	reg &= ~0xF;
 	reg &= ~0xF;
 	reg |= 0x1;
 	reg |= 0x1;
@@ -256,7 +256,7 @@ static void antenna_init(struct agnx_priv *priv, int num_antenna)
 		agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
 		agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
 		agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
 		agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
 		agnx_write32(ctl, AGNX_GCR_SIGLTH, 48);
 		agnx_write32(ctl, AGNX_GCR_SIGLTH, 48);
-//		agnx_write32(ctl, AGNX_GCR_SIGLTH, 16);
+/*		agnx_write32(ctl, AGNX_GCR_SIGLTH, 16); */
 		break;
 		break;
 	default:
 	default:
 		printk(KERN_WARNING PFX "Unknow antenna number\n");
 		printk(KERN_WARNING PFX "Unknow antenna number\n");
@@ -275,8 +275,8 @@ static void chain_update(struct agnx_priv *priv, u32 chain)
 	if (reg == 0x4)
 	if (reg == 0x4)
 		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
 		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
 	else if (reg != 0x0)
 	else if (reg != 0x0)
-     		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
-        else {
+		spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
+	else {
 		if (chain == 3 || chain == 6) {
 		if (chain == 3 || chain == 6) {
 			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
 			spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
 			agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
 			agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
@@ -634,8 +634,7 @@ static void chain_calibrate(struct agnx_priv *priv, struct chains *chains,
 	}
 	}
 } /* chain_calibrate */
 } /* chain_calibrate */
 
 
-
-static void inline get_calibrete_value(struct agnx_priv *priv, struct chains *chains,
+static inline void get_calibrete_value(struct agnx_priv *priv, struct chains *chains,
 				       unsigned int num)
 				       unsigned int num)
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
@@ -652,7 +651,7 @@ static void inline get_calibrete_value(struct agnx_priv *priv, struct chains *ch
 	}
 	}
 
 
 	if (num == 0 || num == 1 || num == 2) {
 	if (num == 0 || num == 1 || num == 2) {
-		if ( 0 == chains[num].cali)
+		if (0 == chains[num].cali)
 			chains[num].cali = 0xff;
 			chains[num].cali = 0xff;
 		else
 		else
 			chains[num].cali--;
 			chains[num].cali--;
@@ -669,7 +668,7 @@ static inline void calibra_delay(struct agnx_priv *priv)
 	unsigned int i = 100;
 	unsigned int i = 100;
 
 
 	wmb();
 	wmb();
-	while (i--) {
+	while (--i) {
 		reg = (ioread32(ctl + AGNX_ACI_STATUS));
 		reg = (ioread32(ctl + AGNX_ACI_STATUS));
 		if (reg == 0x4000)
 		if (reg == 0x4000)
 			break;
 			break;

+ 10 - 11
drivers/staging/agnx/sta.c

@@ -18,7 +18,7 @@ void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id)
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 
 
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
-        reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
+	reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
 	printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
 	printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
 }
 }
 
 
@@ -40,7 +40,7 @@ void hash_write(struct agnx_priv *priv, u8 *mac_addr, u8 sta_id)
 	iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
 	iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 
 
-        reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
+	reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
 	if (!(reglo & 0x80000000))
 	if (!(reglo & 0x80000000))
 		printk(KERN_WARNING PFX "Update hash table failed\n");
 		printk(KERN_WARNING PFX "Update hash table failed\n");
 }
 }
@@ -59,7 +59,7 @@ void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id)
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
 
 
-        reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
+	reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
 	printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
 	printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
 
 
 }
 }
@@ -69,15 +69,14 @@ void hash_dump(struct agnx_priv *priv, u8 sta_id)
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	u32 reghi, reglo;
 	u32 reghi, reglo;
 
 
-	reglo = 0x0;		/* dump command */
-	reglo|= 0x40000000;  	/* status bit */
+	reglo = 0x40000000;  	/* status bit */
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 	iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
 	iowrite32(sta_id << 16, ctl + AGNX_RXM_HASH_DUMP_DATA);
 	iowrite32(sta_id << 16, ctl + AGNX_RXM_HASH_DUMP_DATA);
 
 
 	udelay(80);
 	udelay(80);
 
 
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
-        reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
+	reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
 	printk(PFX "hash cmd are : %.8x%.8x\n", reghi, reglo);
 	printk(PFX "hash cmd are : %.8x%.8x\n", reghi, reglo);
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_FLAG);
 	reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_FLAG);
 	printk(PFX "hash flag is : %.8x\n", reghi);
 	printk(PFX "hash flag is : %.8x\n", reghi);
@@ -91,7 +90,7 @@ void hash_dump(struct agnx_priv *priv, u8 sta_id)
 void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx)
 void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx)
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
-        memcpy_fromio(power, ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
+	memcpy_fromio(power, ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
 		      sizeof(*power));
 		      sizeof(*power));
 }
 }
 
 
@@ -100,7 +99,7 @@ set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int
 {
 {
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	/* FIXME   2. Write Template to offset + station number  */
 	/* FIXME   2. Write Template to offset + station number  */
-        memcpy_toio(ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
+	memcpy_toio(ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
 		    power, sizeof(*power));
 		    power, sizeof(*power));
 }
 }
 
 
@@ -135,7 +134,7 @@ inline void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int s
 {
 {
 	void __iomem *data = priv->data;
 	void __iomem *data = priv->data;
 
 
-        memcpy_toio(data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx,
+	memcpy_toio(data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx,
 		    sta, sizeof(*sta));
 		    sta, sizeof(*sta));
 }
 }
 
 
@@ -165,7 +164,7 @@ static void sta_tx_workqueue_init(struct agnx_priv *priv, unsigned int sta_idx)
 
 
 	reg = agnx_set_bits(WORK_QUEUE_VALID, WORK_QUEUE_VALID_SHIFT, 1);
 	reg = agnx_set_bits(WORK_QUEUE_VALID, WORK_QUEUE_VALID_SHIFT, 1);
 	reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 1);
 	reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 1);
-//	reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 0);
+/*	reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 0); */
 	tx_wq.reg2 |= cpu_to_le32(reg);
 	tx_wq.reg2 |= cpu_to_le32(reg);
 
 
 	/* Suppose all 8 traffic class are used */
 	/* Suppose all 8 traffic class are used */
@@ -181,7 +180,7 @@ static void sta_traffic_init(struct agnx_sta_traffic *traffic)
 
 
 	reg = agnx_set_bits(NEW_PACKET, NEW_PACKET_SHIFT, 1);
 	reg = agnx_set_bits(NEW_PACKET, NEW_PACKET_SHIFT, 1);
 	reg |= agnx_set_bits(TRAFFIC_VALID, TRAFFIC_VALID_SHIFT, 1);
 	reg |= agnx_set_bits(TRAFFIC_VALID, TRAFFIC_VALID_SHIFT, 1);
-//	reg |= agnx_set_bits(TRAFFIC_ACK_TYPE, TRAFFIC_ACK_TYPE_SHIFT, 1);
+/*	reg |= agnx_set_bits(TRAFFIC_ACK_TYPE, TRAFFIC_ACK_TYPE_SHIFT, 1); */
 	traffic->reg0 = cpu_to_le32(reg);
 	traffic->reg0 = cpu_to_le32(reg);
 
 
 	/* 	3. setting RX Sequence Number to 4095 */
 	/* 	3. setting RX Sequence Number to 4095 */

+ 1 - 1
drivers/staging/agnx/sta.h

@@ -16,7 +16,7 @@ struct agnx_hash_cmd {
 #define PASS		0x00000001
 #define PASS		0x00000001
 #define PASS_SHIFT	1
 #define PASS_SHIFT	1
 	__be32 cmdlo;
 	__be32 cmdlo;
-}__attribute__((__packed__));
+} __attribute__((__packed__));
 
 
 
 
 /*
 /*

+ 6 - 6
drivers/staging/agnx/table.c

@@ -80,7 +80,7 @@ void routing_table_init(struct agnx_priv *priv)
 
 
 	disable_receiver(priv);
 	disable_receiver(priv);
 
 
-	for ( type = 0; type < 0x3; type++ ) {
+	for (type = 0; type < 0x3; type++) {
 		for (subtype = 0; subtype < 0x10; subtype++) {
 		for (subtype = 0; subtype < 0x10; subtype++) {
 			/* 1. Set Routing table to R/W and to Return status on Read */
 			/* 1. Set Routing table to R/W and to Return status on Read */
 			reg = (type << ROUTAB_TYPE_SHIFT) |
 			reg = (type << ROUTAB_TYPE_SHIFT) |
@@ -89,7 +89,7 @@ void routing_table_init(struct agnx_priv *priv)
 			if (type == ROUTAB_TYPE_DATA) {
 			if (type == ROUTAB_TYPE_DATA) {
 				/* NULL goes to RFP */
 				/* NULL goes to RFP */
 				if (subtype == ROUTAB_SUBTYPE_NULL)
 				if (subtype == ROUTAB_SUBTYPE_NULL)
-//					reg |= ROUTAB_ROUTE_RFP;
+/*					reg |= ROUTAB_ROUTE_RFP; */
 					reg |= ROUTAB_ROUTE_CPU;
 					reg |= ROUTAB_ROUTE_CPU;
 				/* QOS NULL goes to CPU */
 				/* QOS NULL goes to CPU */
 				else if (subtype == ROUTAB_SUBTYPE_QOSNULL)
 				else if (subtype == ROUTAB_SUBTYPE_QOSNULL)
@@ -104,7 +104,7 @@ void routing_table_init(struct agnx_priv *priv)
 					 (subtype == ROUTAB_SUBTYPE_QOSDATAPOLL) ||
 					 (subtype == ROUTAB_SUBTYPE_QOSDATAPOLL) ||
 					 (subtype == ROUTAB_SUBTYPE_QOSDATAACKPOLL))
 					 (subtype == ROUTAB_SUBTYPE_QOSDATAACKPOLL))
 					reg |= ROUTAB_ROUTE_ENCRY;
 					reg |= ROUTAB_ROUTE_ENCRY;
-//					reg |= ROUTAB_ROUTE_CPU;
+/*					reg |= ROUTAB_ROUTE_CPU; */
 				/*Drop NULL and QOS NULL ack, poll and poll ack*/
 				/*Drop NULL and QOS NULL ack, poll and poll ack*/
 				else if ((subtype == ROUTAB_SUBTYPE_NULLACK) ||
 				else if ((subtype == ROUTAB_SUBTYPE_NULLACK) ||
 					 (subtype == ROUTAB_SUBTYPE_QOSNULLACK) ||
 					 (subtype == ROUTAB_SUBTYPE_QOSNULLACK) ||
@@ -112,11 +112,11 @@ void routing_table_init(struct agnx_priv *priv)
 					 (subtype == ROUTAB_SUBTYPE_QOSNULLPOLL) ||
 					 (subtype == ROUTAB_SUBTYPE_QOSNULLPOLL) ||
 					 (subtype == ROUTAB_SUBTYPE_NULLPOLLACK) ||
 					 (subtype == ROUTAB_SUBTYPE_NULLPOLLACK) ||
 					 (subtype == ROUTAB_SUBTYPE_QOSNULLPOLLACK))
 					 (subtype == ROUTAB_SUBTYPE_QOSNULLPOLLACK))
-//					reg |= ROUTAB_ROUTE_DROP;
+/*					reg |= ROUTAB_ROUTE_DROP; */
 					reg |= ROUTAB_ROUTE_CPU;
 					reg |= ROUTAB_ROUTE_CPU;
-			}
-			else
+			} else {
 				reg |= (ROUTAB_ROUTE_CPU);
 				reg |= (ROUTAB_ROUTE_CPU);
+			}
 			iowrite32(reg, ctl + AGNX_RXM_ROUTAB);
 			iowrite32(reg, ctl + AGNX_RXM_ROUTAB);
 			/* Check to verify that the status bit cleared */
 			/* Check to verify that the status bit cleared */
 			routing_table_delay();
 			routing_table_delay();

+ 116 - 100
drivers/staging/agnx/xmit.c

@@ -17,8 +17,8 @@
 #include "debug.h"
 #include "debug.h"
 #include "phy.h"
 #include "phy.h"
 
 
-unsigned int rx_frame_cnt = 0;
-//unsigned int local_tx_sent_cnt = 0;
+unsigned int rx_frame_cnt;
+/* unsigned int local_tx_sent_cnt = 0; */
 
 
 static inline void disable_rx_engine(struct agnx_priv *priv)
 static inline void disable_rx_engine(struct agnx_priv *priv)
 {
 {
@@ -242,15 +242,15 @@ static void get_rx_stats(struct agnx_priv *priv, struct agnx_hdr *hdr,
 	memset(stat, 0, sizeof(*stat));
 	memset(stat, 0, sizeof(*stat));
 	/* RSSI */
 	/* RSSI */
 	rssi = (u8 *)&hdr->phy_stats_lo;
 	rssi = (u8 *)&hdr->phy_stats_lo;
-//	stat->ssi = (rssi[0] + rssi[1] + rssi[2]) / 3;
+/*	stat->ssi = (rssi[0] + rssi[1] + rssi[2]) / 3; */
 	/* Noise */
 	/* Noise */
 	noise = ioread32(ctl + AGNX_GCR_NOISE0);
 	noise = ioread32(ctl + AGNX_GCR_NOISE0);
 	noise += ioread32(ctl + AGNX_GCR_NOISE1);
 	noise += ioread32(ctl + AGNX_GCR_NOISE1);
 	noise += ioread32(ctl + AGNX_GCR_NOISE2);
 	noise += ioread32(ctl + AGNX_GCR_NOISE2);
 	stat->noise = noise / 3;
 	stat->noise = noise / 3;
 	/* Signal quality */
 	/* Signal quality */
-	//snr = stat->ssi - stat->noise;
-	if (snr >=0 && snr < 40)
+/*	snr = stat->ssi - stat->noise; */
+	if (snr >= 0 && snr < 40)
 		stat->signal = 5 * snr / 2;
 		stat->signal = 5 * snr / 2;
 	else if (snr >= 40)
 	else if (snr >= 40)
 		stat->signal = 100;
 		stat->signal = 100;
@@ -269,10 +269,9 @@ static void get_rx_stats(struct agnx_priv *priv, struct agnx_hdr *hdr,
 
 
 	stat->band = IEEE80211_BAND_2GHZ;
 	stat->band = IEEE80211_BAND_2GHZ;
 	stat->freq = agnx_channels[priv->channel - 1].center_freq;
 	stat->freq = agnx_channels[priv->channel - 1].center_freq;
-//	stat->antenna = 3;
-//	stat->mactime = be32_to_cpu(hdr->time_stamp);
-//	stat->channel = priv->channel;
-
+/*	stat->antenna = 3;
+	stat->mactime = be32_to_cpu(hdr->time_stamp);
+	stat->channel = priv->channel; */
 }
 }
 
 
 static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr,
 static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr,
@@ -296,7 +295,7 @@ static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr,
 static inline int agnx_packet_check(struct agnx_priv *priv, struct agnx_hdr *agnxhdr,
 static inline int agnx_packet_check(struct agnx_priv *priv, struct agnx_hdr *agnxhdr,
 				    unsigned packet_len)
 				    unsigned packet_len)
 {
 {
-	if (agnx_get_bits(CRC_FAIL, CRC_FAIL_SHIFT, be32_to_cpu(agnxhdr->reg1)) == 1){
+	if (agnx_get_bits(CRC_FAIL, CRC_FAIL_SHIFT, be32_to_cpu(agnxhdr->reg1)) == 1) {
 		printk(PFX "RX: CRC check fail\n");
 		printk(PFX "RX: CRC check fail\n");
 		goto drop;
 		goto drop;
 	}
 	}
@@ -320,7 +319,7 @@ void handle_rx_irq(struct agnx_priv *priv)
 {
 {
 	struct ieee80211_rx_status status;
 	struct ieee80211_rx_status status;
 	unsigned int len;
 	unsigned int len;
-//	AGNX_TRACE;
+/*	AGNX_TRACE; */
 
 
 	do {
 	do {
 		struct agnx_desc *desc;
 		struct agnx_desc *desc;
@@ -341,54 +340,54 @@ void handle_rx_irq(struct agnx_priv *priv)
 
 
 		len = (frag & PACKET_LEN) >> PACKET_LEN_SHIFT;
 		len = (frag & PACKET_LEN) >> PACKET_LEN_SHIFT;
 		if (agnx_packet_check(priv, hdr, len) == -1) {
 		if (agnx_packet_check(priv, hdr, len) == -1) {
- 			rx_desc_reusing(priv, i);
+			rx_desc_reusing(priv, i);
 			continue;
 			continue;
 		}
 		}
 		skb_put(skb, len);
 		skb_put(skb, len);
 
 
 		do {
 		do {
-			u16 fctl;
+				u16 fctl;
 			fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)->frame_control);
 			fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)->frame_control);
-			if ((fctl & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_BEACON)// && !(fctl & IEEE80211_STYPE_BEACON))
+			if ((fctl & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_BEACON)/* && !(fctl & IEEE80211_STYPE_BEACON)) */
 				dump_ieee80211_hdr((struct ieee80211_hdr *)hdr->mac_hdr, "RX");
 				dump_ieee80211_hdr((struct ieee80211_hdr *)hdr->mac_hdr, "RX");
 		} while (0);
 		} while (0);
 
 
 		if (hdr->_11b0 && !hdr->_11g0) {
 		if (hdr->_11b0 && !hdr->_11g0) {
-/* 			int j; */
-/* 			u16 fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr) */
-/* 					       ->frame_control); */
-/* 			if ( (fctl & IEEE80211_FCTL_FTYPE) ==  IEEE80211_FTYPE_DATA) { */
-/* 				agnx_print_rx_hdr(hdr); */
-// 				agnx_print_sta(priv, BSSID_STAID);
-/* 				for (j = 0; j < 8; j++) */
-/* 					agnx_print_sta_tx_wq(priv, BSSID_STAID, j);		 */
-/* 			} */
+/*			int j;
+			u16 fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)
+					       ->frame_control);
+			if ( (fctl & IEEE80211_FCTL_FTYPE) ==  IEEE80211_FTYPE_DATA) {
+				agnx_print_rx_hdr(hdr);
+				agnx_print_sta(priv, BSSID_STAID);
+				for (j = 0; j < 8; j++)
+					agnx_print_sta_tx_wq(priv, BSSID_STAID, j);
+			} */
 
 
 			get_rx_stats(priv, hdr, &status);
 			get_rx_stats(priv, hdr, &status);
 			skb_pull(skb, sizeof(*hdr));
 			skb_pull(skb, sizeof(*hdr));
 			combine_hdr_frag((struct ieee80211_hdr *)hdr->mac_hdr, skb);
 			combine_hdr_frag((struct ieee80211_hdr *)hdr->mac_hdr, skb);
 		} else if (!hdr->_11b0 && hdr->_11g0) {
 		} else if (!hdr->_11b0 && hdr->_11g0) {
-//			int j;
+/*			int j; */
 			agnx_print_rx_hdr(hdr);
 			agnx_print_rx_hdr(hdr);
 			agnx_print_sta(priv, BSSID_STAID);
 			agnx_print_sta(priv, BSSID_STAID);
-//			for (j = 0; j < 8; j++)
+/*			for (j = 0; j < 8; j++) */
 			agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);
 			agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);
 
 
 			print_hex_dump_bytes("agnx: RX_PACKET: ", DUMP_PREFIX_NONE,
 			print_hex_dump_bytes("agnx: RX_PACKET: ", DUMP_PREFIX_NONE,
 					     skb->data, skb->len + 8);
 					     skb->data, skb->len + 8);
 
 
-//			if (agnx_plcp_get_bitrate_ofdm(&hdr->_11g0) == 0)
+/*			if (agnx_plcp_get_bitrate_ofdm(&hdr->_11g0) == 0) */
 			get_rx_stats(priv, hdr, &status);
 			get_rx_stats(priv, hdr, &status);
 			skb_pull(skb, sizeof(*hdr));
 			skb_pull(skb, sizeof(*hdr));
 			combine_hdr_frag((struct ieee80211_hdr *)
 			combine_hdr_frag((struct ieee80211_hdr *)
 					 ((void *)&hdr->mac_hdr), skb);
 					 ((void *)&hdr->mac_hdr), skb);
-//			dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G");
+/*			dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */
 		} else
 		} else
 			agnx_bug("Unknown packets type");
 			agnx_bug("Unknown packets type");
 		ieee80211_rx_irqsafe(priv->hw, skb, &status);
 		ieee80211_rx_irqsafe(priv->hw, skb, &status);
 		rx_desc_reinit(priv, i);
 		rx_desc_reinit(priv, i);
 
 
-	} while ( priv->rx.idx++ );
+	} while (priv->rx.idx++);
 } /* handle_rx_irq */
 } /* handle_rx_irq */
 
 
 static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring)
 static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring)
@@ -415,40 +414,40 @@ static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring)
 		pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_TODEVICE);
 		pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_TODEVICE);
 
 
 		do {
 		do {
-//			int j;
+/*			int j; */
 			size_t len;
 			size_t len;
 			len = info->skb->len - sizeof(struct agnx_hdr) + info->hdr_len;
 			len = info->skb->len - sizeof(struct agnx_hdr) + info->hdr_len;
-			//	if (len == 614) {
-//				agnx_print_desc(desc);
+/*			if (len == 614) { */
+/*				agnx_print_desc(desc); */
 				if (info->type == PACKET) {
 				if (info->type == PACKET) {
-//					agnx_print_tx_hdr((struct agnx_hdr *)info->skb->data);
-/* 					agnx_print_sta_power(priv, LOCAL_STAID); */
-/* 					agnx_print_sta(priv, LOCAL_STAID); */
-/* //					for (j = 0; j < 8; j++) */
-/* 					agnx_print_sta_tx_wq(priv, LOCAL_STAID, 0); */
-//					agnx_print_sta_power(priv, BSSID_STAID);
-//					agnx_print_sta(priv, BSSID_STAID);
-//					for (j = 0; j < 8; j++)
-//					agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);
+/*					agnx_print_tx_hdr((struct agnx_hdr *)info->skb->data); */
+/*					agnx_print_sta_power(priv, LOCAL_STAID); */
+/*					agnx_print_sta(priv, LOCAL_STAID); */
+/*					for (j = 0; j < 8; j++) */
+/*					agnx_print_sta_tx_wq(priv, LOCAL_STAID, 0); */
+/*					agnx_print_sta_power(priv, BSSID_STAID); */
+/*					agnx_print_sta(priv, BSSID_STAID); */
+/*					for (j = 0; j < 8; j++) */
+/*					agnx_print_sta_tx_wq(priv, BSSID_STAID, 0); */
 				}
 				}
-//			}
+/*			} */
 		} while (0);
 		} while (0);
 
 
 		if (info->type == PACKET) {
 		if (info->type == PACKET) {
-//			dump_txm_registers(priv);
-//			dump_rxm_registers(priv);
-//			dump_bm_registers(priv);
-//			dump_cir_registers(priv);
+/*			dump_txm_registers(priv);
+			dump_rxm_registers(priv);
+			dump_bm_registers(priv);
+			dump_cir_registers(priv); */
 		}
 		}
 
 
 		if (info->type == PACKET) {
 		if (info->type == PACKET) {
-//			struct ieee80211_hdr *hdr;
+/*			struct ieee80211_hdr *hdr; */
 			struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(info->skb);
 			struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(info->skb);
 
 
 			skb_pull(info->skb, sizeof(struct agnx_hdr));
 			skb_pull(info->skb, sizeof(struct agnx_hdr));
 			memcpy(skb_push(info->skb, info->hdr_len), &info->hdr, info->hdr_len);
 			memcpy(skb_push(info->skb, info->hdr_len), &info->hdr, info->hdr_len);
 
 
-//			dump_ieee80211_hdr((struct ieee80211_hdr *)info->skb->data, "TX_HANDLE");
+/*			dump_ieee80211_hdr((struct ieee80211_hdr *)info->skb->data, "TX_HANDLE"); */
 /* 			print_hex_dump_bytes("agnx: TX_HANDLE: ", DUMP_PREFIX_NONE, */
 /* 			print_hex_dump_bytes("agnx: TX_HANDLE: ", DUMP_PREFIX_NONE, */
 /* 					     info->skb->data, info->skb->len); */
 /* 					     info->skb->data, info->skb->len); */
 
 
@@ -462,7 +461,7 @@ static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring)
 /* 				ieee80211_tx_status_irqsafe(priv->hw, info->skb, &(info->tx_status)); */
 /* 				ieee80211_tx_status_irqsafe(priv->hw, info->skb, &(info->tx_status)); */
 /* 			} else */
 /* 			} else */
 /* 				dev_kfree_skb_irq(info->skb); */
 /* 				dev_kfree_skb_irq(info->skb); */
- 		}
+		}
 		memset(desc, 0, sizeof(*desc));
 		memset(desc, 0, sizeof(*desc));
 		memset(info, 0, sizeof(*info));
 		memset(info, 0, sizeof(*info));
 	}
 	}
@@ -485,7 +484,7 @@ void handle_txd_irq(struct agnx_priv *priv)
 
 
 void handle_other_irq(struct agnx_priv *priv)
 void handle_other_irq(struct agnx_priv *priv)
 {
 {
-//	void __iomem *ctl = priv->ctl;
+/*	void __iomem *ctl = priv->ctl; */
 	u32 status = priv->irq_status;
 	u32 status = priv->irq_status;
 	void __iomem *ctl = priv->ctl;
 	void __iomem *ctl = priv->ctl;
 	u32 reg;
 	u32 reg;
@@ -526,11 +525,11 @@ void handle_other_irq(struct agnx_priv *priv)
 		iowrite32(reg, ctl + AGNX_INT_MASK);
 		iowrite32(reg, ctl + AGNX_INT_MASK);
 		iowrite32(IRQ_RX_FRAME, ctl + AGNX_INT_STAT);
 		iowrite32(IRQ_RX_FRAME, ctl + AGNX_INT_STAT);
 		printk(PFX "IRQ: RX Frame\n");
 		printk(PFX "IRQ: RX Frame\n");
- 		rx_frame_cnt++;
+		rx_frame_cnt++;
 	}
 	}
 	if (status & IRQ_ERR_INT) {
 	if (status & IRQ_ERR_INT) {
 		iowrite32(IRQ_ERR_INT, ctl + AGNX_INT_STAT);
 		iowrite32(IRQ_ERR_INT, ctl + AGNX_INT_STAT);
-//		agnx_hw_reset(priv);
+/*		agnx_hw_reset(priv); */
 		printk(PFX "IRQ: Error Interrupt\n");
 		printk(PFX "IRQ: Error Interrupt\n");
 	}
 	}
 	if (status & IRQ_TX_QUE_FULL)
 	if (status & IRQ_TX_QUE_FULL)
@@ -558,14 +557,14 @@ void handle_other_irq(struct agnx_priv *priv)
 
 
 static inline void route_flag_set(struct agnx_hdr *txhdr)
 static inline void route_flag_set(struct agnx_hdr *txhdr)
 {
 {
-//	u32 reg = 0;
+/*	u32 reg = 0; */
 
 
 	/* FIXME */
 	/* FIXME */
-/*  	reg = (0x7 << ROUTE_COMPRESSION_SHIFT) & ROUTE_COMPRESSION; */
-/* 	txhdr->reg5 = cpu_to_be32(reg); */
- 	txhdr->reg5 = (0xa << 0x0) | (0x7 << 0x18);
-// 	txhdr->reg5 = cpu_to_be32((0xa << 0x0) | (0x7 << 0x18));
-// 	txhdr->reg5 = cpu_to_be32(0x7 << 0x0);
+/*	reg = (0x7 << ROUTE_COMPRESSION_SHIFT) & ROUTE_COMPRESSION; */
+/*	txhdr->reg5 = cpu_to_be32(reg); */
+	txhdr->reg5 = (0xa << 0x0) | (0x7 << 0x18);
+/*	txhdr->reg5 = cpu_to_be32((0xa << 0x0) | (0x7 << 0x18)); */
+/*	txhdr->reg5 = cpu_to_be32(0x7 << 0x0); */
 }
 }
 
 
 /* Return 0 if no match */
 /* Return 0 if no match */
@@ -579,12 +578,29 @@ static inline unsigned int get_power_level(unsigned int rate, unsigned int anten
 	case 55:
 	case 55:
 	case 60:
 	case 60:
 	case 90:
 	case 90:
-	case 120: power_level = 22; break;
-	case 180: power_level = 19; break;
-	case 240: power_level = 18; break;
-	case 360: power_level = 16; break;
-	case 480: power_level = 15; break;
-	case 540: power_level = 14; break;
+	case 120:
+		power_level = 22;
+		break;
+
+	case 180:
+		power_level = 19;
+		break;
+
+	case 240:
+		power_level = 18;
+		break;
+
+	case 360:
+		power_level = 16;
+		break;
+
+	case 480:
+		power_level = 15;
+		break;
+
+	case 540:
+		power_level = 14;
+		break;
 	default:
 	default:
 		agnx_bug("Error rate setting\n");
 		agnx_bug("Error rate setting\n");
 	}
 	}
@@ -604,30 +620,30 @@ static inline void fill_agnx_hdr(struct agnx_priv *priv, struct agnx_info *tx_in
 
 
 	memset(txhdr, 0, sizeof(*txhdr));
 	memset(txhdr, 0, sizeof(*txhdr));
 
 
-//	reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, LOCAL_STAID);
+/*	reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, LOCAL_STAID); */
 	reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, BSSID_STAID);
 	reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, BSSID_STAID);
 	reg |= agnx_set_bits(WORKQUEUE_ID, WORKQUEUE_ID_SHIFT, 0);
 	reg |= agnx_set_bits(WORKQUEUE_ID, WORKQUEUE_ID_SHIFT, 0);
 	txhdr->reg4 = cpu_to_be32(reg);
 	txhdr->reg4 = cpu_to_be32(reg);
 
 
 	/* Set the Hardware Sequence Number to 1? */
 	/* Set the Hardware Sequence Number to 1? */
 	reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 0);
 	reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 0);
-//	reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 1);
+/*	reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 1); */
 	reg |= agnx_set_bits(MAC_HDR_LEN, MAC_HDR_LEN_SHIFT, tx_info->hdr_len);
 	reg |= agnx_set_bits(MAC_HDR_LEN, MAC_HDR_LEN_SHIFT, tx_info->hdr_len);
 	txhdr->reg1 = cpu_to_be32(reg);
 	txhdr->reg1 = cpu_to_be32(reg);
 	/* Set the agnx_hdr's MAC header */
 	/* Set the agnx_hdr's MAC header */
 	memcpy(txhdr->mac_hdr, &tx_info->hdr, tx_info->hdr_len);
 	memcpy(txhdr->mac_hdr, &tx_info->hdr, tx_info->hdr_len);
 
 
 	reg = agnx_set_bits(ACK, ACK_SHIFT, 1);
 	reg = agnx_set_bits(ACK, ACK_SHIFT, 1);
-//	reg = agnx_set_bits(ACK, ACK_SHIFT, 0);
+/*	reg = agnx_set_bits(ACK, ACK_SHIFT, 0); */
 	reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 0);
 	reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 0);
-//	reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 1);
+/*	reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 1); */
 	reg |= agnx_set_bits(RELAY, RELAY_SHIFT, 0);
 	reg |= agnx_set_bits(RELAY, RELAY_SHIFT, 0);
 	reg |= agnx_set_bits(TM, TM_SHIFT, 0);
 	reg |= agnx_set_bits(TM, TM_SHIFT, 0);
 	txhdr->reg0 = cpu_to_be32(reg);
 	txhdr->reg0 = cpu_to_be32(reg);
 
 
 	/* Set the long and short retry limits */
 	/* Set the long and short retry limits */
- 	txhdr->tx.short_retry_limit = tx_info->txi->control.rates[0].count;
- 	txhdr->tx.long_retry_limit = tx_info->txi->control.rates[0].count;
+	txhdr->tx.short_retry_limit = tx_info->txi->control.rates[0].count;
+	txhdr->tx.long_retry_limit = tx_info->txi->control.rates[0].count;
 
 
 	/* FIXME */
 	/* FIXME */
 	len = tx_info->skb->len - sizeof(*txhdr) + tx_info->hdr_len + FCS_LEN;
 	len = tx_info->skb->len - sizeof(*txhdr) + tx_info->hdr_len + FCS_LEN;
@@ -652,23 +668,23 @@ static void txm_power_set(struct agnx_priv *priv,
 	if (txi->control.rates[0].idx < 0) {
 	if (txi->control.rates[0].idx < 0) {
 		/* For B mode Short Preamble */
 		/* For B mode Short Preamble */
 		reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_SHORT);
 		reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_SHORT);
-//		control->tx_rate = -control->tx_rate;
+/*		control->tx_rate = -control->tx_rate; */
 	} else
 	} else
 		reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211G);
 		reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211G);
-//		reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_LONG);
+/*		reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_LONG); */
 	reg |= agnx_set_bits(SIGNAL, SIGNAL_SHIFT, 0xB);
 	reg |= agnx_set_bits(SIGNAL, SIGNAL_SHIFT, 0xB);
 	reg |= agnx_set_bits(RATE, RATE_SHIFT, 0xB);
 	reg |= agnx_set_bits(RATE, RATE_SHIFT, 0xB);
-//	reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 15);
+/*	reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 15); */
 	reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 20);
 	reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 20);
 	/* if rate < 11M set it to 0 */
 	/* if rate < 11M set it to 0 */
 	reg |= agnx_set_bits(NUM_TRANSMITTERS, NUM_TRANSMITTERS_SHIFT, 1);
 	reg |= agnx_set_bits(NUM_TRANSMITTERS, NUM_TRANSMITTERS_SHIFT, 1);
-//	reg |= agnx_set_bits(EDCF, EDCF_SHIFT, 1);
-//	reg |= agnx_set_bits(TIFS, TIFS_SHIFT, 1);
+/*	reg |= agnx_set_bits(EDCF, EDCF_SHIFT, 1); */
+/*	reg |= agnx_set_bits(TIFS, TIFS_SHIFT, 1); */
 
 
 	power.reg = reg;
 	power.reg = reg;
-//	power.reg = cpu_to_le32(reg);
+/*	power.reg = cpu_to_le32(reg); */
 
 
-//	set_sta_power(priv, &power, LOCAL_STAID);
+/*	set_sta_power(priv, &power, LOCAL_STAID); */
 	set_sta_power(priv, &power, BSSID_STAID);
 	set_sta_power(priv, &power, BSSID_STAID);
 }
 }
 
 
@@ -759,24 +775,24 @@ static int __agnx_tx(struct agnx_priv *priv, struct sk_buff *skb,
 
 
 	txm_power_set(priv, txi);
 	txm_power_set(priv, txi);
 
 
-/* 	do { */
-/* 		int j; */
-/* 		size_t len; */
-/* 		len = skb->len - hdr_info->dma_len + hdr_info->hdr_len;  */
-/* //		if (len == 614) { */
-/* 			agnx_print_desc(hdr_desc); */
-/* 			agnx_print_desc(frag_desc); */
-/* 			agnx_print_tx_hdr((struct agnx_hdr *)skb->data); */
-/* 			agnx_print_sta_power(priv, LOCAL_STAID); */
-/* 			agnx_print_sta(priv, LOCAL_STAID); */
-/* 			for (j = 0; j < 8; j++) */
-/* 				agnx_print_sta_tx_wq(priv, LOCAL_STAID, j); */
-/* 			agnx_print_sta_power(priv, BSSID_STAID); */
-/* 			agnx_print_sta(priv, BSSID_STAID); */
-/* 			for (j = 0; j < 8; j++) */
-/* 				agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */
-/* 			//	} */
-/* 	} while (0); */
+/*	do { */
+/*		int j; */
+/*		size_t len; */
+/*		len = skb->len - hdr_info->dma_len + hdr_info->hdr_len;  */
+/*		if (len == 614) { */
+/*			agnx_print_desc(hdr_desc); */
+/*			agnx_print_desc(frag_desc); */
+/*			agnx_print_tx_hdr((struct agnx_hdr *)skb->data); */
+/*			agnx_print_sta_power(priv, LOCAL_STAID); */
+/*			agnx_print_sta(priv, LOCAL_STAID); */
+/*			for (j = 0; j < 8; j++) */
+/*				agnx_print_sta_tx_wq(priv, LOCAL_STAID, j); */
+/*			agnx_print_sta_power(priv, BSSID_STAID); */
+/*			agnx_print_sta(priv, BSSID_STAID); */
+/*			for (j = 0; j < 8; j++) */
+/*				agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */
+/*			} */
+/*	} while (0); */
 
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 
@@ -787,7 +803,7 @@ static int __agnx_tx(struct agnx_priv *priv, struct sk_buff *skb,
 		reg = (ioread32(priv->ctl + AGNX_CIR_TXMCTL));
 		reg = (ioread32(priv->ctl + AGNX_CIR_TXMCTL));
 		reg |= 0x8;
 		reg |= 0x8;
 		iowrite32((reg), priv->ctl + AGNX_CIR_TXMCTL);
 		iowrite32((reg), priv->ctl + AGNX_CIR_TXMCTL);
-	}while (0);
+	} while (0);
 
 
 	/* Trigger TXD */
 	/* Trigger TXD */
 	do {
 	do {
@@ -795,7 +811,7 @@ static int __agnx_tx(struct agnx_priv *priv, struct sk_buff *skb,
 		reg = (ioread32(priv->ctl + AGNX_CIR_TXDCTL));
 		reg = (ioread32(priv->ctl + AGNX_CIR_TXDCTL));
 		reg |= 0x8;
 		reg |= 0x8;
 		iowrite32((reg), priv->ctl + AGNX_CIR_TXDCTL);
 		iowrite32((reg), priv->ctl + AGNX_CIR_TXDCTL);
-	}while (0);
+	} while (0);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -807,12 +823,12 @@ int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb)
 	if (tx_packet_check(skb))
 	if (tx_packet_check(skb))
 		return 0;
 		return 0;
 
 
-/* 	print_hex_dump_bytes("agnx: TX_PACKET: ", DUMP_PREFIX_NONE, */
-/* 			     skb->data, skb->len); */
+/*	print_hex_dump_bytes("agnx: TX_PACKET: ", DUMP_PREFIX_NONE, */
+/*			     skb->data, skb->len); */
 
 
-        fctl = le16_to_cpu(*((__le16 *)skb->data));
+	fctl = le16_to_cpu(*((__le16 *)skb->data));
 
 
-	if ( (fctl & IEEE80211_FCTL_FTYPE)  == IEEE80211_FTYPE_DATA )
+	if ((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
 		return __agnx_tx(priv, skb, &priv->txd);
 		return __agnx_tx(priv, skb, &priv->txd);
 	else
 	else
 		return __agnx_tx(priv, skb, &priv->txm);
 		return __agnx_tx(priv, skb, &priv->txm);

+ 41 - 39
drivers/staging/altpciechdma/altpciechdma.c

@@ -46,7 +46,6 @@
 #include <linux/cdev.h>
 #include <linux/cdev.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/io.h>
@@ -313,15 +312,16 @@ static int __devinit map_bars(struct ape_dev *ape, struct pci_dev *dev)
 			continue;
 			continue;
 		/* do not map BARs with address 0 */
 		/* do not map BARs with address 0 */
 		if (!bar_start || !bar_end) {
 		if (!bar_start || !bar_end) {
-            printk(KERN_DEBUG "BAR #%d is not present?!\n", i);
+			printk(KERN_DEBUG "BAR #%d is not present?!\n", i);
 			rc = -1;
 			rc = -1;
 			goto fail;
 			goto fail;
 		}
 		}
 		bar_length = bar_end - bar_start + 1;
 		bar_length = bar_end - bar_start + 1;
 		/* BAR length is less than driver requires? */
 		/* BAR length is less than driver requires? */
 		if (bar_length < bar_min_len[i]) {
 		if (bar_length < bar_min_len[i]) {
-            printk(KERN_DEBUG "BAR #%d length = %lu bytes but driver "
-            "requires at least %lu bytes\n", i, bar_length, bar_min_len[i]);
+			printk(KERN_DEBUG "BAR #%d length = %lu bytes but driver "
+			"requires at least %lu bytes\n",
+			i, bar_length, bar_min_len[i]);
 			rc = -1;
 			rc = -1;
 			goto fail;
 			goto fail;
 		}
 		}
@@ -333,8 +333,8 @@ static int __devinit map_bars(struct ape_dev *ape, struct pci_dev *dev)
 			rc = -1;
 			rc = -1;
 			goto fail;
 			goto fail;
 		}
 		}
-        printk(KERN_DEBUG "BAR[%d] mapped at 0x%p with length %lu(/%lu).\n", i,
-			ape->bar[i], bar_min_len[i], bar_length);
+		printk(KERN_DEBUG "BAR[%d] mapped at 0x%p with length %lu(/%lu).\n", i,
+		ape->bar[i], bar_min_len[i], bar_length);
 	}
 	}
 	/* succesfully mapped all required BAR regions */
 	/* succesfully mapped all required BAR regions */
 	rc = 0;
 	rc = 0;
@@ -427,11 +427,13 @@ static int ape_sg_to_chdma_table(struct scatterlist *sgl, int nents, int first,
 		dma_addr_t next = sg_dma_address(&sgl[i + 1]);
 		dma_addr_t next = sg_dma_address(&sgl[i + 1]);
 		/* length of this entry i */
 		/* length of this entry i */
 		len = sg_dma_len(&sgl[i]);
 		len = sg_dma_len(&sgl[i]);
-		printk(KERN_DEBUG "%04d: addr=0x%08x length=0x%08x\n", i, addr, len);
+		printk(KERN_DEBUG "%04d: addr=0x%Lx length=0x%08x\n", i,
+			(unsigned long long)addr, len);
 		/* entry i + 1 is non-contiguous with entry i? */
 		/* entry i + 1 is non-contiguous with entry i? */
 		if (next != addr + len) {
 		if (next != addr + len) {
 			/* TODO create entry here (we could overwrite i) */
 			/* TODO create entry here (we could overwrite i) */
-			printk(KERN_DEBUG "%4d: cont_addr=0x%08x cont_len=0x%08x\n", j, cont_addr, cont_len);
+			printk(KERN_DEBUG "%4d: cont_addr=0x%Lx cont_len=0x%08x\n", j,
+				(unsigned long long)cont_addr, cont_len);
 			/* set descriptor for contiguous transfer */
 			/* set descriptor for contiguous transfer */
 			ape_chdma_desc_set(&desc[j], cont_addr, ep_addr, cont_len);
 			ape_chdma_desc_set(&desc[j], cont_addr, ep_addr, cont_len);
 			/* next end point memory address */
 			/* next end point memory address */
@@ -447,8 +449,10 @@ static int ape_sg_to_chdma_table(struct scatterlist *sgl, int nents, int first,
 		addr = next;
 		addr = next;
 	}
 	}
 	/* TODO create entry here  (we could overwrite i) */
 	/* TODO create entry here  (we could overwrite i) */
-	printk(KERN_DEBUG "%04d: addr=0x%08x length=0x%08x\n", i, addr, len);
-	printk(KERN_DEBUG "%4d: cont_addr=0x%08x length=0x%08x\n", j, cont_addr, cont_len);
+	printk(KERN_DEBUG "%04d: addr=0x%Lx length=0x%08x\n", i,
+		(unsigned long long)addr, len);
+	printk(KERN_DEBUG "%4d: cont_addr=0x%Lx length=0x%08x\n", j,
+		(unsigned long long)cont_addr, cont_len);
 	j++;
 	j++;
 	return j;
 	return j;
 }
 }
@@ -467,15 +471,14 @@ static inline int compare(u32 *p, u32 *q, int len)
 		} else {
 		} else {
 			fail++;
 			fail++;
 			/* show the first few miscompares */
 			/* show the first few miscompares */
-			if (fail < 10) {
-                printk(KERN_DEBUG "[%p] = 0x%08x != [%p] = 0x%08x ?!\n", p, *p, q, *q);
-            /* but stop after a while */
-            } else if (fail == 10) {
-                printk(KERN_DEBUG "---more errors follow! not printed---\n");
-		  	} else {
+			if (fail < 10)
+				printk(KERN_DEBUG "[%p] = 0x%08x != [%p] = 0x%08x ?!\n", p, *p, q, *q);
+				/* but stop after a while */
+			else if (fail == 10)
+				printk(KERN_DEBUG "---more errors follow! not printed---\n");
+			else
 				/* stop compare after this many errors */
 				/* stop compare after this many errors */
-                break;
-            }
+			break;
 		}
 		}
 		p++;
 		p++;
 		q++;
 		q++;
@@ -528,7 +531,7 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
 	printk(KERN_DEBUG "ape->table_virt = 0x%p.\n", ape->table_virt);
 	printk(KERN_DEBUG "ape->table_virt = 0x%p.\n", ape->table_virt);
 
 
 	if (!write_header || !read_header || !ape->table_virt)
 	if (!write_header || !read_header || !ape->table_virt)
-        goto fail;
+		goto fail;
 
 
 	/* allocate and map coherently-cached memory for a DMA-able buffer */
 	/* allocate and map coherently-cached memory for a DMA-able buffer */
 	/* @see Documentation/PCI/PCI-DMA-mapping.txt, near line 318 */
 	/* @see Documentation/PCI/PCI-DMA-mapping.txt, near line 318 */
@@ -565,9 +568,8 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
 	/* read 8192 bytes from RC buffer to EP address 4096 */
 	/* read 8192 bytes from RC buffer to EP address 4096 */
 	ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus, 4096, 2 * PAGE_SIZE);
 	ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus, 4096, 2 * PAGE_SIZE);
 #if 1
 #if 1
-	for (i = 0; i < 255; i++) {
+	for (i = 0; i < 255; i++)
 		ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus, 4096, 2 * PAGE_SIZE);
 		ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus, 4096, 2 * PAGE_SIZE);
-	}
 	/* index of last descriptor */
 	/* index of last descriptor */
 	n = i - 1;
 	n = i - 1;
 #endif
 #endif
@@ -647,7 +649,7 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
 		printk(KERN_DEBUG "EPLAST = %u, n = %d\n", eplast, n);
 		printk(KERN_DEBUG "EPLAST = %u, n = %d\n", eplast, n);
 		if (eplast == n) {
 		if (eplast == n) {
 			printk(KERN_DEBUG "DONE\n");
 			printk(KERN_DEBUG "DONE\n");
-            /* print IRQ count before the transfer */
+			/* print IRQ count before the transfer */
 			printk(KERN_DEBUG "#IRQs during transfer: %d\n", ape->irq_count - irq_count);
 			printk(KERN_DEBUG "#IRQs during transfer: %d\n", ape->irq_count - irq_count);
 			break;
 			break;
 		}
 		}
@@ -661,9 +663,9 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
 	n = 0;
 	n = 0;
 	ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus + 8192, 4096, 2 * PAGE_SIZE);
 	ape_chdma_desc_set(&ape->table_virt->desc[n], buffer_bus + 8192, 4096, 2 * PAGE_SIZE);
 #if 1
 #if 1
-	for (i = 0; i < 255; i++) {
+	for (i = 0; i < 255; i++)
 		ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus + 8192, 4096, 2 * PAGE_SIZE);
 		ape_chdma_desc_set(&ape->table_virt->desc[i], buffer_bus + 8192, 4096, 2 * PAGE_SIZE);
-	}
+
 	/* index of last descriptor */
 	/* index of last descriptor */
 	n = i - 1;
 	n = i - 1;
 #endif
 #endif
@@ -691,7 +693,7 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
 	w = (u32)(n + 1);
 	w = (u32)(n + 1);
 	/* enable updates of eplast for each descriptor completion */
 	/* enable updates of eplast for each descriptor completion */
 	w |= (u32)(1UL << 18)/*global EPLAST_EN*/;
 	w |= (u32)(1UL << 18)/*global EPLAST_EN*/;
-#if 0 // test variable, make a module option later
+#if 0   /* test variable, make a module option later */
 	/* enable MSI for each descriptor completion */
 	/* enable MSI for each descriptor completion */
 	if (ape->msi_enabled)
 	if (ape->msi_enabled)
 		w |= (1UL << 17)/*global MSI*/;
 		w |= (1UL << 17)/*global MSI*/;
@@ -715,7 +717,7 @@ static int __devinit dma_test(struct ape_dev *ape, struct pci_dev *dev)
 	/** memory write barrier */
 	/** memory write barrier */
 	wmb();
 	wmb();
 	/** dummy read to flush posted writes */
 	/** dummy read to flush posted writes */
-	//(void)ioread32();
+	/* (void) ioread32(); */
 
 
 	printk(KERN_DEBUG "POLL FOR WRITE:\n");
 	printk(KERN_DEBUG "POLL FOR WRITE:\n");
 	/* poll for completion, 1000 times 1 millisecond */
 	/* poll for completion, 1000 times 1 millisecond */
@@ -844,7 +846,7 @@ static int __devinit probe(struct pci_dev *dev, const struct pci_device_id *id)
 	}
 	}
 	ape->got_regions = 1;
 	ape->got_regions = 1;
 
 
-#if 1 // @todo For now, disable 64-bit, because I do not understand the implications (DAC!)
+#if 1   /* @todo For now, disable 64-bit, because I do not understand the implications (DAC!) */
 	/* query for DMA transfer */
 	/* query for DMA transfer */
 	/* @see Documentation/PCI/PCI-DMA-mapping.txt */
 	/* @see Documentation/PCI/PCI-DMA-mapping.txt */
 	if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)) {
 	if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)) {
@@ -947,7 +949,8 @@ static void __devexit remove(struct pci_dev *dev)
 	struct ape_dev *ape;
 	struct ape_dev *ape;
 	printk(KERN_DEBUG "remove(0x%p)\n", dev);
 	printk(KERN_DEBUG "remove(0x%p)\n", dev);
 	if ((dev == 0) || (dev->dev.driver_data == 0)) {
 	if ((dev == 0) || (dev->dev.driver_data == 0)) {
-		printk(KERN_DEBUG "remove(dev = 0x%p) dev->dev.driver_data = 0x%p\n", dev, dev->dev.driver_data);
+		printk(KERN_DEBUG "remove(dev = 0x%p) dev->dev.driver_data = 0x%p\n",
+			dev, (dev? dev->dev.driver_data: NULL));
 		return;
 		return;
 	}
 	}
 	ape = (struct ape_dev *)dev->dev.driver_data;
 	ape = (struct ape_dev *)dev->dev.driver_data;
@@ -1048,10 +1051,9 @@ static ssize_t sg_write(struct file *file, const char __user *buf, size_t count,
 	printk(KERN_DEBUG DRV_NAME "_write(buf=0x%p, count=%lld, pos=%llu)\n",
 	printk(KERN_DEBUG DRV_NAME "_write(buf=0x%p, count=%lld, pos=%llu)\n",
 		buf, (s64)count, (u64)*pos);
 		buf, (s64)count, (u64)*pos);
 	/* TODO transfer boundaries at PAGE_SIZE granularity */
 	/* TODO transfer boundaries at PAGE_SIZE granularity */
-	while (remaining > 0)
-	{
+	while (remaining > 0) {
 		/* limit DMA transfer size */
 		/* limit DMA transfer size */
-		transfer_len = (remaining < APE_CHDMA_MAX_TRANSFER_LEN)? remaining:
+		transfer_len = (remaining < APE_CHDMA_MAX_TRANSFER_LEN) ? remaining :
 			APE_CHDMA_MAX_TRANSFER_LEN;
 			APE_CHDMA_MAX_TRANSFER_LEN;
 		/* get all user space buffer pages and create a scattergather list */
 		/* get all user space buffer pages and create a scattergather list */
 		sgm_map_user_pages(ape->sgm, transfer_addr, transfer_len, 0/*read from userspace*/);
 		sgm_map_user_pages(ape->sgm, transfer_addr, transfer_len, 0/*read from userspace*/);
@@ -1085,12 +1087,12 @@ static ssize_t sg_write(struct file *file, const char __user *buf, size_t count,
 /*
 /*
  * character device file operations
  * character device file operations
  */
  */
-static struct file_operations sg_fops = {
-  .owner = THIS_MODULE,
-  .open = sg_open,
-  .release = sg_close,
-  .read = sg_read,
-  .write = sg_write,
+static const struct file_operations sg_fops = {
+	.owner = THIS_MODULE,
+	.open = sg_open,
+	.release = sg_close,
+	.read = sg_read,
+	.write = sg_write,
 };
 };
 
 
 /* sg_init() - Initialize character device
 /* sg_init() - Initialize character device
@@ -1158,12 +1160,12 @@ static struct pci_driver pci_driver = {
  */
  */
 static int __init alterapciechdma_init(void)
 static int __init alterapciechdma_init(void)
 {
 {
-  int rc = 0;
+	int rc = 0;
 	printk(KERN_DEBUG DRV_NAME " init(), built at " __DATE__ " " __TIME__ "\n");
 	printk(KERN_DEBUG DRV_NAME " init(), built at " __DATE__ " " __TIME__ "\n");
 	/* register this driver with the PCI bus driver */
 	/* register this driver with the PCI bus driver */
 	rc = pci_register_driver(&pci_driver);
 	rc = pci_register_driver(&pci_driver);
 	if (rc < 0)
 	if (rc < 0)
-	  return rc;
+		return rc;
 	return 0;
 	return 0;
 }
 }
 
 

+ 15 - 3
drivers/staging/android/binder.c

@@ -2649,14 +2649,22 @@ static void binder_vma_open(struct vm_area_struct *vma)
 {
 {
 	struct binder_proc *proc = vma->vm_private_data;
 	struct binder_proc *proc = vma->vm_private_data;
 	if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
 	if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
-		printk(KERN_INFO "binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot));
+		printk(KERN_INFO
+			"binder: %d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n",
+			proc->pid, vma->vm_start, vma->vm_end,
+			(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
+			(unsigned long)pgprot_val(vma->vm_page_prot));
 	dump_stack();
 	dump_stack();
 }
 }
 static void binder_vma_close(struct vm_area_struct *vma)
 static void binder_vma_close(struct vm_area_struct *vma)
 {
 {
 	struct binder_proc *proc = vma->vm_private_data;
 	struct binder_proc *proc = vma->vm_private_data;
 	if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
 	if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
-		printk(KERN_INFO "binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot));
+		printk(KERN_INFO
+			"binder: %d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n",
+			proc->pid, vma->vm_start, vma->vm_end,
+			(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
+			(unsigned long)pgprot_val(vma->vm_page_prot));
 	proc->vma = NULL;
 	proc->vma = NULL;
 }
 }
 
 
@@ -2677,7 +2685,11 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
 		vma->vm_end = vma->vm_start + SZ_4M;
 		vma->vm_end = vma->vm_start + SZ_4M;
 
 
 	if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
 	if (binder_debug_mask & BINDER_DEBUG_OPEN_CLOSE)
-		printk(KERN_INFO "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", proc->pid, vma->vm_start, vma->vm_end, (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, pgprot_val(vma->vm_page_prot));
+		printk(KERN_INFO
+			"binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
+			proc->pid, vma->vm_start, vma->vm_end,
+			(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
+			(unsigned long)pgprot_val(vma->vm_page_prot));
 
 
 	if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
 	if (vma->vm_flags & FORBIDDEN_MMAP_FLAGS) {
 		ret = -EPERM;
 		ret = -EPERM;

+ 4 - 4
drivers/staging/android/ram_console.c

@@ -225,7 +225,7 @@ static int __init ram_console_init(struct ram_console_buffer *buffer,
 		buffer_size - sizeof(struct ram_console_buffer);
 		buffer_size - sizeof(struct ram_console_buffer);
 
 
 	if (ram_console_buffer_size > buffer_size) {
 	if (ram_console_buffer_size > buffer_size) {
-		pr_err("ram_console: buffer %p, invalid size %d, datasize %d\n",
+		pr_err("ram_console: buffer %p, invalid size %zu, datasize %zu\n",
 		       buffer, buffer_size, ram_console_buffer_size);
 		       buffer, buffer_size, ram_console_buffer_size);
 		return 0;
 		return 0;
 	}
 	}
@@ -235,8 +235,8 @@ static int __init ram_console_init(struct ram_console_buffer *buffer,
 						ECC_BLOCK_SIZE) + 1) * ECC_SIZE;
 						ECC_BLOCK_SIZE) + 1) * ECC_SIZE;
 
 
 	if (ram_console_buffer_size > buffer_size) {
 	if (ram_console_buffer_size > buffer_size) {
-		pr_err("ram_console: buffer %p, invalid size %d, "
-		       "non-ecc datasize %d\n",
+		pr_err("ram_console: buffer %p, invalid size %zu, "
+		       "non-ecc datasize %zu\n",
 		       buffer, buffer_size, ram_console_buffer_size);
 		       buffer, buffer_size, ram_console_buffer_size);
 		return 0;
 		return 0;
 	}
 	}
@@ -322,7 +322,7 @@ static int ram_console_driver_probe(struct platform_device *pdev)
 	}
 	}
 	buffer_size = res->end - res->start + 1;
 	buffer_size = res->end - res->start + 1;
 	start = res->start;
 	start = res->start;
-	printk(KERN_INFO "ram_console: got buffer at %x, size %x\n",
+	printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n",
 	       start, buffer_size);
 	       start, buffer_size);
 	buffer = ioremap(res->start, buffer_size);
 	buffer = ioremap(res->start, buffer_size);
 	if (buffer == NULL) {
 	if (buffer == NULL) {

+ 86 - 63
drivers/staging/asus_oled/asus_oled.c

@@ -56,10 +56,10 @@ MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
 MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION);
 MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 
-static struct class *oled_class = 0;
-static int oled_num = 0;
+static struct class *oled_class;
+static int oled_num;
 
 
-static uint start_off = 0;
+static uint start_off;
 
 
 module_param(start_off, uint, 0644);
 module_param(start_off, uint, 0644);
 
 
@@ -80,20 +80,20 @@ struct oled_dev_desc_str {
 };
 };
 
 
 /* table of devices that work with this driver */
 /* table of devices that work with this driver */
-static struct usb_device_id id_table [] = {
+static struct usb_device_id id_table[] = {
 	{ USB_DEVICE(0x0b05, 0x1726) }, // Asus G1/G2 (and variants)
 	{ USB_DEVICE(0x0b05, 0x1726) }, // Asus G1/G2 (and variants)
 	{ USB_DEVICE(0x0b05, 0x175b) }, // Asus G50V (and possibly others - G70? G71?)
 	{ USB_DEVICE(0x0b05, 0x175b) }, // Asus G50V (and possibly others - G70? G71?)
 	{ },
 	{ },
 };
 };
 
 
 /* parameters of specific devices */
 /* parameters of specific devices */
-static struct oled_dev_desc_str oled_dev_desc_table [] = {
+static struct oled_dev_desc_str oled_dev_desc_table[] = {
 	{ 0x0b05, 0x1726, 128, PACK_MODE_G1, "G1/G2" },
 	{ 0x0b05, 0x1726, 128, PACK_MODE_G1, "G1/G2" },
 	{ 0x0b05, 0x175b, 256, PACK_MODE_G50, "G50" },
 	{ 0x0b05, 0x175b, 256, PACK_MODE_G50, "G50" },
 	{ },
 	{ },
 };
 };
 
 
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
 
 
 #define SETUP_PACKET_HEADER(packet, val1, val2, val3, val4, val5, val6, val7) \
 #define SETUP_PACKET_HEADER(packet, val1, val2, val3, val4, val5, val6, val7) \
 	do {					\
 	do {					\
@@ -107,7 +107,7 @@ MODULE_DEVICE_TABLE (usb, id_table);
 		packet->header.value6 = val5;		\
 		packet->header.value6 = val5;		\
 		packet->header.value7 = val6;		\
 		packet->header.value7 = val6;		\
 		packet->header.value8 = val7;		\
 		packet->header.value8 = val7;		\
-	} while(0);
+	} while (0);
 
 
 struct asus_oled_header {
 struct asus_oled_header {
 	uint8_t		magic1;
 	uint8_t		magic1;
@@ -160,10 +160,12 @@ static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
 
 
 	SETUP_PACKET_HEADER(packet, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00);
 	SETUP_PACKET_HEADER(packet, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00);
 
 
-	if (enabl) packet->bitmap[0] = 0xaf;
-	else packet->bitmap[0] = 0xae;
+	if (enabl)
+		packet->bitmap[0] = 0xaf;
+	else
+		packet->bitmap[0] = 0xae;
 
 
-	for (a=0; a<1; a++) {
+	for (a = 0; a < 1; a++) {
 		retval = usb_bulk_msg(odev->udev,
 		retval = usb_bulk_msg(odev->udev,
 			usb_sndbulkpipe(odev->udev, 2),
 			usb_sndbulkpipe(odev->udev, 2),
 			packet,
 			packet,
@@ -252,7 +254,7 @@ static void send_packets(struct usb_device *udev, struct asus_oled_packet *packe
 	}
 	}
 }
 }
 
 
-static void send_packet(struct usb_device *udev, struct asus_oled_packet *packet, size_t offset, size_t len, char *buf, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6){
+static void send_packet(struct usb_device *udev, struct asus_oled_packet *packet, size_t offset, size_t len, char *buf, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint8_t b6) {
 	int retval;
 	int retval;
 	int act_len;
 	int act_len;
 
 
@@ -294,7 +296,7 @@ static void send_data(struct asus_oled_dev *odev)
 		return;
 		return;
 	}
 	}
 
 
-	if (odev->pack_mode==PACK_MODE_G1){
+	if (odev->pack_mode == PACK_MODE_G1) {
 		// When sending roll-mode data the display updated only first packet.
 		// When sending roll-mode data the display updated only first packet.
 		// I have no idea why, but when static picture is send just before
 		// I have no idea why, but when static picture is send just before
 		// rolling picture - everything works fine.
 		// rolling picture - everything works fine.
@@ -308,7 +310,7 @@ static void send_data(struct asus_oled_dev *odev)
 		send_packets(odev->udev, packet, odev->buf, odev->pic_mode, packet_num);
 		send_packets(odev->udev, packet, odev->buf, odev->pic_mode, packet_num);
 	}
 	}
 	else
 	else
-	if (odev->pack_mode==PACK_MODE_G50){
+	if (odev->pack_mode == PACK_MODE_G50) {
 		send_packets_g50(odev->udev, packet, odev->buf);
 		send_packets_g50(odev->udev, packet, odev->buf);
 	}
 	}
 
 
@@ -326,7 +328,7 @@ static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count)
 			x += odev->x_shift;
 			x += odev->x_shift;
 			y += odev->y_shift;
 			y += odev->y_shift;
 
 
-			switch(odev->pack_mode)
+			switch (odev->pack_mode)
 			{
 			{
 				case PACK_MODE_G1:
 				case PACK_MODE_G1:
 					// i = (x/128)*640 + 127 - x + (y/8)*128;
 					// i = (x/128)*640 + 127 - x + (y/8)*128;
@@ -377,30 +379,32 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, siz
 {
 {
 	size_t offs = 0, max_offs;
 	size_t offs = 0, max_offs;
 
 
-	if (count < 1) return 0;
+	if (count < 1)
+		return 0;
 
 
-	if (tolower(buf[0]) == 'b'){
+	if (tolower(buf[0]) == 'b') {
 	    // binary mode, set the entire memory
 	    // binary mode, set the entire memory
 
 
 	    size_t i;
 	    size_t i;
 
 
 	    odev->buf_size = (odev->dev_width * ASUS_OLED_DISP_HEIGHT) / 8;
 	    odev->buf_size = (odev->dev_width * ASUS_OLED_DISP_HEIGHT) / 8;
 
 
-	    if (odev->buf) kfree(odev->buf);
+	    if (odev->buf)
+		    kfree(odev->buf);
 	    odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
 	    odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
 
 
 	    memset(odev->buf, 0xff, odev->buf_size);
 	    memset(odev->buf, 0xff, odev->buf_size);
 
 
-	    for (i=1; i < count && i<=32*32; i++){
+	    for (i = 1; i < count && i <= 32 * 32; i++) {
 		odev->buf[i-1] = buf[i];
 		odev->buf[i-1] = buf[i];
 		odev->buf_offs = i-1;
 		odev->buf_offs = i-1;
 	    }
 	    }
 
 
-	    odev->width=odev->dev_width / 8;
-	    odev->height=ASUS_OLED_DISP_HEIGHT;
-	    odev->x_shift=0;
-	    odev->y_shift=0;
-	    odev->last_val=0;
+	    odev->width = odev->dev_width / 8;
+	    odev->height = ASUS_OLED_DISP_HEIGHT;
+	    odev->x_shift = 0;
+	    odev->y_shift = 0;
+	    odev->last_val =  0;
 
 
 	    send_data(odev);
 	    send_data(odev);
 
 
@@ -416,7 +420,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, siz
 			goto error_header;
 			goto error_header;
 		}
 		}
 
 
-		switch(tolower(buf[1])) {
+		switch (tolower(buf[1])) {
 			case ASUS_OLED_STATIC:
 			case ASUS_OLED_STATIC:
 			case ASUS_OLED_ROLL:
 			case ASUS_OLED_ROLL:
 			case ASUS_OLED_FLASH:
 			case ASUS_OLED_FLASH:
@@ -432,27 +436,36 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, siz
 			if (buf[i] >= '0' && buf[i] <= '9') {
 			if (buf[i] >= '0' && buf[i] <= '9') {
 				w = 10*w + (buf[i] - '0');
 				w = 10*w + (buf[i] - '0');
 
 
-				if (w > ASUS_OLED_MAX_WIDTH) goto error_width;
+				if (w > ASUS_OLED_MAX_WIDTH)
+					goto error_width;
 			}
 			}
-			else if (tolower(buf[i]) == 'x') break;
-			else goto error_width;
+			else if (tolower(buf[i]) == 'x')
+				break;
+			else
+				goto error_width;
 		}
 		}
 
 
 		for (++i; i < count; ++i) {
 		for (++i; i < count; ++i) {
 			if (buf[i] >= '0' && buf[i] <= '9') {
 			if (buf[i] >= '0' && buf[i] <= '9') {
 				h = 10*h + (buf[i] - '0');
 				h = 10*h + (buf[i] - '0');
 
 
-				if (h > ASUS_OLED_DISP_HEIGHT) goto error_height;
+				if (h > ASUS_OLED_DISP_HEIGHT)
+					goto error_height;
 			}
 			}
-			else if (tolower(buf[i]) == '>') break;
-			else goto error_height;
+			else if (tolower(buf[i]) == '>')
+				break;
+			else
+				goto error_height;
 		}
 		}
 
 
-		if (w < 1 || w > ASUS_OLED_MAX_WIDTH) goto error_width;
+		if (w < 1 || w > ASUS_OLED_MAX_WIDTH)
+			goto error_width;
 
 
-		if (h < 1 || h > ASUS_OLED_DISP_HEIGHT) goto error_height;
+		if (h < 1 || h > ASUS_OLED_DISP_HEIGHT)
+			goto error_height;
 
 
-		if (i >= count || buf[i] != '>') goto error_header;
+		if (i >= count || buf[i] != '>')
+			goto error_header;
 
 
 		offs = i+1;
 		offs = i+1;
 
 
@@ -468,7 +481,8 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, siz
 
 
 		odev->buf_size = w_mem * h_mem / 8;
 		odev->buf_size = w_mem * h_mem / 8;
 
 
-		if (odev->buf) kfree(odev->buf);
+		if (odev->buf)
+			kfree(odev->buf);
 		odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
 		odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
 
 
 		if (odev->buf == NULL) {
 		if (odev->buf == NULL) {
@@ -505,23 +519,30 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, const char *buf, siz
 		int ret;
 		int ret;
 
 
 		if (buf[offs] == '1' || buf[offs] == '#') {
 		if (buf[offs] == '1' || buf[offs] == '#') {
-			if ( (ret = append_values(odev, 1, 1)) < 0) return ret;
+			ret = append_values(odev, 1, 1);
+			if (ret < 0)
+				return ret;
 		}
 		}
 		else if (buf[offs] == '0' || buf[offs] == ' ') {
 		else if (buf[offs] == '0' || buf[offs] == ' ') {
-			if ( (ret = append_values(odev, 0, 1)) < 0) return ret;
+			ret = append_values(odev, 0, 1);
+			if (ret < 0)
+				return ret;
 		}
 		}
 		else if (buf[offs] == '\n') {
 		else if (buf[offs] == '\n') {
 			// New line detected. Lets assume, that all characters till the end of the
 			// New line detected. Lets assume, that all characters till the end of the
 			// line were equal to the last character in this line.
 			// line were equal to the last character in this line.
 			if (odev->buf_offs % odev->width != 0)
 			if (odev->buf_offs % odev->width != 0)
-				if ( (ret = append_values(odev, odev->last_val,
-				      odev->width - (odev->buf_offs % odev->width))) < 0) return ret;
+				ret = append_values(odev, odev->last_val,
+				      odev->width - (odev->buf_offs % odev->width));
+				if (ret < 0)
+					return ret;
 		}
 		}
 
 
 		offs++;
 		offs++;
 	}
 	}
 
 
-	if (odev->buf_offs >= max_offs) send_data(odev);
+	if (odev->buf_offs >= max_offs)
+		send_data(odev);
 
 
 	return count;
 	return count;
 
 
@@ -566,9 +587,9 @@ static int asus_oled_probe(struct usb_interface *interface, const struct usb_dev
 	uint16_t dev_width = 0;
 	uint16_t dev_width = 0;
 	oled_pack_mode_t pack_mode = PACK_MODE_LAST;
 	oled_pack_mode_t pack_mode = PACK_MODE_LAST;
 	const struct oled_dev_desc_str * dev_desc = oled_dev_desc_table;
 	const struct oled_dev_desc_str * dev_desc = oled_dev_desc_table;
-	const char *desc = 0;
+	const char *desc = NULL;
 
 
-	if (id == 0) {
+	if (!id) {
 		// Even possible? Just to make sure...
 		// Even possible? Just to make sure...
 		dev_err(&interface->dev, "No usb_device_id provided!\n");
 		dev_err(&interface->dev, "No usb_device_id provided!\n");
 		return -ENODEV;
 		return -ENODEV;
@@ -586,7 +607,7 @@ static int asus_oled_probe(struct usb_interface *interface, const struct usb_dev
 		}
 		}
 	}
 	}
 
 
-	if ( !desc || dev_width < 1 || pack_mode == PACK_MODE_LAST) {
+	if (!desc || dev_width < 1 || pack_mode == PACK_MODE_LAST) {
 		dev_err(&interface->dev, "Missing or incomplete device description!\n");
 		dev_err(&interface->dev, "Missing or incomplete device description!\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -611,20 +632,20 @@ static int asus_oled_probe(struct usb_interface *interface, const struct usb_dev
 	odev->last_val = 0;
 	odev->last_val = 0;
 	odev->buf = NULL;
 	odev->buf = NULL;
 	odev->enabled = 1;
 	odev->enabled = 1;
-	odev->dev = 0;
+	odev->dev = NULL;
 
 
-	usb_set_intfdata (interface, odev);
+	usb_set_intfdata(interface, odev);
 
 
-	if ((retval = device_create_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled)))) {
+	retval = device_create_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
+	if (retval)
 		goto err_files;
 		goto err_files;
-	}
 
 
-	if ((retval = device_create_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture)))) {
+	retval = device_create_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
+	if (retval)
 		goto err_files;
 		goto err_files;
-	}
 
 
-	odev->dev = device_create(oled_class, &interface->dev, MKDEV(0,0),
-				NULL,"oled_%d", ++oled_num);
+	odev->dev = device_create(oled_class, &interface->dev, MKDEV(0, 0),
+				NULL, "oled_%d", ++oled_num);
 
 
 	if (IS_ERR(odev->dev)) {
 	if (IS_ERR(odev->dev)) {
 		retval = PTR_ERR(odev->dev);
 		retval = PTR_ERR(odev->dev);
@@ -633,13 +654,13 @@ static int asus_oled_probe(struct usb_interface *interface, const struct usb_dev
 
 
 	dev_set_drvdata(odev->dev, odev);
 	dev_set_drvdata(odev->dev, odev);
 
 
-	if ( (retval = device_create_file(odev->dev, &dev_attr_enabled))) {
+	retval = device_create_file(odev->dev, &dev_attr_enabled);
+	if (retval)
 		goto err_class_enabled;
 		goto err_class_enabled;
-	}
 
 
-	if ( (retval = device_create_file(odev->dev, &dev_attr_picture))) {
+	retval = device_create_file(odev->dev, &dev_attr_picture);
+	if (retval)
 		goto err_class_picture;
 		goto err_class_picture;
-	}
 
 
 	dev_info(&interface->dev, "Attached Asus OLED device: %s [width %u, pack_mode %d]\n", desc, odev->dev_width, odev->pack_mode);
 	dev_info(&interface->dev, "Attached Asus OLED device: %s [width %u, pack_mode %d]\n", desc, odev->dev_width, odev->pack_mode);
 
 
@@ -659,7 +680,7 @@ err_files:
 	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
 	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
 	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
 	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
 
 
-	usb_set_intfdata (interface, NULL);
+	usb_set_intfdata(interface, NULL);
 	usb_put_dev(odev->udev);
 	usb_put_dev(odev->udev);
 	kfree(odev);
 	kfree(odev);
 
 
@@ -670,19 +691,20 @@ static void asus_oled_disconnect(struct usb_interface *interface)
 {
 {
 	struct asus_oled_dev *odev;
 	struct asus_oled_dev *odev;
 
 
-	odev = usb_get_intfdata (interface);
-	usb_set_intfdata (interface, NULL);
+	odev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
 
 
 	device_remove_file(odev->dev, &dev_attr_picture);
 	device_remove_file(odev->dev, &dev_attr_picture);
 	device_remove_file(odev->dev, &dev_attr_enabled);
 	device_remove_file(odev->dev, &dev_attr_enabled);
 	device_unregister(odev->dev);
 	device_unregister(odev->dev);
 
 
-	device_remove_file(&interface->dev, & ASUS_OLED_DEVICE_ATTR(picture));
-	device_remove_file(&interface->dev, & ASUS_OLED_DEVICE_ATTR(enabled));
+	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
+	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
 
 
 	usb_put_dev(odev->udev);
 	usb_put_dev(odev->udev);
 
 
-	if (odev->buf) kfree(odev->buf);
+	if (odev->buf)
+		kfree(odev->buf);
 
 
 	kfree(odev);
 	kfree(odev);
 
 
@@ -713,7 +735,8 @@ static int __init asus_oled_init(void)
 		return PTR_ERR(oled_class);
 		return PTR_ERR(oled_class);
 	}
 	}
 
 
-	if ((retval = class_create_file(oled_class, &class_attr_version))) {
+	retval = class_create_file(oled_class, &class_attr_version);
+	if (retval) {
 		err("Error creating class version file");
 		err("Error creating class version file");
 		goto error;
 		goto error;
 	}
 	}
@@ -740,6 +763,6 @@ static void __exit asus_oled_exit(void)
 	usb_deregister(&oled_driver);
 	usb_deregister(&oled_driver);
 }
 }
 
 
-module_init (asus_oled_init);
-module_exit (asus_oled_exit);
+module_init(asus_oled_init);
+module_exit(asus_oled_exit);
 
 

+ 7 - 2
drivers/staging/at76_usb/TODO

@@ -1,2 +1,7 @@
-rewrite the driver to use the proper in-kernel wireless stack
-instead of using its own.
+Fix the mac80211 port of at76_usb (the proper in-kernel wireless
+stack) and get it included to the mainline. Patches available here:
+
+http://git.kernel.org/?p=linux/kernel/git/linville/wireless-legacy.git;a=shortlog;h=at76
+
+Contact Kalle Valo <kalle.valo@iki.fi> and linux-wireless list
+<linux-wireless@vger.kernel.org> for more information.

+ 10 - 11
drivers/staging/at76_usb/at76_usb.c

@@ -36,7 +36,7 @@
 #include <net/ieee80211_radiotap.h>
 #include <net/ieee80211_radiotap.h>
 #include <linux/firmware.h>
 #include <linux/firmware.h>
 #include <linux/leds.h>
 #include <linux/leds.h>
-#include <net/ieee80211.h>
+#include <linux/ieee80211.h>
 
 
 #include "at76_usb.h"
 #include "at76_usb.h"
 
 
@@ -1727,12 +1727,12 @@ static int at76_assoc_req(struct at76_priv *priv, struct bss_info *bss)
 
 
 	/* write TLV data elements */
 	/* write TLV data elements */
 
 
-	ie->id = MFIE_TYPE_SSID;
+	ie->id = WLAN_EID_SSID;
 	ie->len = bss->ssid_len;
 	ie->len = bss->ssid_len;
 	memcpy(ie->data, bss->ssid, bss->ssid_len);
 	memcpy(ie->data, bss->ssid, bss->ssid_len);
 	next_ie(&ie);
 	next_ie(&ie);
 
 
-	ie->id = MFIE_TYPE_RATES;
+	ie->id = WLAN_EID_SUPP_RATES;
 	ie->len = sizeof(hw_rates);
 	ie->len = sizeof(hw_rates);
 	memcpy(ie->data, hw_rates, sizeof(hw_rates));
 	memcpy(ie->data, hw_rates, sizeof(hw_rates));
 	next_ie(&ie);		/* ie points behind the supp_rates field */
 	next_ie(&ie);		/* ie points behind the supp_rates field */
@@ -4397,7 +4397,7 @@ static void at76_rx_mgmt_beacon(struct at76_priv *priv,
 
 
 		switch (ie->id) {
 		switch (ie->id) {
 
 
-		case MFIE_TYPE_SSID:
+		case WLAN_EID_SSID:
 			if (have_ssid)
 			if (have_ssid)
 				break;
 				break;
 
 
@@ -4420,7 +4420,7 @@ static void at76_rx_mgmt_beacon(struct at76_priv *priv,
 			have_ssid = 1;
 			have_ssid = 1;
 			break;
 			break;
 
 
-		case MFIE_TYPE_RATES:
+		case WLAN_EID_SUPP_RATES:
 			if (have_rates)
 			if (have_rates)
 				break;
 				break;
 
 
@@ -4433,7 +4433,7 @@ static void at76_rx_mgmt_beacon(struct at76_priv *priv,
 				 hex2str(ie->data, ie->len));
 				 hex2str(ie->data, ie->len));
 			break;
 			break;
 
 
-		case MFIE_TYPE_DS_SET:
+		case WLAN_EID_DS_PARAMS:
 			if (have_channel)
 			if (have_channel)
 				break;
 				break;
 
 
@@ -4443,9 +4443,9 @@ static void at76_rx_mgmt_beacon(struct at76_priv *priv,
 				 priv->netdev->name, match->channel);
 				 priv->netdev->name, match->channel);
 			break;
 			break;
 
 
-		case MFIE_TYPE_CF_SET:
-		case MFIE_TYPE_TIM:
-		case MFIE_TYPE_IBSS_SET:
+		case WLAN_EID_CF_PARAMS:
+		case WLAN_EID_TIM:
+		case WLAN_EID_IBSS_PARAMS:
 		default:
 		default:
 			at76_dbg(DBG_RX_BEACON, "%s: beacon IE id %d len %d %s",
 			at76_dbg(DBG_RX_BEACON, "%s: beacon IE id %d len %d %s",
 				 priv->netdev->name, ie->id, ie->len,
 				 priv->netdev->name, ie->id, ie->len,
@@ -5370,8 +5370,7 @@ static void at76_delete_device(struct at76_priv *priv)
 
 
 	at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__);
 	at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__);
 
 
-	if (priv->rx_skb)
-		kfree_skb(priv->rx_skb);
+	kfree_skb(priv->rx_skb);
 
 
 	at76_free_bss_list(priv);
 	at76_free_bss_list(priv);
 	del_timer_sync(&priv->bss_list_timer);
 	del_timer_sync(&priv->bss_list_timer);

+ 87 - 0
drivers/staging/at76_usb/at76_usb.h

@@ -22,6 +22,93 @@
 #ifndef _AT76_USB_H
 #ifndef _AT76_USB_H
 #define _AT76_USB_H
 #define _AT76_USB_H
 
 
+/*
+ * ieee80211 definitions copied from net/ieee80211.h
+ */
+
+#define WEP_KEY_LEN		13
+#define WEP_KEYS		4
+
+#define IEEE80211_DATA_LEN		2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+#define IEEE80211_1ADDR_LEN 10
+#define IEEE80211_2ADDR_LEN 16
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN    4
+#define IEEE80211_HLEN			(IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN		(IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+#define MIN_FRAG_THRESHOLD     256U
+#define	MAX_FRAG_THRESHOLD     2346U
+
+struct ieee80211_info_element {
+	u8 id;
+	u8 len;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr {
+	__le16 frame_ctl;
+	__le16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	__le16 seq_ctl;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+struct ieee80211_auth {
+	struct ieee80211_hdr_3addr header;
+	__le16 algorithm;
+	__le16 transaction;
+	__le16 status;
+	/* challenge */
+	struct ieee80211_info_element info_element[0];
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_request {
+	struct ieee80211_hdr_3addr header;
+	__le16 capability;
+	__le16 listen_interval;
+	/* SSID, supported rates, RSN */
+	struct ieee80211_info_element info_element[0];
+} __attribute__ ((packed));
+
+struct ieee80211_probe_response {
+	struct ieee80211_hdr_3addr header;
+	__le32 time_stamp[2];
+	__le16 beacon_interval;
+	__le16 capability;
+	/* SSID, supported rates, FH params, DS params,
+	 * CF params, IBSS params, TIM (if beacon), RSN */
+	struct ieee80211_info_element info_element[0];
+} __attribute__ ((packed));
+
+/* Alias beacon for probe_response */
+#define ieee80211_beacon ieee80211_probe_response
+
+struct ieee80211_assoc_response {
+	struct ieee80211_hdr_3addr header;
+	__le16 capability;
+	__le16 status;
+	__le16 aid;
+	/* supported rates */
+	struct ieee80211_info_element info_element[0];
+} __attribute__ ((packed));
+
+struct ieee80211_disassoc {
+	struct ieee80211_hdr_3addr header;
+	__le16 reason;
+} __attribute__ ((packed));
+
 /* Board types */
 /* Board types */
 enum board_type {
 enum board_type {
 	BOARD_503_ISL3861 = 1,
 	BOARD_503_ISL3861 = 1,

+ 9 - 0
drivers/staging/b3dfg/Kconfig

@@ -0,0 +1,9 @@
+config B3DFG
+       tristate "Brontes 3d Frame Framegrabber"
+       default n
+       ---help---
+         This driver provides support for the Brontes 3d Framegrabber
+         PCI card.
+
+         To compile this driver as a module, choose M here. The module
+         will be called b3dfg.

+ 1 - 0
drivers/staging/b3dfg/Makefile

@@ -0,0 +1 @@
+obj-$(CONFIG_B3DFG) += b3dfg.o

+ 4 - 0
drivers/staging/b3dfg/TODO

@@ -0,0 +1,4 @@
+
+ - queue/wait buffer presents filltime results for each frame?
+ - counting of dropped frames
+ - review endianness

+ 1119 - 0
drivers/staging/b3dfg/b3dfg.c

@@ -0,0 +1,1119 @@
+ /*
+ * Brontes PCI frame grabber driver
+ *
+ * Copyright (C) 2008 3M Company
+ * Contact: Justin Bronder <jsbronder@brontes3d.com>
+ * Original Authors: Daniel Drake <ddrake@brontes3d.com>
+ *                   Duane Griffin <duaneg@dghda.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/uaccess.h>
+
+static unsigned int b3dfg_nbuf = 2;
+
+module_param_named(buffer_count, b3dfg_nbuf, uint, 0444);
+
+MODULE_PARM_DESC(buffer_count, "Number of buffers (min 2, default 2)\n");
+
+MODULE_AUTHOR("Daniel Drake <ddrake@brontes3d.com>");
+MODULE_DESCRIPTION("Brontes frame grabber driver");
+MODULE_LICENSE("GPL");
+
+#define DRIVER_NAME "b3dfg"
+#define B3DFG_MAX_DEVS 4
+#define B3DFG_FRAMES_PER_BUFFER 3
+
+#define B3DFG_BAR_REGS	0
+#define B3DFG_REGS_LENGTH 0x10000
+
+#define B3DFG_IOC_MAGIC		0xb3 /* dfg :-) */
+#define B3DFG_IOCGFRMSZ		_IOR(B3DFG_IOC_MAGIC, 1, int)
+#define B3DFG_IOCTNUMBUFS	_IO(B3DFG_IOC_MAGIC, 2)
+#define B3DFG_IOCTTRANS		_IO(B3DFG_IOC_MAGIC, 3)
+#define B3DFG_IOCTQUEUEBUF	_IO(B3DFG_IOC_MAGIC, 4)
+#define B3DFG_IOCTPOLLBUF	_IOWR(B3DFG_IOC_MAGIC, 5, struct b3dfg_poll)
+#define B3DFG_IOCTWAITBUF	_IOWR(B3DFG_IOC_MAGIC, 6, struct b3dfg_wait)
+#define B3DFG_IOCGWANDSTAT	_IOR(B3DFG_IOC_MAGIC, 7, int)
+
+enum {
+	/* number of 4kb pages per frame */
+	B3D_REG_FRM_SIZE = 0x0,
+
+	/* bit 0: set to enable interrupts
+	 * bit 1: set to enable cable status change interrupts */
+	B3D_REG_HW_CTRL = 0x4,
+
+	/* bit 0-1 - 1-based ID of next pending frame transfer (0 = none)
+	 * bit 2 indicates the previous DMA transfer has completed
+	 * bit 3 indicates wand cable status change
+	 * bit 8:15 - counter of number of discarded triplets */
+	B3D_REG_DMA_STS = 0x8,
+
+	/* bit 0: wand status (1 = present, 0 = disconnected) */
+	B3D_REG_WAND_STS = 0xc,
+
+	/* bus address for DMA transfers. lower 2 bits must be zero because DMA
+	 * works with 32 bit word size. */
+	B3D_REG_EC220_DMA_ADDR = 0x8000,
+
+	/* bit 20:0 - number of 32 bit words to be transferred
+	 * bit 21:31 - reserved */
+	B3D_REG_EC220_TRF_SIZE = 0x8004,
+
+	/* bit 0 - error bit
+	 * bit 1 - interrupt bit (set to generate interrupt at end of transfer)
+	 * bit 2 - start bit (set to start transfer)
+	 * bit 3 - direction (0 = DMA_TO_DEVICE, 1 = DMA_FROM_DEVICE
+	 * bit 4:31 - reserved */
+	B3D_REG_EC220_DMA_STS = 0x8008,
+};
+
+enum b3dfg_buffer_state {
+	B3DFG_BUFFER_POLLED = 0,
+	B3DFG_BUFFER_PENDING,
+	B3DFG_BUFFER_POPULATED,
+};
+
+struct b3dfg_buffer {
+	unsigned char *frame[B3DFG_FRAMES_PER_BUFFER];
+	struct list_head list;
+	u8 state;
+};
+
+struct b3dfg_dev {
+
+	/* no protection needed: all finalized at initialization time */
+	struct pci_dev *pdev;
+	struct cdev chardev;
+	struct device *dev;
+	void __iomem *regs;
+	unsigned int frame_size;
+
+	/*
+	 * Protects buffer state, including buffer_queue, triplet_ready,
+	 * cur_dma_frame_idx & cur_dma_frame_addr.
+	 */
+	spinlock_t buffer_lock;
+	struct b3dfg_buffer *buffers;
+	struct list_head buffer_queue;
+
+	/* Last frame in triplet transferred (-1 if none). */
+	int cur_dma_frame_idx;
+
+	/* Current frame's address for DMA. */
+	dma_addr_t cur_dma_frame_addr;
+
+	/*
+	 * Protects cstate_tstamp.
+	 * Nests inside buffer_lock.
+	 */
+	spinlock_t cstate_lock;
+	unsigned long cstate_tstamp;
+
+	/*
+	 * Protects triplets_dropped.
+	 * Nests inside buffers_lock.
+	 */
+	spinlock_t triplets_dropped_lock;
+	unsigned int triplets_dropped;
+
+	wait_queue_head_t buffer_waitqueue;
+
+	unsigned int transmission_enabled:1;
+	unsigned int triplet_ready:1;
+};
+
+static u8 b3dfg_devices[B3DFG_MAX_DEVS];
+
+static struct class *b3dfg_class;
+static dev_t b3dfg_devt;
+
+static const struct pci_device_id b3dfg_ids[] __devinitdata = {
+	{ PCI_DEVICE(0x0b3d, 0x0001) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, b3dfg_ids);
+
+/***** user-visible types *****/
+
+struct b3dfg_poll {
+	int buffer_idx;
+	unsigned int triplets_dropped;
+};
+
+struct b3dfg_wait {
+	int buffer_idx;
+	unsigned int timeout;
+	unsigned int triplets_dropped;
+};
+
+/**** register I/O ****/
+
+static u32 b3dfg_read32(struct b3dfg_dev *fgdev, u16 reg)
+{
+	return ioread32(fgdev->regs + reg);
+}
+
+static void b3dfg_write32(struct b3dfg_dev *fgdev, u16 reg, u32 value)
+{
+	iowrite32(value, fgdev->regs + reg);
+}
+
+/**** buffer management ****/
+
+/*
+ * Program EC220 for transfer of a specific frame.
+ * Called with buffer_lock held.
+ */
+static int setup_frame_transfer(struct b3dfg_dev *fgdev,
+	struct b3dfg_buffer *buf, int frame)
+{
+	unsigned char *frm_addr;
+	dma_addr_t frm_addr_dma;
+	unsigned int frm_size = fgdev->frame_size;
+
+	frm_addr = buf->frame[frame];
+	frm_addr_dma = pci_map_single(fgdev->pdev, frm_addr,
+					  frm_size, PCI_DMA_FROMDEVICE);
+	if (pci_dma_mapping_error(fgdev->pdev, frm_addr_dma))
+		return -ENOMEM;
+
+	fgdev->cur_dma_frame_addr = frm_addr_dma;
+	fgdev->cur_dma_frame_idx = frame;
+
+	b3dfg_write32(fgdev, B3D_REG_EC220_DMA_ADDR,
+					cpu_to_le32(frm_addr_dma));
+	b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE,
+					cpu_to_le32(frm_size >> 2));
+	b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0xf);
+
+	return 0;
+}
+
+/* Caller should hold buffer lock */
+static void dequeue_all_buffers(struct b3dfg_dev *fgdev)
+{
+	int i;
+	for (i = 0; i < b3dfg_nbuf; i++) {
+		struct b3dfg_buffer *buf = &fgdev->buffers[i];
+		buf->state = B3DFG_BUFFER_POLLED;
+		list_del_init(&buf->list);
+	}
+}
+
+/* queue a buffer to receive data */
+static int queue_buffer(struct b3dfg_dev *fgdev, int bufidx)
+{
+	struct device *dev = &fgdev->pdev->dev;
+	struct b3dfg_buffer *buf;
+	unsigned long flags;
+	int r = 0;
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+	if (bufidx < 0 || bufidx >= b3dfg_nbuf) {
+		dev_dbg(dev, "Invalid buffer index, %d\n", bufidx);
+		r = -ENOENT;
+		goto out;
+	}
+	buf = &fgdev->buffers[bufidx];
+
+	if (unlikely(buf->state == B3DFG_BUFFER_PENDING)) {
+		dev_dbg(dev, "buffer %d is already queued\n", bufidx);
+		r = -EINVAL;
+		goto out;
+	}
+
+	buf->state = B3DFG_BUFFER_PENDING;
+	list_add_tail(&buf->list, &fgdev->buffer_queue);
+
+	if (fgdev->transmission_enabled && fgdev->triplet_ready) {
+		dev_dbg(dev, "triplet is ready, pushing immediately\n");
+		fgdev->triplet_ready = 0;
+		r = setup_frame_transfer(fgdev, buf, 0);
+		if (r)
+			dev_err(dev, "unable to map DMA buffer\n");
+	}
+
+out:
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+	return r;
+}
+
+/* non-blocking buffer poll. returns 1 if data is present in the buffer,
+ * 0 otherwise */
+static int poll_buffer(struct b3dfg_dev *fgdev, void __user *arg)
+{
+	struct device *dev = &fgdev->pdev->dev;
+	struct b3dfg_poll p;
+	struct b3dfg_buffer *buf;
+	unsigned long flags;
+	int r = 1;
+	int arg_out = 0;
+
+	if (copy_from_user(&p, arg, sizeof(p)))
+		return -EFAULT;
+
+	if (unlikely(!fgdev->transmission_enabled)) {
+		dev_dbg(dev, "cannot poll, transmission disabled\n");
+		return -EINVAL;
+	}
+
+	if (p.buffer_idx < 0 || p.buffer_idx >= b3dfg_nbuf)
+		return -ENOENT;
+
+	buf = &fgdev->buffers[p.buffer_idx];
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+
+	if (likely(buf->state == B3DFG_BUFFER_POPULATED)) {
+		arg_out = 1;
+		buf->state = B3DFG_BUFFER_POLLED;
+
+		/* IRQs already disabled by spin_lock_irqsave above. */
+		spin_lock(&fgdev->triplets_dropped_lock);
+		p.triplets_dropped = fgdev->triplets_dropped;
+		fgdev->triplets_dropped = 0;
+		spin_unlock(&fgdev->triplets_dropped_lock);
+	} else {
+		r = 0;
+	}
+
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+	if (arg_out && copy_to_user(arg, &p, sizeof(p)))
+		r = -EFAULT;
+
+	return r;
+}
+
+static unsigned long get_cstate_change(struct b3dfg_dev *fgdev)
+{
+	unsigned long flags, when;
+
+	spin_lock_irqsave(&fgdev->cstate_lock, flags);
+	when = fgdev->cstate_tstamp;
+	spin_unlock_irqrestore(&fgdev->cstate_lock, flags);
+	return when;
+}
+
+static int is_event_ready(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf,
+			  unsigned long when)
+{
+	int result;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+	spin_lock(&fgdev->cstate_lock);
+	result = (!fgdev->transmission_enabled ||
+		  buf->state == B3DFG_BUFFER_POPULATED ||
+		  when != fgdev->cstate_tstamp);
+	spin_unlock(&fgdev->cstate_lock);
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+	return result;
+}
+
+/* sleep until a specific buffer becomes populated */
+static int wait_buffer(struct b3dfg_dev *fgdev, void __user *arg)
+{
+	struct device *dev = &fgdev->pdev->dev;
+	struct b3dfg_wait w;
+	struct b3dfg_buffer *buf;
+	unsigned long flags, when;
+	int r;
+
+	if (copy_from_user(&w, arg, sizeof(w)))
+		return -EFAULT;
+
+	if (!fgdev->transmission_enabled) {
+		dev_dbg(dev, "cannot wait, transmission disabled\n");
+		return -EINVAL;
+	}
+
+	if (w.buffer_idx < 0 || w.buffer_idx >= b3dfg_nbuf)
+		return -ENOENT;
+
+	buf = &fgdev->buffers[w.buffer_idx];
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+
+	if (buf->state == B3DFG_BUFFER_POPULATED) {
+		r = w.timeout;
+		goto out_triplets_dropped;
+	}
+
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+	when = get_cstate_change(fgdev);
+	if (w.timeout > 0) {
+		r = wait_event_interruptible_timeout(fgdev->buffer_waitqueue,
+			is_event_ready(fgdev, buf, when),
+			(w.timeout * HZ) / 1000);
+
+		if (unlikely(r < 0))
+			goto out;
+
+		w.timeout = r * 1000 / HZ;
+	} else {
+		r = wait_event_interruptible(fgdev->buffer_waitqueue,
+			is_event_ready(fgdev, buf, when));
+
+		if (unlikely(r)) {
+			r = -ERESTARTSYS;
+			goto out;
+		}
+	}
+
+	/* TODO: Inform the user via field(s) in w? */
+	if (!fgdev->transmission_enabled || when != get_cstate_change(fgdev)) {
+		r = -EINVAL;
+		goto out;
+	}
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+
+	if (buf->state != B3DFG_BUFFER_POPULATED) {
+		r = -ETIMEDOUT;
+		goto out_unlock;
+	}
+
+	buf->state = B3DFG_BUFFER_POLLED;
+
+out_triplets_dropped:
+
+	/* IRQs already disabled by spin_lock_irqsave above. */
+	spin_lock(&fgdev->triplets_dropped_lock);
+	w.triplets_dropped = fgdev->triplets_dropped;
+	fgdev->triplets_dropped = 0;
+	spin_unlock(&fgdev->triplets_dropped_lock);
+
+out_unlock:
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+	if (copy_to_user(arg, &w, sizeof(w)))
+		r = -EFAULT;
+out:
+	return r;
+}
+
+/* mmap page fault handler */
+static int b3dfg_vma_fault(struct vm_area_struct *vma,
+	struct vm_fault *vmf)
+{
+	struct b3dfg_dev *fgdev = vma->vm_file->private_data;
+	unsigned long off = vmf->pgoff << PAGE_SHIFT;
+	unsigned int frame_size = fgdev->frame_size;
+	unsigned int buf_size = frame_size * B3DFG_FRAMES_PER_BUFFER;
+	unsigned char *addr;
+
+	/* determine which buffer the offset lies within */
+	unsigned int buf_idx = off / buf_size;
+	/* and the offset into the buffer */
+	unsigned int buf_off = off % buf_size;
+
+	/* determine which frame inside the buffer the offset lies in */
+	unsigned int frm_idx = buf_off / frame_size;
+	/* and the offset into the frame */
+	unsigned int frm_off = buf_off % frame_size;
+
+	if (unlikely(buf_idx >= b3dfg_nbuf))
+		return VM_FAULT_SIGBUS;
+
+	addr = fgdev->buffers[buf_idx].frame[frm_idx] + frm_off;
+	vm_insert_pfn(vma, (unsigned long)vmf->virtual_address,
+			  virt_to_phys(addr) >> PAGE_SHIFT);
+
+	return VM_FAULT_NOPAGE;
+}
+
+static struct vm_operations_struct b3dfg_vm_ops = {
+	.fault = b3dfg_vma_fault,
+};
+
+static int get_wand_status(struct b3dfg_dev *fgdev, int __user *arg)
+{
+	u32 wndstat = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
+	dev_dbg(&fgdev->pdev->dev, "wand status %x\n", wndstat);
+	return __put_user(wndstat & 0x1, arg);
+}
+
+static int enable_transmission(struct b3dfg_dev *fgdev)
+{
+	u16 command;
+	unsigned long flags;
+	struct device *dev = &fgdev->pdev->dev;
+
+	dev_dbg(dev, "enable transmission\n");
+
+	/* check the cable is plugged in. */
+	if (!b3dfg_read32(fgdev, B3D_REG_WAND_STS)) {
+		dev_dbg(dev, "cannot start transmission without wand\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Check we're a bus master.
+	 * TODO: I think we can remove this having added the pci_set_master call
+	 */
+	pci_read_config_word(fgdev->pdev, PCI_COMMAND, &command);
+	if (!(command & PCI_COMMAND_MASTER)) {
+		dev_err(dev, "not a bus master, force-enabling\n");
+		pci_write_config_word(fgdev->pdev, PCI_COMMAND,
+			command | PCI_COMMAND_MASTER);
+	}
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+
+	/* Handle racing enable_transmission calls. */
+	if (fgdev->transmission_enabled) {
+		spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+		goto out;
+	}
+
+	spin_lock(&fgdev->triplets_dropped_lock);
+	fgdev->triplets_dropped = 0;
+	spin_unlock(&fgdev->triplets_dropped_lock);
+
+	fgdev->triplet_ready = 0;
+	fgdev->cur_dma_frame_idx = -1;
+	fgdev->transmission_enabled = 1;
+
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+	/* Enable DMA and cable status interrupts. */
+	b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0x03);
+
+out:
+	return 0;
+}
+
+static void disable_transmission(struct b3dfg_dev *fgdev)
+{
+	struct device *dev = &fgdev->pdev->dev;
+	unsigned long flags;
+	u32 tmp;
+
+	dev_dbg(dev, "disable transmission\n");
+
+	/* guarantee that no more interrupts will be serviced */
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+	fgdev->transmission_enabled = 0;
+
+	b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
+
+	/* FIXME: temporary debugging only. if the board stops transmitting,
+	 * hitting ctrl+c and seeing this message is useful for determining
+	 * the state of the board. */
+	tmp = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
+	dev_dbg(dev, "DMA_STS reads %x after TX stopped\n", tmp);
+
+	dequeue_all_buffers(fgdev);
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+	wake_up_interruptible(&fgdev->buffer_waitqueue);
+}
+
+static int set_transmission(struct b3dfg_dev *fgdev, int enabled)
+{
+	int res = 0;
+
+	if (enabled && !fgdev->transmission_enabled)
+		res = enable_transmission(fgdev);
+	else if (!enabled && fgdev->transmission_enabled)
+		disable_transmission(fgdev);
+
+	return res;
+}
+
+/* Called in interrupt context. */
+static void handle_cstate_unplug(struct b3dfg_dev *fgdev)
+{
+	/* Disable all interrupts. */
+	b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
+
+	/* Stop transmission. */
+	spin_lock(&fgdev->buffer_lock);
+	fgdev->transmission_enabled = 0;
+
+	fgdev->cur_dma_frame_idx = -1;
+	fgdev->triplet_ready = 0;
+	if (fgdev->cur_dma_frame_addr) {
+		pci_unmap_single(fgdev->pdev, fgdev->cur_dma_frame_addr,
+				 fgdev->frame_size, PCI_DMA_FROMDEVICE);
+		fgdev->cur_dma_frame_addr = 0;
+	}
+	dequeue_all_buffers(fgdev);
+	spin_unlock(&fgdev->buffer_lock);
+}
+
+/* Called in interrupt context. */
+static void handle_cstate_change(struct b3dfg_dev *fgdev)
+{
+	u32 cstate = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
+	unsigned long when;
+	struct device *dev = &fgdev->pdev->dev;
+
+	dev_dbg(dev, "cable state change: %u\n", cstate);
+
+	/*
+	 * When the wand is unplugged we reset our state. The hardware will
+	 * have done the same internally.
+	 *
+	 * Note we should never see a cable *plugged* event, as interrupts
+	 * should only be enabled when transmitting, which requires the cable
+	 * to be plugged. If we do see one it probably means the cable has been
+	 * unplugged and re-plugged very rapidly. Possibly because it has a
+	 * broken wire and is momentarily losing contact.
+	 *
+	 * TODO: At the moment if you plug in the cable then enable transmission
+	 * the hardware will raise a couple of spurious interrupts, so
+	 * just ignore them for now.
+	 *
+	 * Once the hardware is fixed we should complain and treat it as an
+	 * unplug. Or at least track how frequently it is happening and do
+	 * so if too many come in.
+	 */
+	if (cstate) {
+		dev_warn(dev, "ignoring unexpected plug event\n");
+		return;
+	}
+	handle_cstate_unplug(fgdev);
+
+	/*
+	 * Record cable state change timestamp & wake anyone waiting
+	 * on a cable state change. Be paranoid about ensuring events
+	 * are not missed if we somehow get two interrupts in a jiffy.
+	 */
+	spin_lock(&fgdev->cstate_lock);
+	when = jiffies_64;
+	if (when <= fgdev->cstate_tstamp)
+		when = fgdev->cstate_tstamp + 1;
+	fgdev->cstate_tstamp = when;
+	wake_up_interruptible(&fgdev->buffer_waitqueue);
+	spin_unlock(&fgdev->cstate_lock);
+}
+
+/* Called with buffer_lock held. */
+static void transfer_complete(struct b3dfg_dev *fgdev)
+{
+	struct b3dfg_buffer *buf;
+	struct device *dev = &fgdev->pdev->dev;
+
+	pci_unmap_single(fgdev->pdev, fgdev->cur_dma_frame_addr,
+			 fgdev->frame_size, PCI_DMA_FROMDEVICE);
+	fgdev->cur_dma_frame_addr = 0;
+
+	buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
+	if (buf) {
+		dev_dbg(dev, "handle frame completion\n");
+		if (fgdev->cur_dma_frame_idx == B3DFG_FRAMES_PER_BUFFER - 1) {
+
+			/* last frame of that triplet completed */
+			dev_dbg(dev, "triplet completed\n");
+			buf->state = B3DFG_BUFFER_POPULATED;
+			list_del_init(&buf->list);
+			wake_up_interruptible(&fgdev->buffer_waitqueue);
+		}
+	} else {
+		dev_err(dev, "got frame but no buffer!\n");
+	}
+}
+
+/*
+ * Called with buffer_lock held.
+ *
+ * Note that idx is the (1-based) *next* frame to be transferred, while
+ * cur_dma_frame_idx is the (0-based) *last* frame to have been transferred (or
+ * -1 if none). Thus there should be a difference of 2 between them.
+ */
+static bool setup_next_frame_transfer(struct b3dfg_dev *fgdev, int idx)
+{
+	struct b3dfg_buffer *buf;
+	struct device *dev = &fgdev->pdev->dev;
+	bool need_ack = 1;
+
+	dev_dbg(dev, "program DMA transfer for next frame: %d\n", idx);
+
+	buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
+	if (buf) {
+		if (idx == fgdev->cur_dma_frame_idx + 2) {
+			if (setup_frame_transfer(fgdev, buf, idx - 1))
+				dev_err(dev, "unable to map DMA buffer\n");
+			need_ack = 0;
+		} else {
+			dev_err(dev, "frame mismatch, got %d, expected %d\n",
+				idx, fgdev->cur_dma_frame_idx + 2);
+
+			/* FIXME: handle dropped triplets here */
+		}
+	} else {
+		dev_err(dev, "cannot setup DMA, no buffer\n");
+	}
+
+	return need_ack;
+}
+
+static irqreturn_t b3dfg_intr(int irq, void *dev_id)
+{
+	struct b3dfg_dev *fgdev = dev_id;
+	struct device *dev = &fgdev->pdev->dev;
+	u32 sts;
+	u8 dropped;
+	bool need_ack = 1;
+	irqreturn_t res = IRQ_HANDLED;
+
+	sts = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
+	if (unlikely(sts == 0)) {
+		dev_warn(dev, "ignore interrupt, DMA status is 0\n");
+		res = IRQ_NONE;
+		goto out;
+	}
+
+	if (unlikely(!fgdev->transmission_enabled)) {
+		dev_warn(dev, "ignore interrupt, TX disabled\n");
+		res = IRQ_HANDLED;
+		goto out;
+	}
+
+	/* Handle dropped frames, as reported by the hardware. */
+	dropped = (sts >> 8) & 0xff;
+	dev_dbg(dev, "intr: DMA_STS=%08x (drop=%d comp=%d next=%d)\n",
+		sts, dropped, !!(sts & 0x4), sts & 0x3);
+	if (unlikely(dropped > 0)) {
+		spin_lock(&fgdev->triplets_dropped_lock);
+		fgdev->triplets_dropped += dropped;
+		spin_unlock(&fgdev->triplets_dropped_lock);
+	}
+
+	/* Handle a cable state change (i.e. the wand being unplugged). */
+	if (sts & 0x08) {
+		handle_cstate_change(fgdev);
+		goto out;
+	}
+
+	spin_lock(&fgdev->buffer_lock);
+	if (unlikely(list_empty(&fgdev->buffer_queue))) {
+
+		/* FIXME need more sanity checking here */
+		dev_info(dev, "buffer not ready for next transfer\n");
+		fgdev->triplet_ready = 1;
+		goto out_unlock;
+	}
+
+	/* Has a frame transfer been completed? */
+	if (sts & 0x4) {
+		u32 dma_status = b3dfg_read32(fgdev, B3D_REG_EC220_DMA_STS);
+
+		/* Check for DMA errors reported by the hardware. */
+		if (unlikely(dma_status & 0x1)) {
+			dev_err(dev, "EC220 error: %08x\n", dma_status);
+
+			/* FIXME flesh out error handling */
+			goto out_unlock;
+		}
+
+		/* Sanity check, we should have a frame index at this point. */
+		if (unlikely(fgdev->cur_dma_frame_idx == -1)) {
+			dev_err(dev, "completed but no last idx?\n");
+
+			/* FIXME flesh out error handling */
+			goto out_unlock;
+		}
+
+		transfer_complete(fgdev);
+	}
+
+	/* Is there another frame transfer pending? */
+	if (sts & 0x3)
+		need_ack = setup_next_frame_transfer(fgdev, sts & 0x3);
+	else
+		fgdev->cur_dma_frame_idx = -1;
+
+out_unlock:
+	spin_unlock(&fgdev->buffer_lock);
+out:
+	if (need_ack) {
+		dev_dbg(dev, "acknowledging interrupt\n");
+		b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0x0b);
+	}
+	return res;
+}
+
+static int b3dfg_open(struct inode *inode, struct file *filp)
+{
+	struct b3dfg_dev *fgdev =
+		container_of(inode->i_cdev, struct b3dfg_dev, chardev);
+
+	dev_dbg(&fgdev->pdev->dev, "open\n");
+	filp->private_data = fgdev;
+	return 0;
+}
+
+static int b3dfg_release(struct inode *inode, struct file *filp)
+{
+	struct b3dfg_dev *fgdev = filp->private_data;
+	dev_dbg(&fgdev->pdev->dev, "release\n");
+	disable_transmission(fgdev);
+	return 0;
+}
+
+static long b3dfg_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct b3dfg_dev *fgdev = filp->private_data;
+
+	switch (cmd) {
+	case B3DFG_IOCGFRMSZ:
+		return __put_user(fgdev->frame_size, (int __user *) arg);
+	case B3DFG_IOCGWANDSTAT:
+		return get_wand_status(fgdev, (int __user *) arg);
+	case B3DFG_IOCTTRANS:
+		return set_transmission(fgdev, (int) arg);
+	case B3DFG_IOCTQUEUEBUF:
+		return queue_buffer(fgdev, (int) arg);
+	case B3DFG_IOCTPOLLBUF:
+		return poll_buffer(fgdev, (void __user *) arg);
+	case B3DFG_IOCTWAITBUF:
+		return wait_buffer(fgdev, (void __user *) arg);
+	default:
+		dev_dbg(&fgdev->pdev->dev, "unrecognised ioctl %x\n", cmd);
+		return -EINVAL;
+	}
+}
+
+static unsigned int b3dfg_poll(struct file *filp, poll_table *poll_table)
+{
+	struct b3dfg_dev *fgdev = filp->private_data;
+	unsigned long flags, when;
+	int i;
+	int r = 0;
+
+	when = get_cstate_change(fgdev);
+	poll_wait(filp, &fgdev->buffer_waitqueue, poll_table);
+
+	spin_lock_irqsave(&fgdev->buffer_lock, flags);
+	for (i = 0; i < b3dfg_nbuf; i++) {
+		if (fgdev->buffers[i].state == B3DFG_BUFFER_POPULATED) {
+			r = POLLIN | POLLRDNORM;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+	/* TODO: Confirm this is how we want to communicate the change. */
+	if (!fgdev->transmission_enabled || when != get_cstate_change(fgdev))
+		r = POLLERR;
+
+	return r;
+}
+
+static int b3dfg_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct b3dfg_dev *fgdev = filp->private_data;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long vsize = vma->vm_end - vma->vm_start;
+	unsigned long bufdatalen = b3dfg_nbuf * fgdev->frame_size * 3;
+	unsigned long psize = bufdatalen - offset;
+	int r = 0;
+
+	if (vsize <= psize) {
+		vma->vm_flags |= VM_IO | VM_RESERVED | VM_CAN_NONLINEAR |
+				 VM_PFNMAP;
+		vma->vm_ops = &b3dfg_vm_ops;
+	} else {
+		r = -EINVAL;
+	}
+
+	return r;
+}
+
+static struct file_operations b3dfg_fops = {
+	.owner = THIS_MODULE,
+	.open = b3dfg_open,
+	.release = b3dfg_release,
+	.unlocked_ioctl = b3dfg_ioctl,
+	.poll = b3dfg_poll,
+	.mmap = b3dfg_mmap,
+};
+
+static void free_all_frame_buffers(struct b3dfg_dev *fgdev)
+{
+	int i, j;
+	for (i = 0; i < b3dfg_nbuf; i++)
+		for (j = 0; j < B3DFG_FRAMES_PER_BUFFER; j++)
+			kfree(fgdev->buffers[i].frame[j]);
+	kfree(fgdev->buffers);
+}
+
+/* initialize device and any data structures. called before any interrupts
+ * are enabled. */
+static int b3dfg_init_dev(struct b3dfg_dev *fgdev)
+{
+	int i, j;
+	u32 frm_size = b3dfg_read32(fgdev, B3D_REG_FRM_SIZE);
+
+	/* Disable interrupts. In abnormal circumstances (e.g. after a crash)
+	 * the board may still be transmitting from the previous session. If we
+	 * ensure that interrupts are disabled before we later enable them, we
+	 * are sure to capture a triplet from the start, rather than starting
+	 * from frame 2 or 3. Disabling interrupts causes the FG to throw away
+	 * all buffered data and stop buffering more until interrupts are
+	 * enabled again.
+	 */
+	b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
+
+	fgdev->frame_size = frm_size * 4096;
+	fgdev->buffers = kzalloc(sizeof(struct b3dfg_buffer) * b3dfg_nbuf,
+				 GFP_KERNEL);
+	if (!fgdev->buffers)
+		goto err_no_buf;
+	for (i = 0; i < b3dfg_nbuf; i++) {
+		struct b3dfg_buffer *buf = &fgdev->buffers[i];
+		for (j = 0; j < B3DFG_FRAMES_PER_BUFFER; j++) {
+			buf->frame[j] = kmalloc(fgdev->frame_size, GFP_KERNEL);
+			if (!buf->frame[j])
+				goto err_no_mem;
+		}
+		INIT_LIST_HEAD(&buf->list);
+	}
+
+	INIT_LIST_HEAD(&fgdev->buffer_queue);
+	init_waitqueue_head(&fgdev->buffer_waitqueue);
+	spin_lock_init(&fgdev->buffer_lock);
+	spin_lock_init(&fgdev->cstate_lock);
+	spin_lock_init(&fgdev->triplets_dropped_lock);
+	return 0;
+
+err_no_mem:
+	free_all_frame_buffers(fgdev);
+err_no_buf:
+	return -ENOMEM;
+}
+
+/* find next free minor number, returns -1 if none are availabile */
+static int get_free_minor(void)
+{
+	int i;
+	for (i = 0; i < B3DFG_MAX_DEVS; i++) {
+		if (b3dfg_devices[i] == 0)
+			return i;
+	}
+	return -1;
+}
+
+static int __devinit b3dfg_probe(struct pci_dev *pdev,
+	const struct pci_device_id *id)
+{
+	struct b3dfg_dev *fgdev = kzalloc(sizeof(*fgdev), GFP_KERNEL);
+	int r = 0;
+	int minor = get_free_minor();
+	dev_t devno = MKDEV(MAJOR(b3dfg_devt), minor);
+	unsigned long res_len;
+	resource_size_t res_base;
+
+	if (fgdev == NULL)
+		return -ENOMEM;
+
+	if (minor < 0) {
+		dev_err(&pdev->dev, "too many devices found!\n");
+		r = -EIO;
+		goto err_free;
+	}
+
+	b3dfg_devices[minor] = 1;
+	dev_info(&pdev->dev, "probe device with IRQ %d\n", pdev->irq);
+
+	cdev_init(&fgdev->chardev, &b3dfg_fops);
+	fgdev->chardev.owner = THIS_MODULE;
+
+	r = cdev_add(&fgdev->chardev, devno, 1);
+	if (r) {
+		dev_err(&pdev->dev, "cannot add char device\n");
+		goto err_release_minor;
+	}
+
+	fgdev->dev = device_create(
+		b3dfg_class,
+		&pdev->dev,
+		devno,
+		dev_get_drvdata(&pdev->dev),
+		DRIVER_NAME "%d", minor);
+
+	if (IS_ERR(fgdev->dev)) {
+		dev_err(&pdev->dev, "cannot create device\n");
+		r = PTR_ERR(fgdev->dev);
+		goto err_del_cdev;
+	}
+
+	r = pci_enable_device(pdev);
+	if (r) {
+		dev_err(&pdev->dev, "cannot enable PCI device\n");
+		goto err_dev_unreg;
+	}
+
+	res_len = pci_resource_len(pdev, B3DFG_BAR_REGS);
+	if (res_len != B3DFG_REGS_LENGTH) {
+		dev_err(&pdev->dev, "invalid register resource size\n");
+		r = -EIO;
+		goto err_disable;
+	}
+
+	if (pci_resource_flags(pdev, B3DFG_BAR_REGS)
+				!= (IORESOURCE_MEM | IORESOURCE_SIZEALIGN)) {
+		dev_err(&pdev->dev, "invalid resource flags\n");
+		r = -EIO;
+		goto err_disable;
+	}
+	r = pci_request_regions(pdev, DRIVER_NAME);
+	if (r) {
+		dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+		goto err_disable;
+	}
+
+	pci_set_master(pdev);
+
+	r = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (r) {
+		dev_err(&pdev->dev, "no usable DMA configuration\n");
+		goto err_free_res;
+	}
+
+	res_base = pci_resource_start(pdev, B3DFG_BAR_REGS);
+	fgdev->regs = ioremap_nocache(res_base, res_len);
+	if (!fgdev->regs) {
+		dev_err(&pdev->dev, "regs ioremap failed\n");
+		r = -EIO;
+		goto err_free_res;
+	}
+
+	fgdev->pdev = pdev;
+	pci_set_drvdata(pdev, fgdev);
+	r = b3dfg_init_dev(fgdev);
+	if (r < 0) {
+		dev_err(&pdev->dev, "failed to initalize device\n");
+		goto err_unmap;
+	}
+
+	r = request_irq(pdev->irq, b3dfg_intr, IRQF_SHARED, DRIVER_NAME, fgdev);
+	if (r) {
+		dev_err(&pdev->dev, "couldn't request irq %d\n", pdev->irq);
+		goto err_free_bufs;
+	}
+
+	return 0;
+
+err_free_bufs:
+	free_all_frame_buffers(fgdev);
+err_unmap:
+	iounmap(fgdev->regs);
+err_free_res:
+	pci_release_regions(pdev);
+err_disable:
+	pci_disable_device(pdev);
+err_dev_unreg:
+	device_destroy(b3dfg_class, devno);
+err_del_cdev:
+	cdev_del(&fgdev->chardev);
+err_release_minor:
+	b3dfg_devices[minor] = 0;
+err_free:
+	kfree(fgdev);
+	return r;
+}
+
+static void __devexit b3dfg_remove(struct pci_dev *pdev)
+{
+	struct b3dfg_dev *fgdev = pci_get_drvdata(pdev);
+	unsigned int minor = MINOR(fgdev->chardev.dev);
+
+	dev_dbg(&pdev->dev, "remove\n");
+
+	free_irq(pdev->irq, fgdev);
+	iounmap(fgdev->regs);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	device_destroy(b3dfg_class, MKDEV(MAJOR(b3dfg_devt), minor));
+	cdev_del(&fgdev->chardev);
+	free_all_frame_buffers(fgdev);
+	kfree(fgdev);
+	b3dfg_devices[minor] = 0;
+}
+
+static struct pci_driver b3dfg_driver = {
+	.name = DRIVER_NAME,
+	.id_table = b3dfg_ids,
+	.probe = b3dfg_probe,
+	.remove = __devexit_p(b3dfg_remove),
+};
+
+static int __init b3dfg_module_init(void)
+{
+	int r;
+
+	if (b3dfg_nbuf < 2) {
+		printk(KERN_ERR DRIVER_NAME
+			   ": buffer_count is out of range (must be >= 2)");
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO DRIVER_NAME ": loaded\n");
+
+	b3dfg_class = class_create(THIS_MODULE, DRIVER_NAME);
+	if (IS_ERR(b3dfg_class))
+		return PTR_ERR(b3dfg_class);
+
+	r = alloc_chrdev_region(&b3dfg_devt, 0, B3DFG_MAX_DEVS, DRIVER_NAME);
+	if (r)
+		goto err1;
+
+	r = pci_register_driver(&b3dfg_driver);
+	if (r)
+		goto err2;
+
+	return r;
+
+err2:
+	unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
+err1:
+	class_destroy(b3dfg_class);
+	return r;
+}
+
+static void __exit b3dfg_module_exit(void)
+{
+	printk(KERN_INFO DRIVER_NAME ": unloaded\n");
+	pci_unregister_driver(&b3dfg_driver);
+	unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
+	class_destroy(b3dfg_class);
+}
+
+module_init(b3dfg_module_init);
+module_exit(b3dfg_module_exit);

+ 14 - 0
drivers/staging/comedi/Kconfig

@@ -6,6 +6,13 @@ config COMEDI
 	  Enable support a wide range of data acquisition devices
 	  Enable support a wide range of data acquisition devices
 	  for Linux.
 	  for Linux.
 
 
+config COMEDI_DEBUG
+	bool "Comedi debugging"
+	depends on COMEDI != n
+	help
+	  This is an option for use by developers; most people should
+	  say N here. This enables comedi core and driver debugging.
+
 config COMEDI_RT
 config COMEDI_RT
 	tristate "Comedi Real-time support"
 	tristate "Comedi Real-time support"
 	depends on COMEDI && RT
 	depends on COMEDI && RT
@@ -20,6 +27,13 @@ config COMEDI_PCI_DRIVERS
 	---help---
 	---help---
 	  Enable lots of comedi PCI drivers to be built
 	  Enable lots of comedi PCI drivers to be built
 
 
+config COMEDI_PCMCIA_DRIVERS
+	tristate "Comedi PCMCIA drivers"
+	depends on COMEDI && PCMCIAI
+	default N
+	---help---
+	  Enable lots of comedi PCMCIA drivers to be built
+
 config COMEDI_USB_DRIVERS
 config COMEDI_USB_DRIVERS
 	tristate "Comedi USB drivers"
 	tristate "Comedi USB drivers"
 	depends on COMEDI && USB
 	depends on COMEDI && USB

+ 34 - 49
drivers/staging/comedi/comedi.h

@@ -57,9 +57,6 @@ extern "C" {
 /* max length of device and driver names */
 /* max length of device and driver names */
 #define COMEDI_NAMELEN 20
 #define COMEDI_NAMELEN 20
 
 
-	typedef unsigned int lsampl_t;
-	typedef unsigned short sampl_t;
-
 /* packs and unpacks a channel/range number */
 /* packs and unpacks a channel/range number */
 
 
 #define CR_PACK(chan, rng, aref)		((((aref)&0x3)<<24) | (((rng)&0xff)<<16) | (chan))
 #define CR_PACK(chan, rng, aref)		((((aref)&0x3)<<24) | (((rng)&0xff)<<16) | (chan))
@@ -261,10 +258,11 @@ enum configuration_ids {
 	INSN_CONFIG_GET_CLOCK_SRC = 2004,	/* Get master clock source */
 	INSN_CONFIG_GET_CLOCK_SRC = 2004,	/* Get master clock source */
 	INSN_CONFIG_SET_OTHER_SRC = 2005,	/* Set other source */
 	INSN_CONFIG_SET_OTHER_SRC = 2005,	/* Set other source */
 /*	INSN_CONFIG_GET_OTHER_SRC = 2006,*/	/* Get other source */
 /*	INSN_CONFIG_GET_OTHER_SRC = 2006,*/	/* Get other source */
-	INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE,	/* Get size in bytes of
-						  subdevice's on-board fifos
-						  used during streaming
-						  input/output */
+	INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006,	/* Get size in bytes of
+							   subdevice's on-board
+							   fifos used during
+							   streaming
+							   input/output */
 	INSN_CONFIG_SET_COUNTER_MODE = 4097,
 	INSN_CONFIG_SET_COUNTER_MODE = 4097,
 	INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,	/* deprecated */
 	INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,	/* deprecated */
 	INSN_CONFIG_8254_READ_STATUS = 4098,
 	INSN_CONFIG_8254_READ_STATUS = 4098,
@@ -293,45 +291,32 @@ enum comedi_support_level {
 /* ioctls */
 /* ioctls */
 
 
 #define CIO 'd'
 #define CIO 'd'
-#define COMEDI_DEVCONFIG _IOW(CIO, 0, comedi_devconfig)
-#define COMEDI_DEVINFO _IOR(CIO, 1, comedi_devinfo)
-#define COMEDI_SUBDINFO _IOR(CIO, 2, comedi_subdinfo)
-#define COMEDI_CHANINFO _IOR(CIO, 3, comedi_chaninfo)
+#define COMEDI_DEVCONFIG _IOW(CIO, 0, struct comedi_devconfig)
+#define COMEDI_DEVINFO _IOR(CIO, 1, struct comedi_devinfo)
+#define COMEDI_SUBDINFO _IOR(CIO, 2, struct comedi_subdinfo)
+#define COMEDI_CHANINFO _IOR(CIO, 3, struct comedi_chaninfo)
 #define COMEDI_TRIG _IOWR(CIO, 4, comedi_trig)
 #define COMEDI_TRIG _IOWR(CIO, 4, comedi_trig)
 #define COMEDI_LOCK _IO(CIO, 5)
 #define COMEDI_LOCK _IO(CIO, 5)
 #define COMEDI_UNLOCK _IO(CIO, 6)
 #define COMEDI_UNLOCK _IO(CIO, 6)
 #define COMEDI_CANCEL _IO(CIO, 7)
 #define COMEDI_CANCEL _IO(CIO, 7)
-#define COMEDI_RANGEINFO _IOR(CIO, 8, comedi_rangeinfo)
-#define COMEDI_CMD _IOR(CIO, 9, comedi_cmd)
-#define COMEDI_CMDTEST _IOR(CIO, 10, comedi_cmd)
-#define COMEDI_INSNLIST _IOR(CIO, 11, comedi_insnlist)
-#define COMEDI_INSN _IOR(CIO, 12, comedi_insn)
-#define COMEDI_BUFCONFIG _IOR(CIO, 13, comedi_bufconfig)
-#define COMEDI_BUFINFO _IOWR(CIO, 14, comedi_bufinfo)
+#define COMEDI_RANGEINFO _IOR(CIO, 8, struct comedi_rangeinfo)
+#define COMEDI_CMD _IOR(CIO, 9, struct comedi_cmd)
+#define COMEDI_CMDTEST _IOR(CIO, 10, struct comedi_cmd)
+#define COMEDI_INSNLIST _IOR(CIO, 11, struct comedi_insnlist)
+#define COMEDI_INSN _IOR(CIO, 12, struct comedi_insn)
+#define COMEDI_BUFCONFIG _IOR(CIO, 13, struct comedi_bufconfig)
+#define COMEDI_BUFINFO _IOWR(CIO, 14, struct comedi_bufinfo)
 #define COMEDI_POLL _IO(CIO, 15)
 #define COMEDI_POLL _IO(CIO, 15)
 
 
 /* structures */
 /* structures */
 
 
-typedef struct comedi_trig_struct comedi_trig;
-typedef struct comedi_cmd_struct comedi_cmd;
-typedef struct comedi_insn_struct comedi_insn;
-typedef struct comedi_insnlist_struct comedi_insnlist;
-typedef struct comedi_chaninfo_struct comedi_chaninfo;
-typedef struct comedi_subdinfo_struct comedi_subdinfo;
-typedef struct comedi_devinfo_struct comedi_devinfo;
-typedef struct comedi_devconfig_struct comedi_devconfig;
-typedef struct comedi_rangeinfo_struct comedi_rangeinfo;
-typedef struct comedi_krange_struct comedi_krange;
-typedef struct comedi_bufconfig_struct comedi_bufconfig;
-typedef struct comedi_bufinfo_struct comedi_bufinfo;
-
-struct comedi_trig_struct {
+struct comedi_trig {
 	unsigned int subdev;	/* subdevice */
 	unsigned int subdev;	/* subdevice */
 	unsigned int mode;	/* mode */
 	unsigned int mode;	/* mode */
 	unsigned int flags;
 	unsigned int flags;
 	unsigned int n_chan;	/* number of channels */
 	unsigned int n_chan;	/* number of channels */
 	unsigned int *chanlist;	/* channel/range list */
 	unsigned int *chanlist;	/* channel/range list */
-	sampl_t *data;	/* data list, size depends on subd flags */
+	short *data;	/* data list, size depends on subd flags */
 	unsigned int n;	/* number of scans */
 	unsigned int n;	/* number of scans */
 	unsigned int trigsrc;
 	unsigned int trigsrc;
 	unsigned int trigvar;
 	unsigned int trigvar;
@@ -340,21 +325,21 @@ struct comedi_trig_struct {
 	unsigned int unused[3];
 	unsigned int unused[3];
 };
 };
 
 
-struct comedi_insn_struct {
+struct comedi_insn {
 	unsigned int insn;
 	unsigned int insn;
 	unsigned int n;
 	unsigned int n;
-	lsampl_t *data;
+	unsigned int *data;
 	unsigned int subdev;
 	unsigned int subdev;
 	unsigned int chanspec;
 	unsigned int chanspec;
 	unsigned int unused[3];
 	unsigned int unused[3];
 };
 };
 
 
-struct comedi_insnlist_struct {
+struct comedi_insnlist {
 	unsigned int n_insns;
 	unsigned int n_insns;
-	comedi_insn *insns;
+	struct comedi_insn *insns;
 };
 };
 
 
-struct comedi_cmd_struct {
+struct comedi_cmd {
 	unsigned int subdev;
 	unsigned int subdev;
 	unsigned int flags;
 	unsigned int flags;
 
 
@@ -376,37 +361,37 @@ struct comedi_cmd_struct {
 	unsigned int *chanlist;	/* channel/range list */
 	unsigned int *chanlist;	/* channel/range list */
 	unsigned int chanlist_len;
 	unsigned int chanlist_len;
 
 
-	sampl_t *data;	/* data list, size depends on subd flags */
+	short *data;	/* data list, size depends on subd flags */
 	unsigned int data_len;
 	unsigned int data_len;
 };
 };
 
 
-struct comedi_chaninfo_struct {
+struct comedi_chaninfo {
 	unsigned int subdev;
 	unsigned int subdev;
-	lsampl_t *maxdata_list;
+	unsigned int *maxdata_list;
 	unsigned int *flaglist;
 	unsigned int *flaglist;
 	unsigned int *rangelist;
 	unsigned int *rangelist;
 	unsigned int unused[4];
 	unsigned int unused[4];
 };
 };
 
 
-struct comedi_rangeinfo_struct {
+struct comedi_rangeinfo {
 	unsigned int range_type;
 	unsigned int range_type;
 	void *range_ptr;
 	void *range_ptr;
 };
 };
 
 
-struct comedi_krange_struct {
+struct comedi_krange {
 	int min;	/* fixed point, multiply by 1e-6 */
 	int min;	/* fixed point, multiply by 1e-6 */
 	int max;	/* fixed point, multiply by 1e-6 */
 	int max;	/* fixed point, multiply by 1e-6 */
 	unsigned int flags;
 	unsigned int flags;
 };
 };
 
 
 
 
-struct comedi_subdinfo_struct {
+struct comedi_subdinfo {
 	unsigned int type;
 	unsigned int type;
 	unsigned int n_chan;
 	unsigned int n_chan;
 	unsigned int subd_flags;
 	unsigned int subd_flags;
 	unsigned int timer_type;
 	unsigned int timer_type;
 	unsigned int len_chanlist;
 	unsigned int len_chanlist;
-	lsampl_t maxdata;
+	unsigned int maxdata;
 	unsigned int flags;	/* channel flags */
 	unsigned int flags;	/* channel flags */
 	unsigned int range_type;	/* lookup in kernel */
 	unsigned int range_type;	/* lookup in kernel */
 	unsigned int settling_time_0;
 	unsigned int settling_time_0;
@@ -414,7 +399,7 @@ struct comedi_subdinfo_struct {
 	unsigned int unused[8];
 	unsigned int unused[8];
 };
 };
 
 
-struct comedi_devinfo_struct {
+struct comedi_devinfo {
 	unsigned int version_code;
 	unsigned int version_code;
 	unsigned int n_subdevs;
 	unsigned int n_subdevs;
 	char driver_name[COMEDI_NAMELEN];
 	char driver_name[COMEDI_NAMELEN];
@@ -424,12 +409,12 @@ struct comedi_devinfo_struct {
 	int unused[30];
 	int unused[30];
 };
 };
 
 
-struct comedi_devconfig_struct {
+struct comedi_devconfig {
 	char board_name[COMEDI_NAMELEN];
 	char board_name[COMEDI_NAMELEN];
 	int options[COMEDI_NDEVCONFOPTS];
 	int options[COMEDI_NDEVCONFOPTS];
 };
 };
 
 
-struct comedi_bufconfig_struct {
+struct comedi_bufconfig {
 	unsigned int subdevice;
 	unsigned int subdevice;
 	unsigned int flags;
 	unsigned int flags;
 
 
@@ -439,7 +424,7 @@ struct comedi_bufconfig_struct {
 	unsigned int unused[4];
 	unsigned int unused[4];
 };
 };
 
 
-struct comedi_bufinfo_struct {
+struct comedi_bufinfo {
 	unsigned int subdevice;
 	unsigned int subdevice;
 	unsigned int bytes_read;
 	unsigned int bytes_read;
 
 

+ 59 - 69
drivers/staging/comedi/comedi_compat32.c

@@ -37,31 +37,31 @@
 #include <linux/ioctl32.h>	/* for (un)register_ioctl32_conversion */
 #include <linux/ioctl32.h>	/* for (un)register_ioctl32_conversion */
 #endif
 #endif
 
 
-#define COMEDI32_CHANINFO _IOR(CIO,3,comedi32_chaninfo)
-#define COMEDI32_RANGEINFO _IOR(CIO,8,comedi32_rangeinfo)
+#define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct)
+#define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct)
 /* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
 /* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
  * It's too late to change it now, but it only affects the command number. */
  * It's too late to change it now, but it only affects the command number. */
-#define COMEDI32_CMD _IOR(CIO,9,comedi32_cmd)
+#define COMEDI32_CMD _IOR(CIO, 9, struct comedi32_cmd_struct)
 /* N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
 /* N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
  * It's too late to change it now, but it only affects the command number. */
  * It's too late to change it now, but it only affects the command number. */
-#define COMEDI32_CMDTEST _IOR(CIO,10,comedi32_cmd)
-#define COMEDI32_INSNLIST _IOR(CIO,11,comedi32_insnlist)
-#define COMEDI32_INSN _IOR(CIO,12,comedi32_insn)
+#define COMEDI32_CMDTEST _IOR(CIO, 10, struct comedi32_cmd_struct)
+#define COMEDI32_INSNLIST _IOR(CIO, 11, struct comedi32_insnlist_struct)
+#define COMEDI32_INSN _IOR(CIO, 12, struct comedi32_insn_struct)
 
 
-typedef struct comedi32_chaninfo_struct {
+struct comedi32_chaninfo_struct {
 	unsigned int subdev;
 	unsigned int subdev;
-	compat_uptr_t maxdata_list;	/* 32-bit 'lsampl_t *' */
+	compat_uptr_t maxdata_list;	/* 32-bit 'unsigned int *' */
 	compat_uptr_t flaglist;		/* 32-bit 'unsigned int *' */
 	compat_uptr_t flaglist;		/* 32-bit 'unsigned int *' */
 	compat_uptr_t rangelist;	/* 32-bit 'unsigned int *' */
 	compat_uptr_t rangelist;	/* 32-bit 'unsigned int *' */
 	unsigned int unused[4];
 	unsigned int unused[4];
-} comedi32_chaninfo;
+};
 
 
-typedef struct comedi32_rangeinfo_struct {
+struct comedi32_rangeinfo_struct {
 	unsigned int range_type;
 	unsigned int range_type;
 	compat_uptr_t range_ptr;	/* 32-bit 'void *' */
 	compat_uptr_t range_ptr;	/* 32-bit 'void *' */
-} comedi32_rangeinfo;
+};
 
 
-typedef struct comedi32_cmd_struct {
+struct comedi32_cmd_struct {
 	unsigned int subdev;
 	unsigned int subdev;
 	unsigned int flags;
 	unsigned int flags;
 	unsigned int start_src;
 	unsigned int start_src;
@@ -76,37 +76,36 @@ typedef struct comedi32_cmd_struct {
 	unsigned int stop_arg;
 	unsigned int stop_arg;
 	compat_uptr_t chanlist;		/* 32-bit 'unsigned int *' */
 	compat_uptr_t chanlist;		/* 32-bit 'unsigned int *' */
 	unsigned int chanlist_len;
 	unsigned int chanlist_len;
-	compat_uptr_t data;		/* 32-bit 'sampl_t *' */
+	compat_uptr_t data;		/* 32-bit 'short *' */
 	unsigned int data_len;
 	unsigned int data_len;
-} comedi32_cmd;
+};
 
 
-typedef struct comedi32_insn_struct {
+struct comedi32_insn_struct {
 	unsigned int insn;
 	unsigned int insn;
 	unsigned int n;
 	unsigned int n;
-	compat_uptr_t data;		/* 32-bit 'lsampl_t *' */
+	compat_uptr_t data;		/* 32-bit 'unsigned int *' */
 	unsigned int subdev;
 	unsigned int subdev;
 	unsigned int chanspec;
 	unsigned int chanspec;
 	unsigned int unused[3];
 	unsigned int unused[3];
-} comedi32_insn;
+};
 
 
-typedef struct comedi32_insnlist_struct {
+struct comedi32_insnlist_struct {
 	unsigned int n_insns;
 	unsigned int n_insns;
-	compat_uptr_t insns;		/* 32-bit 'comedi_insn *' */
-} comedi32_insnlist;
+	compat_uptr_t insns;		/* 32-bit 'struct comedi_insn *' */
+};
 
 
 /* Handle translated ioctl. */
 /* Handle translated ioctl. */
 static int translated_ioctl(struct file *file, unsigned int cmd,
 static int translated_ioctl(struct file *file, unsigned int cmd,
 		unsigned long arg)
 		unsigned long arg)
 {
 {
-	if (!file->f_op) {
+	if (!file->f_op)
 		return -ENOTTY;
 		return -ENOTTY;
-	}
+
 #ifdef HAVE_UNLOCKED_IOCTL
 #ifdef HAVE_UNLOCKED_IOCTL
 	if (file->f_op->unlocked_ioctl) {
 	if (file->f_op->unlocked_ioctl) {
 		int rc = (int)(*file->f_op->unlocked_ioctl)(file, cmd, arg);
 		int rc = (int)(*file->f_op->unlocked_ioctl)(file, cmd, arg);
-		if (rc == -ENOIOCTLCMD) {
+		if (rc == -ENOIOCTLCMD)
 			rc = -ENOTTY;
 			rc = -ENOTTY;
-		}
 		return rc;
 		return rc;
 	}
 	}
 #endif
 #endif
@@ -124,8 +123,8 @@ static int translated_ioctl(struct file *file, unsigned int cmd,
 /* Handle 32-bit COMEDI_CHANINFO ioctl. */
 /* Handle 32-bit COMEDI_CHANINFO ioctl. */
 static int compat_chaninfo(struct file *file, unsigned long arg)
 static int compat_chaninfo(struct file *file, unsigned long arg)
 {
 {
-	comedi_chaninfo __user *chaninfo;
-	comedi32_chaninfo __user *chaninfo32;
+	struct comedi_chaninfo __user *chaninfo;
+	struct comedi32_chaninfo_struct __user *chaninfo32;
 	int err;
 	int err;
 	union {
 	union {
 		unsigned int uint;
 		unsigned int uint;
@@ -150,9 +149,8 @@ static int compat_chaninfo(struct file *file, unsigned long arg)
 	err |= __put_user(compat_ptr(temp.uptr), &chaninfo->flaglist);
 	err |= __put_user(compat_ptr(temp.uptr), &chaninfo->flaglist);
 	err |= __get_user(temp.uptr, &chaninfo32->rangelist);
 	err |= __get_user(temp.uptr, &chaninfo32->rangelist);
 	err |= __put_user(compat_ptr(temp.uptr), &chaninfo->rangelist);
 	err |= __put_user(compat_ptr(temp.uptr), &chaninfo->rangelist);
-	if (err) {
+	if (err)
 		return -EFAULT;
 		return -EFAULT;
-	}
 
 
 	return translated_ioctl(file, COMEDI_CHANINFO, (unsigned long)chaninfo);
 	return translated_ioctl(file, COMEDI_CHANINFO, (unsigned long)chaninfo);
 }
 }
@@ -160,8 +158,8 @@ static int compat_chaninfo(struct file *file, unsigned long arg)
 /* Handle 32-bit COMEDI_RANGEINFO ioctl. */
 /* Handle 32-bit COMEDI_RANGEINFO ioctl. */
 static int compat_rangeinfo(struct file *file, unsigned long arg)
 static int compat_rangeinfo(struct file *file, unsigned long arg)
 {
 {
-	comedi_rangeinfo __user *rangeinfo;
-	comedi32_rangeinfo __user *rangeinfo32;
+	struct comedi_rangeinfo __user *rangeinfo;
+	struct comedi32_rangeinfo_struct __user *rangeinfo32;
 	int err;
 	int err;
 	union {
 	union {
 		unsigned int uint;
 		unsigned int uint;
@@ -182,17 +180,16 @@ static int compat_rangeinfo(struct file *file, unsigned long arg)
 	err |= __put_user(temp.uint, &rangeinfo->range_type);
 	err |= __put_user(temp.uint, &rangeinfo->range_type);
 	err |= __get_user(temp.uptr, &rangeinfo32->range_ptr);
 	err |= __get_user(temp.uptr, &rangeinfo32->range_ptr);
 	err |= __put_user(compat_ptr(temp.uptr), &rangeinfo->range_ptr);
 	err |= __put_user(compat_ptr(temp.uptr), &rangeinfo->range_ptr);
-	if (err) {
+	if (err)
 		return -EFAULT;
 		return -EFAULT;
-	}
 
 
 	return translated_ioctl(file, COMEDI_RANGEINFO,
 	return translated_ioctl(file, COMEDI_RANGEINFO,
 			(unsigned long)rangeinfo);
 			(unsigned long)rangeinfo);
 }
 }
 
 
 /* Copy 32-bit cmd structure to native cmd structure. */
 /* Copy 32-bit cmd structure to native cmd structure. */
-static int get_compat_cmd(comedi_cmd __user *cmd,
-		comedi32_cmd __user *cmd32)
+static int get_compat_cmd(struct comedi_cmd __user *cmd,
+		struct comedi32_cmd_struct __user *cmd32)
 {
 {
 	int err;
 	int err;
 	union {
 	union {
@@ -242,7 +239,7 @@ static int get_compat_cmd(comedi_cmd __user *cmd,
 }
 }
 
 
 /* Copy native cmd structure to 32-bit cmd structure. */
 /* Copy native cmd structure to 32-bit cmd structure. */
-static int put_compat_cmd(comedi32_cmd __user *cmd32, comedi_cmd __user *cmd)
+static int put_compat_cmd(struct comedi32_cmd_struct __user *cmd32, struct comedi_cmd __user *cmd)
 {
 {
 	int err;
 	int err;
 	unsigned int temp;
 	unsigned int temp;
@@ -292,17 +289,16 @@ static int put_compat_cmd(comedi32_cmd __user *cmd32, comedi_cmd __user *cmd)
 /* Handle 32-bit COMEDI_CMD ioctl. */
 /* Handle 32-bit COMEDI_CMD ioctl. */
 static int compat_cmd(struct file *file, unsigned long arg)
 static int compat_cmd(struct file *file, unsigned long arg)
 {
 {
-	comedi_cmd __user *cmd;
-	comedi32_cmd __user *cmd32;
+	struct comedi_cmd __user *cmd;
+	struct comedi32_cmd_struct __user *cmd32;
 	int rc;
 	int rc;
 
 
 	cmd32 = compat_ptr(arg);
 	cmd32 = compat_ptr(arg);
 	cmd = compat_alloc_user_space(sizeof(*cmd));
 	cmd = compat_alloc_user_space(sizeof(*cmd));
 
 
 	rc = get_compat_cmd(cmd, cmd32);
 	rc = get_compat_cmd(cmd, cmd32);
-	if (rc) {
+	if (rc)
 		return rc;
 		return rc;
-	}
 
 
 	return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
 	return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
 }
 }
@@ -310,33 +306,31 @@ static int compat_cmd(struct file *file, unsigned long arg)
 /* Handle 32-bit COMEDI_CMDTEST ioctl. */
 /* Handle 32-bit COMEDI_CMDTEST ioctl. */
 static int compat_cmdtest(struct file *file, unsigned long arg)
 static int compat_cmdtest(struct file *file, unsigned long arg)
 {
 {
-	comedi_cmd __user *cmd;
-	comedi32_cmd __user *cmd32;
+	struct comedi_cmd __user *cmd;
+	struct comedi32_cmd_struct __user *cmd32;
 	int rc, err;
 	int rc, err;
 
 
 	cmd32 = compat_ptr(arg);
 	cmd32 = compat_ptr(arg);
 	cmd = compat_alloc_user_space(sizeof(*cmd));
 	cmd = compat_alloc_user_space(sizeof(*cmd));
 
 
 	rc = get_compat_cmd(cmd, cmd32);
 	rc = get_compat_cmd(cmd, cmd32);
-	if (rc) {
+	if (rc)
 		return rc;
 		return rc;
-	}
 
 
 	rc = translated_ioctl(file, COMEDI_CMDTEST, (unsigned long)cmd);
 	rc = translated_ioctl(file, COMEDI_CMDTEST, (unsigned long)cmd);
-	if (rc < 0) {
+	if (rc < 0)
 		return rc;
 		return rc;
-	}
 
 
 	err = put_compat_cmd(cmd32, cmd);
 	err = put_compat_cmd(cmd32, cmd);
-	if (err) {
+	if (err)
 		rc = err;
 		rc = err;
-	}
+
 	return rc;
 	return rc;
 }
 }
 
 
 /* Copy 32-bit insn structure to native insn structure. */
 /* Copy 32-bit insn structure to native insn structure. */
-static int get_compat_insn(comedi_insn __user *insn,
-		comedi32_insn __user *insn32)
+static int get_compat_insn(struct comedi_insn __user *insn,
+		struct comedi32_insn_struct __user *insn32)
 {
 {
 	int err;
 	int err;
 	union {
 	union {
@@ -347,9 +341,9 @@ static int get_compat_insn(comedi_insn __user *insn,
 	/* Copy insn structure.  Ignore the unused members. */
 	/* Copy insn structure.  Ignore the unused members. */
 	err = 0;
 	err = 0;
 	if (!access_ok(VERIFY_READ, insn32, sizeof(*insn32))
 	if (!access_ok(VERIFY_READ, insn32, sizeof(*insn32))
-			|| !access_ok(VERIFY_WRITE, insn, sizeof(*insn))) {
+			|| !access_ok(VERIFY_WRITE, insn, sizeof(*insn)))
 		return -EFAULT;
 		return -EFAULT;
-	}
+
 	err |= __get_user(temp.uint, &insn32->insn);
 	err |= __get_user(temp.uint, &insn32->insn);
 	err |= __put_user(temp.uint, &insn->insn);
 	err |= __put_user(temp.uint, &insn->insn);
 	err |= __get_user(temp.uint, &insn32->n);
 	err |= __get_user(temp.uint, &insn32->n);
@@ -367,11 +361,11 @@ static int get_compat_insn(comedi_insn __user *insn,
 static int compat_insnlist(struct file *file, unsigned long arg)
 static int compat_insnlist(struct file *file, unsigned long arg)
 {
 {
 	struct combined_insnlist {
 	struct combined_insnlist {
-		comedi_insnlist insnlist;
-		comedi_insn insn[1];
+		struct comedi_insnlist insnlist;
+		struct comedi_insn insn[1];
 	} __user *s;
 	} __user *s;
-	comedi32_insnlist __user *insnlist32;
-	comedi32_insn __user *insn32;
+	struct comedi32_insnlist_struct __user *insnlist32;
+	struct comedi32_insn_struct __user *insn32;
 	compat_uptr_t uptr;
 	compat_uptr_t uptr;
 	unsigned int n_insns, n;
 	unsigned int n_insns, n;
 	int err, rc;
 	int err, rc;
@@ -386,9 +380,8 @@ static int compat_insnlist(struct file *file, unsigned long arg)
 	err |= __get_user(n_insns, &insnlist32->n_insns);
 	err |= __get_user(n_insns, &insnlist32->n_insns);
 	err |= __get_user(uptr, &insnlist32->insns);
 	err |= __get_user(uptr, &insnlist32->insns);
 	insn32 = compat_ptr(uptr);
 	insn32 = compat_ptr(uptr);
-	if (err) {
+	if (err)
 		return -EFAULT;
 		return -EFAULT;
-	}
 
 
 	/* Allocate user memory to copy insnlist and insns into. */
 	/* Allocate user memory to copy insnlist and insns into. */
 	s = compat_alloc_user_space(offsetof(struct combined_insnlist,
 	s = compat_alloc_user_space(offsetof(struct combined_insnlist,
@@ -400,16 +393,14 @@ static int compat_insnlist(struct file *file, unsigned long arg)
 	}
 	}
 	err |= __put_user(n_insns, &s->insnlist.n_insns);
 	err |= __put_user(n_insns, &s->insnlist.n_insns);
 	err |= __put_user(&s->insn[0], &s->insnlist.insns);
 	err |= __put_user(&s->insn[0], &s->insnlist.insns);
-	if (err) {
+	if (err)
 		return -EFAULT;
 		return -EFAULT;
-	}
 
 
 	/* Copy insn structures. */
 	/* Copy insn structures. */
 	for (n = 0; n < n_insns; n++) {
 	for (n = 0; n < n_insns; n++) {
 		rc = get_compat_insn(&s->insn[n], &insn32[n]);
 		rc = get_compat_insn(&s->insn[n], &insn32[n]);
-		if (rc) {
+		if (rc)
 			return rc;
 			return rc;
-		}
 	}
 	}
 
 
 	return translated_ioctl(file, COMEDI_INSNLIST,
 	return translated_ioctl(file, COMEDI_INSNLIST,
@@ -419,17 +410,16 @@ static int compat_insnlist(struct file *file, unsigned long arg)
 /* Handle 32-bit COMEDI_INSN ioctl. */
 /* Handle 32-bit COMEDI_INSN ioctl. */
 static int compat_insn(struct file *file, unsigned long arg)
 static int compat_insn(struct file *file, unsigned long arg)
 {
 {
-	comedi_insn __user *insn;
-	comedi32_insn __user *insn32;
+	struct comedi_insn __user *insn;
+	struct comedi32_insn_struct __user *insn32;
 	int rc;
 	int rc;
 
 
 	insn32 = compat_ptr(arg);
 	insn32 = compat_ptr(arg);
 	insn = compat_alloc_user_space(sizeof(*insn));
 	insn = compat_alloc_user_space(sizeof(*insn));
 
 
 	rc = get_compat_insn(insn, insn32);
 	rc = get_compat_insn(insn, insn32);
-	if (rc) {
+	if (rc)
 		return rc;
 		return rc;
-	}
 
 
 	return translated_ioctl(file, COMEDI_INSN, (unsigned long)insn);
 	return translated_ioctl(file, COMEDI_INSN, (unsigned long)insn);
 }
 }
@@ -512,14 +502,14 @@ static int mapped_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
 	int rc;
 	int rc;
 
 
 	/* Make sure we are dealing with a Comedi device. */
 	/* Make sure we are dealing with a Comedi device. */
-	if (imajor(file->f_dentry->d_inode) != COMEDI_MAJOR) {
+	if (imajor(file->f_dentry->d_inode) != COMEDI_MAJOR)
 		return -ENOTTY;
 		return -ENOTTY;
-	}
+
 	rc = raw_ioctl(file, cmd, arg);
 	rc = raw_ioctl(file, cmd, arg);
 	/* Do not return -ENOIOCTLCMD. */
 	/* Do not return -ENOIOCTLCMD. */
-	if (rc == -ENOIOCTLCMD) {
+	if (rc == -ENOIOCTLCMD)
 		rc = -ENOTTY;
 		rc = -ENOTTY;
-	}
+
 	return rc;
 	return rc;
 }
 }
 
 

+ 159 - 134
drivers/staging/comedi/comedi_fops.c

@@ -59,33 +59,39 @@ int comedi_debug;
 module_param(comedi_debug, int, 0644);
 module_param(comedi_debug, int, 0644);
 #endif
 #endif
 
 
+int comedi_autoconfig = 1;
+module_param(comedi_autoconfig, bool, 0444);
+
+int comedi_num_legacy_minors = 0;
+module_param(comedi_num_legacy_minors, int, 0444);
+
 static DEFINE_SPINLOCK(comedi_file_info_table_lock);
 static DEFINE_SPINLOCK(comedi_file_info_table_lock);
 static struct comedi_device_file_info
 static struct comedi_device_file_info
     *comedi_file_info_table[COMEDI_NUM_MINORS];
     *comedi_file_info_table[COMEDI_NUM_MINORS];
 
 
-static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg);
-static int do_bufconfig_ioctl(comedi_device *dev, void *arg);
-static int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
+static int do_devconfig_ioctl(struct comedi_device *dev, struct comedi_devconfig *arg);
+static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg);
+static int do_devinfo_ioctl(struct comedi_device *dev, struct comedi_devinfo *arg,
 			    struct file *file);
 			    struct file *file);
-static int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
+static int do_subdinfo_ioctl(struct comedi_device *dev, struct comedi_subdinfo *arg,
 			     void *file);
 			     void *file);
-static int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg);
-static int do_bufinfo_ioctl(comedi_device *dev, void *arg);
-static int do_cmd_ioctl(comedi_device *dev, void *arg, void *file);
-static int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file);
-static int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file);
-static int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file);
-static int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file);
-static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file);
-static int do_insn_ioctl(comedi_device *dev, void *arg, void *file);
-static int do_poll_ioctl(comedi_device *dev, unsigned int subd, void *file);
-
-extern void do_become_nonbusy(comedi_device *dev, comedi_subdevice *s);
-static int do_cancel(comedi_device *dev, comedi_subdevice *s);
+static int do_chaninfo_ioctl(struct comedi_device *dev, struct comedi_chaninfo *arg);
+static int do_bufinfo_ioctl(struct comedi_device *dev, void *arg);
+static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file);
+static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
+static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
+static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file);
+static int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file);
+static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file);
+static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file);
+static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, void *file);
+
+extern void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s);
+static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
 
 
 static int comedi_fasync(int fd, struct file *file, int on);
 static int comedi_fasync(int fd, struct file *file, int on);
 
 
-static int is_device_busy(comedi_device *dev);
+static int is_device_busy(struct comedi_device *dev);
 
 
 #ifdef HAVE_UNLOCKED_IOCTL
 #ifdef HAVE_UNLOCKED_IOCTL
 static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
 static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
@@ -98,9 +104,13 @@ static int comedi_ioctl(struct inode *inode, struct file *file,
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
+	struct comedi_device *dev;
 	int rc;
 	int rc;
 
 
+	if (dev_file_info == NULL || dev_file_info->device == NULL)
+		return -ENODEV;
+	dev = dev_file_info->device;
+
 	mutex_lock(&dev->mutex);
 	mutex_lock(&dev->mutex);
 
 
 	/* Device config is special, because it must work on
 	/* Device config is special, because it must work on
@@ -182,9 +192,9 @@ done:
 	writes:
 	writes:
 		none
 		none
 */
 */
-static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg)
+static int do_devconfig_ioctl(struct comedi_device *dev, struct comedi_devconfig *arg)
 {
 {
-	comedi_devconfig it;
+	struct comedi_devconfig it;
 	int ret;
 	int ret;
 	unsigned char *aux_data = NULL;
 	unsigned char *aux_data = NULL;
 	int aux_len;
 	int aux_len;
@@ -203,7 +213,7 @@ static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if (copy_from_user(&it, arg, sizeof(comedi_devconfig)))
+	if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	it.board_name[COMEDI_NAMELEN - 1] = 0;
 	it.board_name[COMEDI_NAMELEN - 1] = 0;
@@ -262,14 +272,14 @@ static int do_devconfig_ioctl(comedi_device *dev, comedi_devconfig *arg)
 		modified bufconfig at arg
 		modified bufconfig at arg
 
 
 */
 */
-static int do_bufconfig_ioctl(comedi_device *dev, void *arg)
+static int do_bufconfig_ioctl(struct comedi_device *dev, void *arg)
 {
 {
-	comedi_bufconfig bc;
-	comedi_async *async;
-	comedi_subdevice *s;
+	struct comedi_bufconfig bc;
+	struct comedi_async *async;
+	struct comedi_subdevice *s;
 	int ret = 0;
 	int ret = 0;
 
 
-	if (copy_from_user(&bc, arg, sizeof(comedi_bufconfig)))
+	if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
 	if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0)
@@ -330,7 +340,7 @@ static int do_bufconfig_ioctl(comedi_device *dev, void *arg)
 	bc.maximum_size = async->max_bufsize;
 	bc.maximum_size = async->max_bufsize;
 
 
 copyback:
 copyback:
-	if (copy_to_user(arg, &bc, sizeof(comedi_bufconfig)))
+	if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	return 0;
 	return 0;
@@ -350,16 +360,16 @@ copyback:
 		devinfo structure
 		devinfo structure
 
 
 */
 */
-static int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
+static int do_devinfo_ioctl(struct comedi_device *dev, struct comedi_devinfo *arg,
 			    struct file *file)
 			    struct file *file)
 {
 {
-	comedi_devinfo devinfo;
+	struct comedi_devinfo devinfo;
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_subdevice *read_subdev =
+	struct comedi_subdevice *read_subdev =
 	    comedi_get_read_subdevice(dev_file_info);
 	    comedi_get_read_subdevice(dev_file_info);
-	comedi_subdevice *write_subdev =
+	struct comedi_subdevice *write_subdev =
 	    comedi_get_write_subdevice(dev_file_info);
 	    comedi_get_write_subdevice(dev_file_info);
 
 
 	memset(&devinfo, 0, sizeof(devinfo));
 	memset(&devinfo, 0, sizeof(devinfo));
@@ -380,7 +390,7 @@ static int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
 	else
 	else
 		devinfo.write_subdevice = -1;
 		devinfo.write_subdevice = -1;
 
 
-	if (copy_to_user(arg, &devinfo, sizeof(comedi_devinfo)))
+	if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	return 0;
 	return 0;
@@ -400,14 +410,14 @@ static int do_devinfo_ioctl(comedi_device *dev, comedi_devinfo *arg,
 		array of subdevice info structures at arg
 		array of subdevice info structures at arg
 
 
 */
 */
-static int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
+static int do_subdinfo_ioctl(struct comedi_device *dev, struct comedi_subdinfo *arg,
 			     void *file)
 			     void *file)
 {
 {
 	int ret, i;
 	int ret, i;
-	comedi_subdinfo *tmp, *us;
-	comedi_subdevice *s;
+	struct comedi_subdinfo *tmp, *us;
+	struct comedi_subdevice *s;
 
 
-	tmp = kcalloc(dev->n_subdevices, sizeof(comedi_subdinfo), GFP_KERNEL);
+	tmp = kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo), GFP_KERNEL);
 	if (!tmp)
 	if (!tmp)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
@@ -459,7 +469,7 @@ static int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
 	}
 	}
 
 
 	ret = copy_to_user(arg, tmp,
 	ret = copy_to_user(arg, tmp,
-			   dev->n_subdevices * sizeof(comedi_subdinfo));
+			   dev->n_subdevices * sizeof(struct comedi_subdinfo));
 
 
 	kfree(tmp);
 	kfree(tmp);
 
 
@@ -480,12 +490,12 @@ static int do_subdinfo_ioctl(comedi_device *dev, comedi_subdinfo *arg,
 		arrays at elements of chaninfo structure
 		arrays at elements of chaninfo structure
 
 
 */
 */
-static int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg)
+static int do_chaninfo_ioctl(struct comedi_device *dev, struct comedi_chaninfo *arg)
 {
 {
-	comedi_subdevice *s;
-	comedi_chaninfo it;
+	struct comedi_subdevice *s;
+	struct comedi_chaninfo it;
 
 
-	if (copy_from_user(&it, arg, sizeof(comedi_chaninfo)))
+	if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	if (it.subdev >= dev->n_subdevices)
 	if (it.subdev >= dev->n_subdevices)
@@ -496,7 +506,7 @@ static int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg)
 		if (s->maxdata || !s->maxdata_list)
 		if (s->maxdata || !s->maxdata_list)
 			return -EINVAL;
 			return -EINVAL;
 		if (copy_to_user(it.maxdata_list, s->maxdata_list,
 		if (copy_to_user(it.maxdata_list, s->maxdata_list,
-				 s->n_chan * sizeof(lsampl_t)))
+				 s->n_chan * sizeof(unsigned int)))
 			return -EFAULT;
 			return -EFAULT;
 	}
 	}
 
 
@@ -544,13 +554,13 @@ static int do_chaninfo_ioctl(comedi_device *dev, comedi_chaninfo *arg)
     modified bufinfo at arg
     modified bufinfo at arg
 
 
   */
   */
-static int do_bufinfo_ioctl(comedi_device *dev, void *arg)
+static int do_bufinfo_ioctl(struct comedi_device *dev, void *arg)
 {
 {
-	comedi_bufinfo bi;
-	comedi_subdevice *s;
-	comedi_async *async;
+	struct comedi_bufinfo bi;
+	struct comedi_subdevice *s;
+	struct comedi_async *async;
 
 
-	if (copy_from_user(&bi, arg, sizeof(comedi_bufinfo)))
+	if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
 	if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0)
@@ -591,13 +601,13 @@ static int do_bufinfo_ioctl(comedi_device *dev, void *arg)
 	bi.buf_read_ptr = async->buf_read_ptr;
 	bi.buf_read_ptr = async->buf_read_ptr;
 
 
 copyback:
 copyback:
-	if (copy_to_user(arg, &bi, sizeof(comedi_bufinfo)))
+	if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo)))
 		return -EFAULT;
 		return -EFAULT;
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-static int parse_insn(comedi_device *dev, comedi_insn *insn, lsampl_t *data,
+static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data,
 		      void *file);
 		      void *file);
 /*
 /*
  * 	COMEDI_INSNLIST
  * 	COMEDI_INSNLIST
@@ -616,25 +626,25 @@ static int parse_insn(comedi_device *dev, comedi_insn *insn, lsampl_t *data,
  */
  */
 /* arbitrary limits */
 /* arbitrary limits */
 #define MAX_SAMPLES 256
 #define MAX_SAMPLES 256
-static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file)
+static int do_insnlist_ioctl(struct comedi_device *dev, void *arg, void *file)
 {
 {
-	comedi_insnlist insnlist;
-	comedi_insn *insns = NULL;
-	lsampl_t *data = NULL;
+	struct comedi_insnlist insnlist;
+	struct comedi_insn *insns = NULL;
+	unsigned int *data = NULL;
 	int i = 0;
 	int i = 0;
 	int ret = 0;
 	int ret = 0;
 
 
-	if (copy_from_user(&insnlist, arg, sizeof(comedi_insnlist)))
+	if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist)))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	data = kmalloc(sizeof(lsampl_t) * MAX_SAMPLES, GFP_KERNEL);
+	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
 	if (!data) {
 	if (!data) {
 		DPRINTK("kmalloc failed\n");
 		DPRINTK("kmalloc failed\n");
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto error;
 		goto error;
 	}
 	}
 
 
-	insns = kmalloc(sizeof(comedi_insn) * insnlist.n_insns, GFP_KERNEL);
+	insns = kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL);
 	if (!insns) {
 	if (!insns) {
 		DPRINTK("kmalloc failed\n");
 		DPRINTK("kmalloc failed\n");
 		ret = -ENOMEM;
 		ret = -ENOMEM;
@@ -642,7 +652,7 @@ static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file)
 	}
 	}
 
 
 	if (copy_from_user(insns, insnlist.insns,
 	if (copy_from_user(insns, insnlist.insns,
-			   sizeof(comedi_insn) * insnlist.n_insns)) {
+			   sizeof(struct comedi_insn) * insnlist.n_insns)) {
 		DPRINTK("copy_from_user failed\n");
 		DPRINTK("copy_from_user failed\n");
 		ret = -EFAULT;
 		ret = -EFAULT;
 		goto error;
 		goto error;
@@ -656,7 +666,7 @@ static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file)
 		}
 		}
 		if (insns[i].insn & INSN_MASK_WRITE) {
 		if (insns[i].insn & INSN_MASK_WRITE) {
 			if (copy_from_user(data, insns[i].data,
 			if (copy_from_user(data, insns[i].data,
-					   insns[i].n * sizeof(lsampl_t))) {
+					   insns[i].n * sizeof(unsigned int))) {
 				DPRINTK("copy_from_user failed\n");
 				DPRINTK("copy_from_user failed\n");
 				ret = -EFAULT;
 				ret = -EFAULT;
 				goto error;
 				goto error;
@@ -667,7 +677,7 @@ static int do_insnlist_ioctl(comedi_device *dev, void *arg, void *file)
 			goto error;
 			goto error;
 		if (insns[i].insn & INSN_MASK_READ) {
 		if (insns[i].insn & INSN_MASK_READ) {
 			if (copy_to_user(insns[i].data, data,
 			if (copy_to_user(insns[i].data, data,
-					 insns[i].n * sizeof(lsampl_t))) {
+					 insns[i].n * sizeof(unsigned int))) {
 				DPRINTK("copy_to_user failed\n");
 				DPRINTK("copy_to_user failed\n");
 				ret = -EFAULT;
 				ret = -EFAULT;
 				goto error;
 				goto error;
@@ -686,7 +696,7 @@ error:
 	return i;
 	return i;
 }
 }
 
 
-static int check_insn_config_length(comedi_insn *insn, lsampl_t *data)
+static int check_insn_config_length(struct comedi_insn *insn, unsigned int *data)
 {
 {
 	if (insn->n < 1)
 	if (insn->n < 1)
 		return -EINVAL;
 		return -EINVAL;
@@ -747,10 +757,10 @@ static int check_insn_config_length(comedi_insn *insn, lsampl_t *data)
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static int parse_insn(comedi_device *dev, comedi_insn *insn, lsampl_t *data,
+static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data,
 		      void *file)
 		      void *file)
 {
 {
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 	int ret = 0;
 	int ret = 0;
 	int i;
 	int i;
 
 
@@ -815,7 +825,7 @@ static int parse_insn(comedi_device *dev, comedi_insn *insn, lsampl_t *data,
 		}
 		}
 	} else {
 	} else {
 		/* a subdevice instruction */
 		/* a subdevice instruction */
-		lsampl_t maxdata;
+		unsigned int maxdata;
 
 
 		if (insn->subdev >= dev->n_subdevices) {
 		if (insn->subdev >= dev->n_subdevices) {
 			DPRINTK("subdevice %d out of range\n", insn->subdev);
 			DPRINTK("subdevice %d out of range\n", insn->subdev);
@@ -901,25 +911,25 @@ out:
  * 		pointer to insn
  * 		pointer to insn
  *
  *
  * 	reads:
  * 	reads:
- * 		comedi_insn struct at arg
+ * 		struct comedi_insn struct at arg
  * 		data (for writes)
  * 		data (for writes)
  *
  *
  * 	writes:
  * 	writes:
  * 		data (for reads)
  * 		data (for reads)
  */
  */
-static int do_insn_ioctl(comedi_device *dev, void *arg, void *file)
+static int do_insn_ioctl(struct comedi_device *dev, void *arg, void *file)
 {
 {
-	comedi_insn insn;
-	lsampl_t *data = NULL;
+	struct comedi_insn insn;
+	unsigned int *data = NULL;
 	int ret = 0;
 	int ret = 0;
 
 
-	data = kmalloc(sizeof(lsampl_t) * MAX_SAMPLES, GFP_KERNEL);
+	data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL);
 	if (!data) {
 	if (!data) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto error;
 		goto error;
 	}
 	}
 
 
-	if (copy_from_user(&insn, arg, sizeof(comedi_insn))) {
+	if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) {
 		ret = -EFAULT;
 		ret = -EFAULT;
 		goto error;
 		goto error;
 	}
 	}
@@ -928,7 +938,7 @@ static int do_insn_ioctl(comedi_device *dev, void *arg, void *file)
 	if (insn.n > MAX_SAMPLES)
 	if (insn.n > MAX_SAMPLES)
 		insn.n = MAX_SAMPLES;
 		insn.n = MAX_SAMPLES;
 	if (insn.insn & INSN_MASK_WRITE) {
 	if (insn.insn & INSN_MASK_WRITE) {
-		if (copy_from_user(data, insn.data, insn.n * sizeof(lsampl_t))) {
+		if (copy_from_user(data, insn.data, insn.n * sizeof(unsigned int))) {
 			ret = -EFAULT;
 			ret = -EFAULT;
 			goto error;
 			goto error;
 		}
 		}
@@ -937,7 +947,7 @@ static int do_insn_ioctl(comedi_device *dev, void *arg, void *file)
 	if (ret < 0)
 	if (ret < 0)
 		goto error;
 		goto error;
 	if (insn.insn & INSN_MASK_READ) {
 	if (insn.insn & INSN_MASK_READ) {
-		if (copy_to_user(insn.data, data, insn.n * sizeof(lsampl_t))) {
+		if (copy_to_user(insn.data, data, insn.n * sizeof(unsigned int))) {
 			ret = -EFAULT;
 			ret = -EFAULT;
 			goto error;
 			goto error;
 		}
 		}
@@ -965,15 +975,15 @@ error:
 		modified cmd structure at arg
 		modified cmd structure at arg
 
 
 */
 */
-static int do_cmd_ioctl(comedi_device *dev, void *arg, void *file)
+static int do_cmd_ioctl(struct comedi_device *dev, void *arg, void *file)
 {
 {
-	comedi_cmd user_cmd;
-	comedi_subdevice *s;
-	comedi_async *async;
+	struct comedi_cmd user_cmd;
+	struct comedi_subdevice *s;
+	struct comedi_async *async;
 	int ret = 0;
 	int ret = 0;
 	unsigned int *chanlist_saver = NULL;
 	unsigned int *chanlist_saver = NULL;
 
 
-	if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
+	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
 		DPRINTK("bad cmd address\n");
 		DPRINTK("bad cmd address\n");
 		return -EFAULT;
 		return -EFAULT;
 	}
 	}
@@ -1062,7 +1072,7 @@ static int do_cmd_ioctl(comedi_device *dev, void *arg, void *file)
 		/* restore chanlist pointer before copying back */
 		/* restore chanlist pointer before copying back */
 		user_cmd.chanlist = chanlist_saver;
 		user_cmd.chanlist = chanlist_saver;
 		user_cmd.data = NULL;
 		user_cmd.data = NULL;
-		if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
+		if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
 			DPRINTK("fault writing cmd\n");
 			DPRINTK("fault writing cmd\n");
 			ret = -EFAULT;
 			ret = -EFAULT;
 			goto cleanup;
 			goto cleanup;
@@ -1119,15 +1129,15 @@ cleanup:
 		modified cmd structure at arg
 		modified cmd structure at arg
 
 
 */
 */
-static int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file)
+static int do_cmdtest_ioctl(struct comedi_device *dev, void *arg, void *file)
 {
 {
-	comedi_cmd user_cmd;
-	comedi_subdevice *s;
+	struct comedi_cmd user_cmd;
+	struct comedi_subdevice *s;
 	int ret = 0;
 	int ret = 0;
 	unsigned int *chanlist = NULL;
 	unsigned int *chanlist = NULL;
 	unsigned int *chanlist_saver = NULL;
 	unsigned int *chanlist_saver = NULL;
 
 
-	if (copy_from_user(&user_cmd, arg, sizeof(comedi_cmd))) {
+	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
 		DPRINTK("bad cmd address\n");
 		DPRINTK("bad cmd address\n");
 		return -EFAULT;
 		return -EFAULT;
 	}
 	}
@@ -1191,7 +1201,7 @@ static int do_cmdtest_ioctl(comedi_device *dev, void *arg, void *file)
 	/* restore chanlist pointer before copying back */
 	/* restore chanlist pointer before copying back */
 	user_cmd.chanlist = chanlist_saver;
 	user_cmd.chanlist = chanlist_saver;
 
 
-	if (copy_to_user(arg, &user_cmd, sizeof(comedi_cmd))) {
+	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
 		DPRINTK("bad cmd address\n");
 		DPRINTK("bad cmd address\n");
 		ret = -EFAULT;
 		ret = -EFAULT;
 		goto cleanup;
 		goto cleanup;
@@ -1217,11 +1227,11 @@ cleanup:
 
 
 */
 */
 
 
-static int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file)
+static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
 {
 {
 	int ret = 0;
 	int ret = 0;
 	unsigned long flags;
 	unsigned long flags;
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 
 
 	if (arg >= dev->n_subdevices)
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
 		return -EINVAL;
@@ -1261,9 +1271,9 @@ static int do_lock_ioctl(comedi_device *dev, unsigned int arg, void *file)
 	This function isn't protected by the semaphore, since
 	This function isn't protected by the semaphore, since
 	we already own the lock.
 	we already own the lock.
 */
 */
-static int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file)
+static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
 {
 {
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 
 
 	if (arg >= dev->n_subdevices)
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
 		return -EINVAL;
@@ -1301,9 +1311,9 @@ static int do_unlock_ioctl(comedi_device *dev, unsigned int arg, void *file)
 		nothing
 		nothing
 
 
 */
 */
-static int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file)
+static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
 {
 {
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 
 
 	if (arg >= dev->n_subdevices)
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
 		return -EINVAL;
@@ -1337,9 +1347,9 @@ static int do_cancel_ioctl(comedi_device *dev, unsigned int arg, void *file)
 		nothing
 		nothing
 
 
 */
 */
-static int do_poll_ioctl(comedi_device *dev, unsigned int arg, void *file)
+static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, void *file)
 {
 {
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 
 
 	if (arg >= dev->n_subdevices)
 	if (arg >= dev->n_subdevices)
 		return -EINVAL;
 		return -EINVAL;
@@ -1360,7 +1370,7 @@ static int do_poll_ioctl(comedi_device *dev, unsigned int arg, void *file)
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static int do_cancel(comedi_device *dev, comedi_subdevice *s)
+static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 {
 	int ret = 0;
 	int ret = 0;
 
 
@@ -1374,8 +1384,8 @@ static int do_cancel(comedi_device *dev, comedi_subdevice *s)
 
 
 void comedi_unmap(struct vm_area_struct *area)
 void comedi_unmap(struct vm_area_struct *area)
 {
 {
-	comedi_async *async;
-	comedi_device *dev;
+	struct comedi_async *async;
+	struct comedi_device *dev;
 
 
 	async = area->vm_private_data;
 	async = area->vm_private_data;
 	dev = async->subdevice->device;
 	dev = async->subdevice->device;
@@ -1394,14 +1404,14 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
-	comedi_async *async = NULL;
+	struct comedi_device *dev = dev_file_info->device;
+	struct comedi_async *async = NULL;
 	unsigned long start = vma->vm_start;
 	unsigned long start = vma->vm_start;
 	unsigned long size;
 	unsigned long size;
 	int n_pages;
 	int n_pages;
 	int i;
 	int i;
 	int retval;
 	int retval;
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 
 
 	mutex_lock(&dev->mutex);
 	mutex_lock(&dev->mutex);
 	if (!dev->attached) {
 	if (!dev->attached) {
@@ -1470,9 +1480,9 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
-	comedi_subdevice *read_subdev;
-	comedi_subdevice *write_subdev;
+	struct comedi_device *dev = dev_file_info->device;
+	struct comedi_subdevice *read_subdev;
+	struct comedi_subdevice *write_subdev;
 
 
 	mutex_lock(&dev->mutex);
 	mutex_lock(&dev->mutex);
 	if (!dev->attached) {
 	if (!dev->attached) {
@@ -1513,14 +1523,14 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
 static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
 static ssize_t comedi_write(struct file *file, const char *buf, size_t nbytes,
 			    loff_t *offset)
 			    loff_t *offset)
 {
 {
-	comedi_subdevice *s;
-	comedi_async *async;
+	struct comedi_subdevice *s;
+	struct comedi_async *async;
 	int n, m, count = 0, retval = 0;
 	int n, m, count = 0, retval = 0;
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
+	struct comedi_device *dev = dev_file_info->device;
 
 
 	if (!dev->attached) {
 	if (!dev->attached) {
 		DPRINTK("no driver configured on comedi%i\n", dev->minor);
 		DPRINTK("no driver configured on comedi%i\n", dev->minor);
@@ -1615,14 +1625,14 @@ done:
 static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
 static ssize_t comedi_read(struct file *file, char *buf, size_t nbytes,
 			   loff_t *offset)
 			   loff_t *offset)
 {
 {
-	comedi_subdevice *s;
-	comedi_async *async;
+	struct comedi_subdevice *s;
+	struct comedi_async *async;
 	int n, m, count = 0, retval = 0;
 	int n, m, count = 0, retval = 0;
 	DECLARE_WAITQUEUE(wait, current);
 	DECLARE_WAITQUEUE(wait, current);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	const unsigned minor = iminor(file->f_dentry->d_inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
+	struct comedi_device *dev = dev_file_info->device;
 
 
 	if (!dev->attached) {
 	if (!dev->attached) {
 		DPRINTK("no driver configured on comedi%i\n", dev->minor);
 		DPRINTK("no driver configured on comedi%i\n", dev->minor);
@@ -1723,9 +1733,9 @@ done:
 /*
 /*
    This function restores a subdevice to an idle state.
    This function restores a subdevice to an idle state.
  */
  */
-void do_become_nonbusy(comedi_device *dev, comedi_subdevice *s)
+void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 {
-	comedi_async *async = s->async;
+	struct comedi_async *async = s->async;
 
 
 	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
 	comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
 #ifdef CONFIG_COMEDI_RT
 #ifdef CONFIG_COMEDI_RT
@@ -1747,11 +1757,11 @@ void do_become_nonbusy(comedi_device *dev, comedi_subdevice *s)
 
 
 static int comedi_open(struct inode *inode, struct file *file)
 static int comedi_open(struct inode *inode, struct file *file)
 {
 {
-	char mod[32];
 	const unsigned minor = iminor(inode);
 	const unsigned minor = iminor(inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
+	struct comedi_device *dev = dev_file_info ? dev_file_info->device : NULL;
+
 	if (dev == NULL) {
 	if (dev == NULL) {
 		DPRINTK("invalid minor number\n");
 		DPRINTK("invalid minor number\n");
 		return -ENODEV;
 		return -ENODEV;
@@ -1783,10 +1793,9 @@ static int comedi_open(struct inode *inode, struct file *file)
 
 
 	dev->in_request_module = 1;
 	dev->in_request_module = 1;
 
 
-	sprintf(mod, "char-major-%i-%i", COMEDI_MAJOR, dev->minor);
 #ifdef CONFIG_KMOD
 #ifdef CONFIG_KMOD
 	mutex_unlock(&dev->mutex);
 	mutex_unlock(&dev->mutex);
-	request_module(mod);
+	request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor);
 	mutex_lock(&dev->mutex);
 	mutex_lock(&dev->mutex);
 #endif
 #endif
 
 
@@ -1823,8 +1832,8 @@ static int comedi_close(struct inode *inode, struct file *file)
 	const unsigned minor = iminor(inode);
 	const unsigned minor = iminor(inode);
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
-	comedi_device *dev = dev_file_info->device;
-	comedi_subdevice *s = NULL;
+	struct comedi_device *dev = dev_file_info->device;
+	struct comedi_subdevice *s = NULL;
 	int i;
 	int i;
 
 
 	mutex_lock(&dev->mutex);
 	mutex_lock(&dev->mutex);
@@ -1862,7 +1871,7 @@ static int comedi_fasync(int fd, struct file *file, int on)
 	struct comedi_device_file_info *dev_file_info =
 	struct comedi_device_file_info *dev_file_info =
 	    comedi_get_device_file_info(minor);
 	    comedi_get_device_file_info(minor);
 
 
-	comedi_device *dev = dev_file_info->device;
+	struct comedi_device *dev = dev_file_info->device;
 
 
 	return fasync_helper(fd, file, on, &dev->async_queue);
 	return fasync_helper(fd, file, on, &dev->async_queue);
 }
 }
@@ -1893,7 +1902,7 @@ static void comedi_cleanup_legacy_minors(void)
 {
 {
 	unsigned i;
 	unsigned i;
 
 
-	for (i = 0; i < COMEDI_NUM_LEGACY_MINORS; i++)
+	for (i = 0; i < comedi_num_legacy_minors; i++)
 		comedi_free_board_minor(i);
 		comedi_free_board_minor(i);
 }
 }
 
 
@@ -1905,6 +1914,22 @@ static int __init comedi_init(void)
 	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
 	printk(KERN_INFO "comedi: version " COMEDI_RELEASE
 	       " - http://www.comedi.org\n");
 	       " - http://www.comedi.org\n");
 
 
+	if (comedi_num_legacy_minors < 0 ||
+	    comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
+		printk(KERN_ERR "comedi: error: invalid value for module "
+		       "parameter \"comedi_num_legacy_minors\".  Valid values "
+		       "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
+		return -EINVAL;
+	}
+
+	/*
+	 * comedi is unusable if both comedi_autoconfig and
+	 * comedi_num_legacy_minors are zero, so we might as well adjust the
+	 * defaults in that case
+	 */
+	if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0)
+		comedi_num_legacy_minors = 16;
+
 	memset(comedi_file_info_table, 0,
 	memset(comedi_file_info_table, 0,
 	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
 	       sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS);
 
 
@@ -1933,7 +1958,7 @@ static int __init comedi_init(void)
 	comedi_proc_init();
 	comedi_proc_init();
 
 
 	/* create devices files for legacy/manual use */
 	/* create devices files for legacy/manual use */
-	for (i = 0; i < COMEDI_NUM_LEGACY_MINORS; i++) {
+	for (i = 0; i < comedi_num_legacy_minors; i++) {
 		int minor;
 		int minor;
 		minor = comedi_alloc_board_minor(NULL);
 		minor = comedi_alloc_board_minor(NULL);
 		if (minor < 0) {
 		if (minor < 0) {
@@ -1975,15 +2000,15 @@ static void __exit comedi_cleanup(void)
 module_init(comedi_init);
 module_init(comedi_init);
 module_exit(comedi_cleanup);
 module_exit(comedi_cleanup);
 
 
-void comedi_error(const comedi_device *dev, const char *s)
+void comedi_error(const struct comedi_device *dev, const char *s)
 {
 {
 	rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
 	rt_printk("comedi%d: %s: %s\n", dev->minor, dev->driver->driver_name,
 		  s);
 		  s);
 }
 }
 
 
-void comedi_event(comedi_device *dev, comedi_subdevice *s)
+void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 {
-	comedi_async *async = s->async;
+	struct comedi_async *async = s->async;
 	unsigned runflags = 0;
 	unsigned runflags = 0;
 	unsigned runflags_mask = 0;
 	unsigned runflags_mask = 0;
 
 
@@ -2042,7 +2067,7 @@ void comedi_event(comedi_device *dev, comedi_subdevice *s)
 	s->async->events = 0;
 	s->async->events = 0;
 }
 }
 
 
-void comedi_set_subdevice_runflags(comedi_subdevice *s, unsigned mask,
+void comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
 				   unsigned bits)
 				   unsigned bits)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
@@ -2053,7 +2078,7 @@ void comedi_set_subdevice_runflags(comedi_subdevice *s, unsigned mask,
 	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
 	comedi_spin_unlock_irqrestore(&s->spin_lock, flags);
 }
 }
 
 
-unsigned comedi_get_subdevice_runflags(comedi_subdevice *s)
+unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	unsigned runflags;
 	unsigned runflags;
@@ -2064,9 +2089,9 @@ unsigned comedi_get_subdevice_runflags(comedi_subdevice *s)
 	return runflags;
 	return runflags;
 }
 }
 
 
-static int is_device_busy(comedi_device *dev)
+static int is_device_busy(struct comedi_device *dev)
 {
 {
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 	int i;
 	int i;
 
 
 	if (!dev->attached)
 	if (!dev->attached)
@@ -2083,15 +2108,15 @@ static int is_device_busy(comedi_device *dev)
 	return 0;
 	return 0;
 }
 }
 
 
-void comedi_device_init(comedi_device *dev)
+void comedi_device_init(struct comedi_device *dev)
 {
 {
-	memset(dev, 0, sizeof(comedi_device));
+	memset(dev, 0, sizeof(struct comedi_device));
 	spin_lock_init(&dev->spinlock);
 	spin_lock_init(&dev->spinlock);
 	mutex_init(&dev->mutex);
 	mutex_init(&dev->mutex);
 	dev->minor = -1;
 	dev->minor = -1;
 }
 }
 
 
-void comedi_device_cleanup(comedi_device *dev)
+void comedi_device_cleanup(struct comedi_device *dev)
 {
 {
 	if (dev == NULL)
 	if (dev == NULL)
 		return;
 		return;
@@ -2105,13 +2130,13 @@ int comedi_alloc_board_minor(struct device *hardware_device)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	struct comedi_device_file_info *info;
 	struct comedi_device_file_info *info;
-	device_create_result_type *csdev;
+	struct device *csdev;
 	unsigned i;
 	unsigned i;
 
 
 	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
 	info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
 	if (info == NULL)
 	if (info == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
-	info->device = kzalloc(sizeof(comedi_device), GFP_KERNEL);
+	info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
 	if (info->device == NULL) {
 	if (info->device == NULL) {
 		kfree(info);
 		kfree(info);
 		return -ENOMEM;
 		return -ENOMEM;
@@ -2155,7 +2180,7 @@ void comedi_free_board_minor(unsigned minor)
 	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
 	comedi_spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
 
 
 	if (info) {
 	if (info) {
-		comedi_device *dev = info->device;
+		struct comedi_device *dev = info->device;
 		if (dev) {
 		if (dev) {
 			if (dev->class_dev) {
 			if (dev->class_dev) {
 				device_destroy(comedi_class,
 				device_destroy(comedi_class,
@@ -2168,11 +2193,11 @@ void comedi_free_board_minor(unsigned minor)
 	}
 	}
 }
 }
 
 
-int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s)
+int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	struct comedi_device_file_info *info;
 	struct comedi_device_file_info *info;
-	device_create_result_type *csdev;
+	struct device *csdev;
 	unsigned i;
 	unsigned i;
 
 
 	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
 	info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
@@ -2182,7 +2207,7 @@ int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s)
 	info->read_subdevice = s;
 	info->read_subdevice = s;
 	info->write_subdevice = s;
 	info->write_subdevice = s;
 	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
 	comedi_spin_lock_irqsave(&comedi_file_info_table_lock, flags);
-	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_BOARD_MINORS; ++i) {
+	for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
 		if (comedi_file_info_table[i] == NULL) {
 		if (comedi_file_info_table[i] == NULL) {
 			comedi_file_info_table[i] = info;
 			comedi_file_info_table[i] = info;
 			break;
 			break;
@@ -2206,7 +2231,7 @@ int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s)
 	return i;
 	return i;
 }
 }
 
 
-void comedi_free_subdevice_minor(comedi_subdevice *s)
+void comedi_free_subdevice_minor(struct comedi_subdevice *s)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 	struct comedi_device_file_info *info;
 	struct comedi_device_file_info *info;

+ 1 - 0
drivers/staging/comedi/comedi_fops.h

@@ -4,5 +4,6 @@
 
 
 extern struct class *comedi_class;
 extern struct class *comedi_class;
 extern const struct file_operations comedi_fops;
 extern const struct file_operations comedi_fops;
+extern int comedi_autoconfig;
 
 
 #endif /* _COMEDI_FOPS_H */
 #endif /* _COMEDI_FOPS_H */

+ 7 - 5
drivers/staging/comedi/comedi_ksyms.c

@@ -31,12 +31,12 @@
 /* for drivers */
 /* for drivers */
 EXPORT_SYMBOL(comedi_driver_register);
 EXPORT_SYMBOL(comedi_driver_register);
 EXPORT_SYMBOL(comedi_driver_unregister);
 EXPORT_SYMBOL(comedi_driver_unregister);
-//EXPORT_SYMBOL(comedi_bufcheck);
-//EXPORT_SYMBOL(comedi_done);
-//EXPORT_SYMBOL(comedi_error_done);
+/* EXPORT_SYMBOL(comedi_bufcheck); */
+/* EXPORT_SYMBOL(comedi_done); */
+/* EXPORT_SYMBOL(comedi_error_done); */
 EXPORT_SYMBOL(comedi_error);
 EXPORT_SYMBOL(comedi_error);
-//EXPORT_SYMBOL(comedi_eobuf);
-//EXPORT_SYMBOL(comedi_eos);
+/* EXPORT_SYMBOL(comedi_eobuf); */
+/* EXPORT_SYMBOL(comedi_eos); */
 EXPORT_SYMBOL(comedi_event);
 EXPORT_SYMBOL(comedi_event);
 EXPORT_SYMBOL(comedi_get_subdevice_runflags);
 EXPORT_SYMBOL(comedi_get_subdevice_runflags);
 EXPORT_SYMBOL(comedi_set_subdevice_runflags);
 EXPORT_SYMBOL(comedi_set_subdevice_runflags);
@@ -60,6 +60,8 @@ EXPORT_SYMBOL_GPL(comedi_alloc_board_minor);
 EXPORT_SYMBOL_GPL(comedi_free_board_minor);
 EXPORT_SYMBOL_GPL(comedi_free_board_minor);
 EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
 EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
 EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
 EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
+EXPORT_SYMBOL_GPL(comedi_usb_auto_config);
+EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig);
 
 
 /* for kcomedilib */
 /* for kcomedilib */
 EXPORT_SYMBOL(check_chanlist);
 EXPORT_SYMBOL(check_chanlist);

+ 4 - 5
drivers/staging/comedi/comedi_rt.h

@@ -28,7 +28,6 @@
 #error comedi_rt.h should only be included by comedidev.h
 #error comedi_rt.h should only be included by comedidev.h
 #endif
 #endif
 
 
-#include <linux/version.h>
 #include <linux/kdev_t.h>
 #include <linux/kdev_t.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
@@ -59,12 +58,12 @@
 
 
 int comedi_request_irq(unsigned int irq, irqreturn_t(*handler) (int,
 int comedi_request_irq(unsigned int irq, irqreturn_t(*handler) (int,
 		void *PT_REGS_ARG), unsigned long flags, const char *device,
 		void *PT_REGS_ARG), unsigned long flags, const char *device,
-		comedi_device *dev_id);
-void comedi_free_irq(unsigned int irq, comedi_device *dev_id);
+		struct comedi_device *dev_id);
+void comedi_free_irq(unsigned int irq, struct comedi_device *dev_id);
 void comedi_rt_init(void);
 void comedi_rt_init(void);
 void comedi_rt_cleanup(void);
 void comedi_rt_cleanup(void);
-int comedi_switch_to_rt(comedi_device *dev);
-void comedi_switch_to_non_rt(comedi_device *dev);
+int comedi_switch_to_rt(struct comedi_device *dev);
+void comedi_switch_to_non_rt(struct comedi_device *dev);
 void comedi_rt_pend_wakeup(wait_queue_head_t *q);
 void comedi_rt_pend_wakeup(wait_queue_head_t *q);
 extern int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1,
 extern int rt_pend_call(void (*func) (int arg1, void *arg2), int arg1,
 	void *arg2);
 	void *arg2);

+ 97 - 105
drivers/staging/comedi/comedidev.h

@@ -26,7 +26,6 @@
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/kdev_t.h>
 #include <linux/kdev_t.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
@@ -36,7 +35,6 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
-#include <linux/mm.h>
 #include "interrupt.h"
 #include "interrupt.h"
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
@@ -55,9 +53,9 @@
 
 
 #define COMEDI_INITCLEANUP_NOMODULE(x)					\
 #define COMEDI_INITCLEANUP_NOMODULE(x)					\
 	static int __init x ## _init_module(void)			\
 	static int __init x ## _init_module(void)			\
-		{return comedi_driver_register(&(x));}			\
+		{return comedi_driver_register(&(x)); }			\
 	static void __exit x ## _cleanup_module(void)			\
 	static void __exit x ## _cleanup_module(void)			\
-		{comedi_driver_unregister(&(x));} 			\
+		{comedi_driver_unregister(&(x)); } 			\
 	module_init(x ## _init_module);					\
 	module_init(x ## _init_module);					\
 	module_exit(x ## _cleanup_module);					\
 	module_exit(x ## _cleanup_module);					\
 
 
@@ -120,23 +118,14 @@
 #define PCI_VENDOR_ID_MEILHAUS		0x1402
 #define PCI_VENDOR_ID_MEILHAUS		0x1402
 
 
 #define COMEDI_NUM_MINORS 0x100
 #define COMEDI_NUM_MINORS 0x100
-#define COMEDI_NUM_LEGACY_MINORS 0x10
 #define COMEDI_NUM_BOARD_MINORS 0x30
 #define COMEDI_NUM_BOARD_MINORS 0x30
 #define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS
 #define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS
 
 
-typedef struct comedi_device_struct comedi_device;
-typedef struct comedi_subdevice_struct comedi_subdevice;
-typedef struct comedi_async_struct comedi_async;
-typedef struct comedi_driver_struct comedi_driver;
-typedef struct comedi_lrange_struct comedi_lrange;
-
-typedef struct device device_create_result_type;
-
 #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, device, fmt...) \
 #define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, device, fmt...) \
 	device_create(cs, ((parent) ? (parent) : (device)), devt, drvdata, fmt)
 	device_create(cs, ((parent) ? (parent) : (device)), devt, drvdata, fmt)
 
 
-struct comedi_subdevice_struct {
-	comedi_device *device;
+struct comedi_subdevice {
+	struct comedi_device *device;
 	int type;
 	int type;
 	int n_chan;
 	int n_chan;
 	volatile int subdev_flags;
 	volatile int subdev_flags;
@@ -144,7 +133,7 @@ struct comedi_subdevice_struct {
 
 
 	void *private;
 	void *private;
 
 
-	comedi_async *async;
+	struct comedi_async *async;
 
 
 	void *lock;
 	void *lock;
 	void *busy;
 	void *busy;
@@ -153,46 +142,46 @@ struct comedi_subdevice_struct {
 
 
 	int io_bits;
 	int io_bits;
 
 
-	lsampl_t maxdata;	/* if maxdata==0, use list */
-	const lsampl_t *maxdata_list;	/* list is channel specific */
+	unsigned int maxdata;	/* if maxdata==0, use list */
+	const unsigned int *maxdata_list;	/* list is channel specific */
 
 
 	unsigned int flags;
 	unsigned int flags;
 	const unsigned int *flaglist;
 	const unsigned int *flaglist;
 
 
 	unsigned int settling_time_0;
 	unsigned int settling_time_0;
 
 
-	const comedi_lrange *range_table;
-	const comedi_lrange *const *range_table_list;
+	const struct comedi_lrange *range_table;
+	const struct comedi_lrange *const *range_table_list;
 
 
 	unsigned int *chanlist;	/* driver-owned chanlist (not used) */
 	unsigned int *chanlist;	/* driver-owned chanlist (not used) */
 
 
-	int (*insn_read) (comedi_device *, comedi_subdevice *, comedi_insn *,
-		lsampl_t *);
-	int (*insn_write) (comedi_device *, comedi_subdevice *, comedi_insn *,
-		lsampl_t *);
-	int (*insn_bits) (comedi_device *, comedi_subdevice *, comedi_insn *,
-		lsampl_t *);
-	int (*insn_config) (comedi_device *, comedi_subdevice *, comedi_insn *,
-		lsampl_t *);
-
-	int (*do_cmd) (comedi_device *, comedi_subdevice *);
-	int (*do_cmdtest) (comedi_device *, comedi_subdevice *, comedi_cmd *);
-	int (*poll) (comedi_device *, comedi_subdevice *);
-	int (*cancel) (comedi_device *, comedi_subdevice *);
-	/* int (*do_lock)(comedi_device *,comedi_subdevice *); */
-	/* int (*do_unlock)(comedi_device *,comedi_subdevice *); */
+	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 *);
+	/* int (*do_lock)(struct comedi_device *,struct comedi_subdevice *); */
+	/* int (*do_unlock)(struct comedi_device *,struct comedi_subdevice *); */
 
 
 	/* called when the buffer changes */
 	/* called when the buffer changes */
-	int (*buf_change) (comedi_device *dev, comedi_subdevice *s,
+	int (*buf_change) (struct comedi_device *dev, struct comedi_subdevice *s,
 		unsigned long new_size);
 		unsigned long new_size);
 
 
-	void (*munge) (comedi_device *dev, comedi_subdevice *s, void *data,
+	void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s, void *data,
 		unsigned int num_bytes, unsigned int start_chan_index);
 		unsigned int num_bytes, unsigned int start_chan_index);
 	enum dma_data_direction async_dma_dir;
 	enum dma_data_direction async_dma_dir;
 
 
 	unsigned int state;
 	unsigned int state;
 
 
-	device_create_result_type *class_dev;
+	struct device *class_dev;
 	int minor;
 	int minor;
 };
 };
 
 
@@ -201,8 +190,8 @@ struct comedi_buf_page {
 	dma_addr_t dma_addr;
 	dma_addr_t dma_addr;
 };
 };
 
 
-struct comedi_async_struct {
-	comedi_subdevice *subdevice;
+struct comedi_async {
+	struct comedi_subdevice *subdevice;
 
 
 	void *prealloc_buf;	/* pre-allocated buffer */
 	void *prealloc_buf;	/* pre-allocated buffer */
 	unsigned int prealloc_bufsz;	/* buffer size, in bytes */
 	unsigned int prealloc_bufsz;	/* buffer size, in bytes */
@@ -232,7 +221,7 @@ struct comedi_async_struct {
 
 
 	unsigned int events;	/* events that have occurred */
 	unsigned int events;	/* events that have occurred */
 
 
-	comedi_cmd cmd;
+	struct comedi_cmd cmd;
 
 
 	wait_queue_head_t wait_head;
 	wait_queue_head_t wait_head;
 
 
@@ -241,17 +230,17 @@ struct comedi_async_struct {
 	int (*cb_func) (unsigned int flags, void *);
 	int (*cb_func) (unsigned int flags, void *);
 	void *cb_arg;
 	void *cb_arg;
 
 
-	int (*inttrig) (comedi_device *dev, comedi_subdevice *s,
+	int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s,
 			unsigned int x);
 			unsigned int x);
 };
 };
 
 
-struct comedi_driver_struct {
-	struct comedi_driver_struct *next;
+struct comedi_driver {
+	struct comedi_driver *next;
 
 
 	const char *driver_name;
 	const char *driver_name;
 	struct module *module;
 	struct module *module;
-	int (*attach) (comedi_device *, comedi_devconfig *);
-	int (*detach) (comedi_device *);
+	int (*attach) (struct comedi_device *, struct comedi_devconfig *);
+	int (*detach) (struct comedi_device *);
 
 
 	/* number of elements in board_name and board_id arrays */
 	/* number of elements in board_name and board_id arrays */
 	unsigned int num_names;
 	unsigned int num_names;
@@ -260,12 +249,12 @@ struct comedi_driver_struct {
 	int offset;
 	int offset;
 };
 };
 
 
-struct comedi_device_struct {
+struct comedi_device {
 	int use_count;
 	int use_count;
-	comedi_driver *driver;
+	struct comedi_driver *driver;
 	void *private;
 	void *private;
 
 
-	device_create_result_type *class_dev;
+	struct device *class_dev;
 	int minor;
 	int minor;
 	/* hw_dev is passed to dma_alloc_coherent when allocating async buffers
 	/* hw_dev is passed to dma_alloc_coherent when allocating async buffers
 	 * for subdevices that have async_dma_dir set to something other than
 	 * for subdevices that have async_dma_dir set to something other than
@@ -281,25 +270,25 @@ struct comedi_device_struct {
 	int in_request_module;
 	int in_request_module;
 
 
 	int n_subdevices;
 	int n_subdevices;
-	comedi_subdevice *subdevices;
+	struct comedi_subdevice *subdevices;
 
 
 	/* dumb */
 	/* dumb */
 	unsigned long iobase;
 	unsigned long iobase;
 	unsigned int irq;
 	unsigned int irq;
 
 
-	comedi_subdevice *read_subdev;
-	comedi_subdevice *write_subdev;
+	struct comedi_subdevice *read_subdev;
+	struct comedi_subdevice *write_subdev;
 
 
 	struct fasync_struct *async_queue;
 	struct fasync_struct *async_queue;
 
 
-	void (*open) (comedi_device *dev);
-	void (*close) (comedi_device *dev);
+	void (*open) (struct comedi_device *dev);
+	void (*close) (struct comedi_device *dev);
 };
 };
 
 
 struct comedi_device_file_info {
 struct comedi_device_file_info {
-	comedi_device *device;
-	comedi_subdevice *read_subdevice;
-	comedi_subdevice *write_subdevice;
+	struct comedi_device *device;
+	struct comedi_subdevice *read_subdevice;
+	struct comedi_subdevice *write_subdevice;
 };
 };
 
 
 #ifdef CONFIG_COMEDI_DEBUG
 #ifdef CONFIG_COMEDI_DEBUG
@@ -312,8 +301,8 @@ static const int comedi_debug;
  * function prototypes
  * function prototypes
  */
  */
 
 
-void comedi_event(comedi_device *dev, comedi_subdevice *s);
-void comedi_error(const comedi_device *dev, const char *s);
+void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s);
+void comedi_error(const struct comedi_device *dev, const char *s);
 
 
 /* we can expand the number of bits used to encode devices/subdevices into
 /* we can expand the number of bits used to encode devices/subdevices into
  the minor number soon, after more distros support > 8 bit minor numbers
  the minor number soon, after more distros support > 8 bit minor numbers
@@ -327,7 +316,7 @@ static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1;
 
 
 struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor);
 struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor);
 
 
-static inline comedi_subdevice *comedi_get_read_subdevice(
+static inline struct comedi_subdevice *comedi_get_read_subdevice(
 				const struct comedi_device_file_info *info)
 				const struct comedi_device_file_info *info)
 {
 {
 	if (info->read_subdevice)
 	if (info->read_subdevice)
@@ -337,7 +326,7 @@ static inline comedi_subdevice *comedi_get_read_subdevice(
 	return info->device->read_subdev;
 	return info->device->read_subdev;
 }
 }
 
 
-static inline comedi_subdevice *comedi_get_write_subdevice(
+static inline struct comedi_subdevice *comedi_get_write_subdevice(
 				const struct comedi_device_file_info *info)
 				const struct comedi_device_file_info *info)
 {
 {
 	if (info->write_subdevice)
 	if (info->write_subdevice)
@@ -347,17 +336,17 @@ static inline comedi_subdevice *comedi_get_write_subdevice(
 	return info->device->write_subdev;
 	return info->device->write_subdev;
 }
 }
 
 
-void comedi_device_detach(comedi_device *dev);
-int comedi_device_attach(comedi_device *dev, comedi_devconfig *it);
-int comedi_driver_register(comedi_driver *);
-int comedi_driver_unregister(comedi_driver *);
+void comedi_device_detach(struct comedi_device *dev);
+int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it);
+int comedi_driver_register(struct comedi_driver *);
+int comedi_driver_unregister(struct comedi_driver *);
 
 
 void init_polling(void);
 void init_polling(void);
 void cleanup_polling(void);
 void cleanup_polling(void);
-void start_polling(comedi_device *);
-void stop_polling(comedi_device *);
+void start_polling(struct comedi_device *);
+void stop_polling(struct comedi_device *);
 
 
-int comedi_buf_alloc(comedi_device *dev, comedi_subdevice *s, unsigned long
+int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long
 	new_size);
 	new_size);
 
 
 #ifdef CONFIG_PROC_FS
 #ifdef CONFIG_PROC_FS
@@ -386,13 +375,13 @@ enum subdevice_runflags {
    various internal comedi functions
    various internal comedi functions
  */
  */
 
 
-int do_rangeinfo_ioctl(comedi_device *dev, comedi_rangeinfo *arg);
-int check_chanlist(comedi_subdevice *s, int n, unsigned int *chanlist);
-void comedi_set_subdevice_runflags(comedi_subdevice *s, unsigned mask,
+int do_rangeinfo_ioctl(struct comedi_device *dev, struct comedi_rangeinfo *arg);
+int check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist);
+void comedi_set_subdevice_runflags(struct comedi_subdevice *s, unsigned mask,
 	unsigned bits);
 	unsigned bits);
-unsigned comedi_get_subdevice_runflags(comedi_subdevice *s);
-int insn_inval(comedi_device *dev, comedi_subdevice *s,
-	comedi_insn *insn, lsampl_t *data);
+unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s);
+int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
+	struct comedi_insn *insn, unsigned int *data);
 
 
 /* range stuff */
 /* range stuff */
 
 
@@ -403,12 +392,12 @@ int insn_inval(comedi_device *dev, comedi_subdevice *s,
 #define BIP_RANGE(a)		{-(a)*1e6, (a)*1e6, 0}
 #define BIP_RANGE(a)		{-(a)*1e6, (a)*1e6, 0}
 #define UNI_RANGE(a)		{0, (a)*1e6, 0}
 #define UNI_RANGE(a)		{0, (a)*1e6, 0}
 
 
-extern const comedi_lrange range_bipolar10;
-extern const comedi_lrange range_bipolar5;
-extern const comedi_lrange range_bipolar2_5;
-extern const comedi_lrange range_unipolar10;
-extern const comedi_lrange range_unipolar5;
-extern const comedi_lrange range_unknown;
+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_unknown;
 
 
 #define range_digital		range_unipolar5
 #define range_digital		range_unipolar5
 
 
@@ -418,21 +407,21 @@ extern const comedi_lrange range_unknown;
 #define GCC_ZERO_LENGTH_ARRAY 0
 #define GCC_ZERO_LENGTH_ARRAY 0
 #endif
 #endif
 
 
-struct comedi_lrange_struct {
+struct comedi_lrange {
 	int length;
 	int length;
-	comedi_krange range[GCC_ZERO_LENGTH_ARRAY];
+	struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY];
 };
 };
 
 
 /* some silly little inline functions */
 /* some silly little inline functions */
 
 
-static inline int alloc_subdevices(comedi_device *dev,
+static inline int alloc_subdevices(struct comedi_device *dev,
 				   unsigned int num_subdevices)
 				   unsigned int num_subdevices)
 {
 {
 	unsigned i;
 	unsigned i;
 
 
 	dev->n_subdevices = num_subdevices;
 	dev->n_subdevices = num_subdevices;
 	dev->subdevices =
 	dev->subdevices =
-		kcalloc(num_subdevices, sizeof(comedi_subdevice), GFP_KERNEL);
+		kcalloc(num_subdevices, sizeof(struct comedi_subdevice), GFP_KERNEL);
 	if (!dev->subdevices)
 	if (!dev->subdevices)
 		return -ENOMEM;
 		return -ENOMEM;
 	for (i = 0; i < num_subdevices; ++i) {
 	for (i = 0; i < num_subdevices; ++i) {
@@ -444,7 +433,7 @@ static inline int alloc_subdevices(comedi_device *dev,
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int alloc_private(comedi_device *dev, int size)
+static inline int alloc_private(struct comedi_device *dev, int size)
 {
 {
 	dev->private = kzalloc(size, GFP_KERNEL);
 	dev->private = kzalloc(size, GFP_KERNEL);
 	if (!dev->private)
 	if (!dev->private)
@@ -452,17 +441,17 @@ static inline int alloc_private(comedi_device *dev, int size)
 	return 0;
 	return 0;
 }
 }
 
 
-static inline unsigned int bytes_per_sample(const comedi_subdevice *subd)
+static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd)
 {
 {
 	if (subd->subdev_flags & SDF_LSAMPL)
 	if (subd->subdev_flags & SDF_LSAMPL)
-		return sizeof(lsampl_t);
+		return sizeof(unsigned int);
 	else
 	else
-		return sizeof(sampl_t);
+		return sizeof(short);
 }
 }
 
 
 /* must be used in attach to set dev->hw_dev if you wish to dma directly
 /* must be used in attach to set dev->hw_dev if you wish to dma directly
 into comedi's buffer */
 into comedi's buffer */
-static inline void comedi_set_hw_dev(comedi_device *dev, struct device *hw_dev)
+static inline void comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
 {
 {
 	if (dev->hw_dev)
 	if (dev->hw_dev)
 		put_device(dev->hw_dev);
 		put_device(dev->hw_dev);
@@ -474,31 +463,31 @@ static inline void comedi_set_hw_dev(comedi_device *dev, struct device *hw_dev)
 	}
 	}
 }
 }
 
 
-int comedi_buf_put(comedi_async *async, sampl_t x);
-int comedi_buf_get(comedi_async *async, sampl_t *x);
+int comedi_buf_put(struct comedi_async *async, short x);
+int comedi_buf_get(struct comedi_async *async, short *x);
 
 
-unsigned int comedi_buf_write_n_available(comedi_async *async);
-unsigned int comedi_buf_write_alloc(comedi_async *async, unsigned int nbytes);
-unsigned int comedi_buf_write_alloc_strict(comedi_async *async,
+unsigned int comedi_buf_write_n_available(struct comedi_async *async);
+unsigned int comedi_buf_write_alloc(struct comedi_async *async, unsigned int nbytes);
+unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async,
 	unsigned int nbytes);
 	unsigned int nbytes);
-unsigned comedi_buf_write_free(comedi_async *async, unsigned int nbytes);
-unsigned comedi_buf_read_alloc(comedi_async *async, unsigned nbytes);
-unsigned comedi_buf_read_free(comedi_async *async, unsigned int nbytes);
-unsigned int comedi_buf_read_n_available(comedi_async *async);
-void comedi_buf_memcpy_to(comedi_async *async, unsigned int offset,
+unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes);
+unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes);
+unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes);
+unsigned int comedi_buf_read_n_available(struct comedi_async *async);
+void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
 	const void *source, unsigned int num_bytes);
 	const void *source, unsigned int num_bytes);
-void comedi_buf_memcpy_from(comedi_async *async, unsigned int offset,
+void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
 	void *destination, unsigned int num_bytes);
 	void *destination, unsigned int num_bytes);
-static inline unsigned comedi_buf_write_n_allocated(comedi_async *async)
+static inline unsigned comedi_buf_write_n_allocated(struct comedi_async *async)
 {
 {
 	return async->buf_write_alloc_count - async->buf_write_count;
 	return async->buf_write_alloc_count - async->buf_write_count;
 }
 }
-static inline unsigned comedi_buf_read_n_allocated(comedi_async *async)
+static inline unsigned comedi_buf_read_n_allocated(struct comedi_async *async)
 {
 {
 	return async->buf_read_alloc_count - async->buf_read_count;
 	return async->buf_read_alloc_count - async->buf_read_count;
 }
 }
 
 
-void comedi_reset_async_buf(comedi_async *async);
+void comedi_reset_async_buf(struct comedi_async *async);
 
 
 static inline void *comedi_aux_data(int options[], int n)
 static inline void *comedi_aux_data(int options[], int n)
 {
 {
@@ -527,10 +516,13 @@ static inline void *comedi_aux_data(int options[], int n)
 
 
 int comedi_alloc_board_minor(struct device *hardware_device);
 int comedi_alloc_board_minor(struct device *hardware_device);
 void comedi_free_board_minor(unsigned minor);
 void comedi_free_board_minor(unsigned minor);
-int comedi_alloc_subdevice_minor(comedi_device *dev, comedi_subdevice *s);
-void comedi_free_subdevice_minor(comedi_subdevice *s);
+int comedi_alloc_subdevice_minor(struct comedi_device *dev, struct comedi_subdevice *s);
+void comedi_free_subdevice_minor(struct comedi_subdevice *s);
 int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name);
 int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name);
 void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
 void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
+struct usb_device;	/* forward declaration */
+int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name);
+void comedi_usb_auto_unconfig(struct usb_device *usbdev);
 
 
 #include "comedi_rt.h"
 #include "comedi_rt.h"
 
 

+ 56 - 58
drivers/staging/comedi/comedilib.h

@@ -36,18 +36,16 @@
 
 
 #ifndef KCOMEDILIB_DEPRECATED
 #ifndef KCOMEDILIB_DEPRECATED
 
 
-typedef void comedi_t;
-
 /* these functions may not be called at real-time priority */
 /* these functions may not be called at real-time priority */
 
 
-comedi_t *comedi_open(const char *path);
-int comedi_close(comedi_t *dev);
+void *comedi_open(const char *path);
+int comedi_close(void *dev);
 
 
 /* these functions may be called at any priority, but may fail at
 /* these functions may be called at any priority, but may fail at
    real-time priority */
    real-time priority */
 
 
-int comedi_lock(comedi_t *dev, unsigned int subdev);
-int comedi_unlock(comedi_t *dev, unsigned int subdev);
+int comedi_lock(void *dev, unsigned int subdev);
+int comedi_unlock(void *dev, unsigned int subdev);
 
 
 /* these functions may be called at any priority, but you must hold
 /* these functions may be called at any priority, but you must hold
    the lock for the subdevice */
    the lock for the subdevice */
@@ -56,68 +54,68 @@ int comedi_loglevel(int loglevel);
 void comedi_perror(const char *s);
 void comedi_perror(const char *s);
 char *comedi_strerror(int errnum);
 char *comedi_strerror(int errnum);
 int comedi_errno(void);
 int comedi_errno(void);
-int comedi_fileno(comedi_t *dev);
+int comedi_fileno(void *dev);
 
 
-int comedi_cancel(comedi_t *dev, unsigned int subdev);
-int comedi_register_callback(comedi_t *dev, unsigned int subdev,
+int comedi_cancel(void *dev, unsigned int subdev);
+int comedi_register_callback(void *dev, unsigned int subdev,
 	unsigned int mask, int (*cb) (unsigned int, void *), void *arg);
 	unsigned int mask, int (*cb) (unsigned int, void *), void *arg);
 
 
-int comedi_command(comedi_t *dev, comedi_cmd *cmd);
-int comedi_command_test(comedi_t *dev, comedi_cmd *cmd);
-int comedi_trigger(comedi_t *dev, unsigned int subdev, comedi_trig *it);
-int __comedi_trigger(comedi_t *dev, unsigned int subdev, comedi_trig *it);
-int comedi_data_write(comedi_t *dev, unsigned int subdev, unsigned int chan,
-	unsigned int range, unsigned int aref, lsampl_t data);
-int comedi_data_read(comedi_t *dev, unsigned int subdev, unsigned int chan,
-	unsigned int range, unsigned int aref, lsampl_t *data);
-int comedi_data_read_hint(comedi_t *dev, unsigned int subdev,
+int comedi_command(void *dev, struct comedi_cmd *cmd);
+int comedi_command_test(void *dev, struct comedi_cmd *cmd);
+int comedi_trigger(void *dev, unsigned int subdev, struct comedi_trig *it);
+int __comedi_trigger(void *dev, unsigned int subdev, struct comedi_trig *it);
+int comedi_data_write(void *dev, unsigned int subdev, unsigned int chan,
+	unsigned int range, unsigned int aref, unsigned int data);
+int comedi_data_read(void *dev, unsigned int subdev, unsigned int chan,
+	unsigned int range, unsigned int aref, unsigned int *data);
+int comedi_data_read_hint(void *dev, unsigned int subdev,
 	unsigned int chan, unsigned int range, unsigned int aref);
 	unsigned int chan, unsigned int range, unsigned int aref);
-int comedi_data_read_delayed(comedi_t *dev, unsigned int subdev,
+int comedi_data_read_delayed(void *dev, unsigned int subdev,
 	unsigned int chan, unsigned int range, unsigned int aref,
 	unsigned int chan, unsigned int range, unsigned int aref,
-	lsampl_t *data, unsigned int nano_sec);
-int comedi_dio_config(comedi_t *dev, unsigned int subdev, unsigned int chan,
+	unsigned int *data, unsigned int nano_sec);
+int comedi_dio_config(void *dev, unsigned int subdev, unsigned int chan,
 	unsigned int io);
 	unsigned int io);
-int comedi_dio_read(comedi_t *dev, unsigned int subdev, unsigned int chan,
+int comedi_dio_read(void *dev, unsigned int subdev, unsigned int chan,
 	unsigned int *val);
 	unsigned int *val);
-int comedi_dio_write(comedi_t *dev, unsigned int subdev, unsigned int chan,
+int comedi_dio_write(void *dev, unsigned int subdev, unsigned int chan,
 	unsigned int val);
 	unsigned int val);
-int comedi_dio_bitfield(comedi_t *dev, unsigned int subdev, unsigned int mask,
+int comedi_dio_bitfield(void *dev, unsigned int subdev, unsigned int mask,
 	unsigned int *bits);
 	unsigned int *bits);
-int comedi_get_n_subdevices(comedi_t *dev);
-int comedi_get_version_code(comedi_t *dev);
-const char *comedi_get_driver_name(comedi_t *dev);
-const char *comedi_get_board_name(comedi_t *dev);
-int comedi_get_subdevice_type(comedi_t *dev, unsigned int subdevice);
-int comedi_find_subdevice_by_type(comedi_t *dev, int type, unsigned int subd);
-int comedi_get_n_channels(comedi_t *dev, unsigned int subdevice);
-lsampl_t comedi_get_maxdata(comedi_t *dev, unsigned int subdevice, unsigned
+int comedi_get_n_subdevices(void *dev);
+int comedi_get_version_code(void *dev);
+const char *comedi_get_driver_name(void *dev);
+const char *comedi_get_board_name(void *dev);
+int comedi_get_subdevice_type(void *dev, unsigned int subdevice);
+int comedi_find_subdevice_by_type(void *dev, int type, unsigned int subd);
+int comedi_get_n_channels(void *dev, unsigned int subdevice);
+unsigned int comedi_get_maxdata(void *dev, unsigned int subdevice, unsigned
 	int chan);
 	int chan);
-int comedi_get_n_ranges(comedi_t *dev, unsigned int subdevice, unsigned int
+int comedi_get_n_ranges(void *dev, unsigned int subdevice, unsigned int
 	chan);
 	chan);
-int comedi_do_insn(comedi_t *dev, comedi_insn *insn);
-int comedi_poll(comedi_t *dev, unsigned int subdev);
+int comedi_do_insn(void *dev, struct comedi_insn *insn);
+int comedi_poll(void *dev, unsigned int subdev);
 
 
 /* DEPRECATED functions */
 /* DEPRECATED functions */
-int comedi_get_rangetype(comedi_t *dev, unsigned int subdevice,
+int comedi_get_rangetype(void *dev, unsigned int subdevice,
 	unsigned int chan);
 	unsigned int chan);
 
 
 /* ALPHA functions */
 /* ALPHA functions */
-unsigned int comedi_get_subdevice_flags(comedi_t *dev, unsigned int subdevice);
-int comedi_get_len_chanlist(comedi_t *dev, unsigned int subdevice);
-int comedi_get_krange(comedi_t *dev, unsigned int subdevice, unsigned int
-	chan, unsigned int range, comedi_krange *krange);
-unsigned int comedi_get_buf_head_pos(comedi_t *dev, unsigned int subdevice);
-int comedi_set_user_int_count(comedi_t *dev, unsigned int subdevice,
+unsigned int comedi_get_subdevice_flags(void *dev, unsigned int subdevice);
+int comedi_get_len_chanlist(void *dev, unsigned int subdevice);
+int comedi_get_krange(void *dev, unsigned int subdevice, unsigned int
+	chan, unsigned int range, struct comedi_krange *krange);
+unsigned int comedi_get_buf_head_pos(void *dev, unsigned int subdevice);
+int comedi_set_user_int_count(void *dev, unsigned int subdevice,
 	unsigned int buf_user_count);
 	unsigned int buf_user_count);
-int comedi_map(comedi_t *dev, unsigned int subdev, void *ptr);
-int comedi_unmap(comedi_t *dev, unsigned int subdev);
-int comedi_get_buffer_size(comedi_t *dev, unsigned int subdev);
-int comedi_mark_buffer_read(comedi_t *dev, unsigned int subdevice,
+int comedi_map(void *dev, unsigned int subdev, void *ptr);
+int comedi_unmap(void *dev, unsigned int subdev);
+int comedi_get_buffer_size(void *dev, unsigned int subdev);
+int comedi_mark_buffer_read(void *dev, unsigned int subdevice,
 	unsigned int num_bytes);
 	unsigned int num_bytes);
-int comedi_mark_buffer_written(comedi_t *d, unsigned int subdevice,
+int comedi_mark_buffer_written(void *d, unsigned int subdevice,
 	unsigned int num_bytes);
 	unsigned int num_bytes);
-int comedi_get_buffer_contents(comedi_t *dev, unsigned int subdevice);
-int comedi_get_buffer_offset(comedi_t *dev, unsigned int subdevice);
+int comedi_get_buffer_contents(void *dev, unsigned int subdevice);
+int comedi_get_buffer_offset(void *dev, unsigned int subdevice);
 
 
 #else
 #else
 
 
@@ -139,14 +137,14 @@ int comedi_cancel(unsigned int minor, unsigned int subdev);
 int comedi_register_callback(unsigned int minor, unsigned int subdev,
 int comedi_register_callback(unsigned int minor, unsigned int subdev,
 	unsigned int mask, int (*cb) (unsigned int, void *), void *arg);
 	unsigned int mask, int (*cb) (unsigned int, void *), void *arg);
 
 
-int comedi_command(unsigned int minor, comedi_cmd *cmd);
-int comedi_command_test(unsigned int minor, comedi_cmd *cmd);
-int comedi_trigger(unsigned int minor, unsigned int subdev, comedi_trig *it);
-int __comedi_trigger(unsigned int minor, unsigned int subdev, comedi_trig *it);
+int comedi_command(unsigned int minor, struct comedi_cmd *cmd);
+int comedi_command_test(unsigned int minor, struct comedi_cmd *cmd);
+int comedi_trigger(unsigned int minor, unsigned int subdev, struct comedi_trig *it);
+int __comedi_trigger(unsigned int minor, unsigned int subdev, struct comedi_trig *it);
 int comedi_data_write(unsigned int dev, unsigned int subdev, unsigned int chan,
 int comedi_data_write(unsigned int dev, unsigned int subdev, unsigned int chan,
-	unsigned int range, unsigned int aref, lsampl_t data);
+	unsigned int range, unsigned int aref, unsigned int data);
 int comedi_data_read(unsigned int dev, unsigned int subdev, unsigned int chan,
 int comedi_data_read(unsigned int dev, unsigned int subdev, unsigned int chan,
-	unsigned int range, unsigned int aref, lsampl_t *data);
+	unsigned int range, unsigned int aref, unsigned int *data);
 int comedi_dio_config(unsigned int dev, unsigned int subdev, unsigned int chan,
 int comedi_dio_config(unsigned int dev, unsigned int subdev, unsigned int chan,
 	unsigned int io);
 	unsigned int io);
 int comedi_dio_read(unsigned int dev, unsigned int subdev, unsigned int chan,
 int comedi_dio_read(unsigned int dev, unsigned int subdev, unsigned int chan,
@@ -163,11 +161,11 @@ int comedi_get_subdevice_type(unsigned int minor, unsigned int subdevice);
 int comedi_find_subdevice_by_type(unsigned int minor, int type,
 int comedi_find_subdevice_by_type(unsigned int minor, int type,
 	unsigned int subd);
 	unsigned int subd);
 int comedi_get_n_channels(unsigned int minor, unsigned int subdevice);
 int comedi_get_n_channels(unsigned int minor, unsigned int subdevice);
-lsampl_t comedi_get_maxdata(unsigned int minor, unsigned int subdevice, unsigned
+unsigned int comedi_get_maxdata(unsigned int minor, unsigned int subdevice, unsigned
 	int chan);
 	int chan);
 int comedi_get_n_ranges(unsigned int minor, unsigned int subdevice, unsigned int
 int comedi_get_n_ranges(unsigned int minor, unsigned int subdevice, unsigned int
 	chan);
 	chan);
-int comedi_do_insn(unsigned int minor, comedi_insn *insn);
+int comedi_do_insn(unsigned int minor, struct comedi_insn *insn);
 int comedi_poll(unsigned int minor, unsigned int subdev);
 int comedi_poll(unsigned int minor, unsigned int subdev);
 
 
 /* DEPRECATED functions */
 /* DEPRECATED functions */
@@ -179,7 +177,7 @@ unsigned int comedi_get_subdevice_flags(unsigned int minor, unsigned int
 	subdevice);
 	subdevice);
 int comedi_get_len_chanlist(unsigned int minor, unsigned int subdevice);
 int comedi_get_len_chanlist(unsigned int minor, unsigned int subdevice);
 int comedi_get_krange(unsigned int minor, unsigned int subdevice, unsigned int
 int comedi_get_krange(unsigned int minor, unsigned int subdevice, unsigned int
-	chan, unsigned int range, comedi_krange *krange);
+	chan, unsigned int range, struct comedi_krange *krange);
 unsigned int comedi_get_buf_head_pos(unsigned int minor, unsigned int
 unsigned int comedi_get_buf_head_pos(unsigned int minor, unsigned int
 	subdevice);
 	subdevice);
 int comedi_set_user_int_count(unsigned int minor, unsigned int subdevice,
 int comedi_set_user_int_count(unsigned int minor, unsigned int subdevice,

+ 108 - 79
drivers/staging/comedi/drivers.c

@@ -28,6 +28,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
+#include <linux/usb.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
@@ -46,26 +47,26 @@
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/system.h>
 
 
-static int postconfig(comedi_device * dev);
-static int insn_rw_emulate_bits(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data);
-static void *comedi_recognize(comedi_driver * driv, const char *name);
-static void comedi_report_boards(comedi_driver * driv);
-static int poll_invalid(comedi_device * dev, comedi_subdevice * s);
-int comedi_buf_alloc(comedi_device * dev, comedi_subdevice * s,
+static int postconfig(struct comedi_device *dev);
+static int insn_rw_emulate_bits(struct comedi_device *dev, struct comedi_subdevice *s,
+	struct comedi_insn *insn, unsigned int *data);
+static void *comedi_recognize(struct comedi_driver * driv, const char *name);
+static void comedi_report_boards(struct comedi_driver *driv);
+static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s);
+int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
 	unsigned long new_size);
 	unsigned long new_size);
 
 
-comedi_driver *comedi_drivers;
+struct comedi_driver *comedi_drivers;
 
 
 int comedi_modprobe(int minor)
 int comedi_modprobe(int minor)
 {
 {
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static void cleanup_device(comedi_device * dev)
+static void cleanup_device(struct comedi_device *dev)
 {
 {
 	int i;
 	int i;
-	comedi_subdevice *s;
+	struct comedi_subdevice *s;
 
 
 	if (dev->subdevices) {
 	if (dev->subdevices) {
 		for (i = 0; i < dev->n_subdevices; i++) {
 		for (i = 0; i < dev->n_subdevices; i++) {
@@ -80,10 +81,8 @@ static void cleanup_device(comedi_device * dev)
 		dev->subdevices = NULL;
 		dev->subdevices = NULL;
 		dev->n_subdevices = 0;
 		dev->n_subdevices = 0;
 	}
 	}
-	if (dev->private) {
-		kfree(dev->private);
-		dev->private = NULL;
-	}
+	kfree(dev->private);
+	dev->private = NULL;
 	dev->driver = 0;
 	dev->driver = 0;
 	dev->board_name = NULL;
 	dev->board_name = NULL;
 	dev->board_ptr = NULL;
 	dev->board_ptr = NULL;
@@ -96,7 +95,7 @@ static void cleanup_device(comedi_device * dev)
 	comedi_set_hw_dev(dev, NULL);
 	comedi_set_hw_dev(dev, NULL);
 }
 }
 
 
-static void __comedi_device_detach(comedi_device * dev)
+static void __comedi_device_detach(struct comedi_device *dev)
 {
 {
 	dev->attached = 0;
 	dev->attached = 0;
 	if (dev->driver) {
 	if (dev->driver) {
@@ -107,16 +106,16 @@ static void __comedi_device_detach(comedi_device * dev)
 	cleanup_device(dev);
 	cleanup_device(dev);
 }
 }
 
 
-void comedi_device_detach(comedi_device * dev)
+void comedi_device_detach(struct comedi_device *dev)
 {
 {
 	if (!dev->attached)
 	if (!dev->attached)
 		return;
 		return;
 	__comedi_device_detach(dev);
 	__comedi_device_detach(dev);
 }
 }
 
 
-int comedi_device_attach(comedi_device * dev, comedi_devconfig * it)
+int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 {
-	comedi_driver *driv;
+	struct comedi_driver *driv;
 	int ret;
 	int ret;
 
 
 	if (dev->attached)
 	if (dev->attached)
@@ -139,7 +138,7 @@ int comedi_device_attach(comedi_device * dev, comedi_devconfig * it)
 				continue;
 				continue;
 			}
 			}
 		}
 		}
-		//initialize dev->driver here so comedi_error() can be called from attach
+		/* initialize dev->driver here so comedi_error() can be called from attach */
 		dev->driver = driv;
 		dev->driver = driv;
 		ret = driv->attach(dev, it);
 		ret = driv->attach(dev, it);
 		if (ret < 0) {
 		if (ret < 0) {
@@ -150,8 +149,8 @@ int comedi_device_attach(comedi_device * dev, comedi_devconfig * it)
 		goto attached;
 		goto attached;
 	}
 	}
 
 
-	// recognize has failed if we get here
-	// report valid board names before returning error
+	/*  recognize has failed if we get here */
+	/*  report valid board names before returning error */
 	for (driv = comedi_drivers; driv; driv = driv->next) {
 	for (driv = comedi_drivers; driv; driv = driv->next) {
 		if (!try_module_get(driv->module)) {
 		if (!try_module_get(driv->module)) {
 			printk("comedi: failed to increment module count\n");
 			printk("comedi: failed to increment module count\n");
@@ -181,7 +180,7 @@ attached:
 	return 0;
 	return 0;
 }
 }
 
 
-int comedi_driver_register(comedi_driver * driver)
+int comedi_driver_register(struct comedi_driver *driver)
 {
 {
 	driver->next = comedi_drivers;
 	driver->next = comedi_drivers;
 	comedi_drivers = driver;
 	comedi_drivers = driver;
@@ -189,15 +188,15 @@ int comedi_driver_register(comedi_driver * driver)
 	return 0;
 	return 0;
 }
 }
 
 
-int comedi_driver_unregister(comedi_driver * driver)
+int comedi_driver_unregister(struct comedi_driver *driver)
 {
 {
-	comedi_driver *prev;
+	struct comedi_driver *prev;
 	int i;
 	int i;
 
 
 	/* check for devices using this driver */
 	/* check for devices using this driver */
 	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
 	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
 		struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(i);
 		struct comedi_device_file_info *dev_file_info = comedi_get_device_file_info(i);
-		comedi_device *dev;
+		struct comedi_device *dev;
 
 
 		if(dev_file_info == NULL) continue;
 		if(dev_file_info == NULL) continue;
 		dev = dev_file_info->device;
 		dev = dev_file_info->device;
@@ -225,11 +224,11 @@ int comedi_driver_unregister(comedi_driver * driver)
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static int postconfig(comedi_device * dev)
+static int postconfig(struct comedi_device *dev)
 {
 {
 	int i;
 	int i;
-	comedi_subdevice *s;
-	comedi_async *async = NULL;
+	struct comedi_subdevice *s;
+	struct comedi_async *async = NULL;
 	int ret;
 	int ret;
 
 
 	for (i = 0; i < dev->n_subdevices; i++) {
 	for (i = 0; i < dev->n_subdevices; i++) {
@@ -246,7 +245,7 @@ static int postconfig(comedi_device * dev)
 				SDF_CMD_WRITE)) == 0);
 				SDF_CMD_WRITE)) == 0);
 			BUG_ON(!s->do_cmdtest);
 			BUG_ON(!s->do_cmdtest);
 
 
-			async = kzalloc(sizeof(comedi_async), GFP_KERNEL);
+			async = kzalloc(sizeof(struct comedi_async), GFP_KERNEL);
 			if (async == NULL) {
 			if (async == NULL) {
 				printk("failed to allocate async struct\n");
 				printk("failed to allocate async struct\n");
 				return -ENOMEM;
 				return -ENOMEM;
@@ -298,8 +297,8 @@ static int postconfig(comedi_device * dev)
 	return 0;
 	return 0;
 }
 }
 
 
-// generic recognize function for drivers that register their supported board names
-void *comedi_recognize(comedi_driver * driv, const char *name)
+/*  generic recognize function for drivers that register their supported board names */
+void *comedi_recognize(struct comedi_driver * driv, const char *name)
 {
 {
 	unsigned i;
 	unsigned i;
 	const char *const *name_ptr = driv->board_name;
 	const char *const *name_ptr = driv->board_name;
@@ -314,7 +313,7 @@ void *comedi_recognize(comedi_driver * driv, const char *name)
 	return NULL;
 	return NULL;
 }
 }
 
 
-void comedi_report_boards(comedi_driver * driv)
+void comedi_report_boards(struct comedi_driver *driv)
 {
 {
 	unsigned int i;
 	unsigned int i;
 	const char *const *name_ptr;
 	const char *const *name_ptr;
@@ -332,28 +331,28 @@ void comedi_report_boards(comedi_driver * driv)
 		printk(" %s\n", driv->driver_name);
 		printk(" %s\n", driv->driver_name);
 }
 }
 
 
-static int poll_invalid(comedi_device * dev, comedi_subdevice * s)
+static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
 {
 {
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-int insn_inval(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
+int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
+	struct comedi_insn *insn, unsigned int *data)
 {
 {
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
-static int insn_rw_emulate_bits(comedi_device * dev, comedi_subdevice * s,
-	comedi_insn * insn, lsampl_t * data)
+static int insn_rw_emulate_bits(struct comedi_device *dev, struct comedi_subdevice *s,
+	struct comedi_insn *insn, unsigned int *data)
 {
 {
-	comedi_insn new_insn;
+	struct comedi_insn new_insn;
 	int ret;
 	int ret;
 	static const unsigned channels_per_bitfield = 32;
 	static const unsigned channels_per_bitfield = 32;
 
 
 	unsigned chan = CR_CHAN(insn->chanspec);
 	unsigned chan = CR_CHAN(insn->chanspec);
 	const unsigned base_bitfield_channel =
 	const unsigned base_bitfield_channel =
 		(chan < channels_per_bitfield) ? 0 : chan;
 		(chan < channels_per_bitfield) ? 0 : chan;
-	lsampl_t new_data[2];
+	unsigned int new_data[2];
 	memset(new_data, 0, sizeof(new_data));
 	memset(new_data, 0, sizeof(new_data));
 	memset(&new_insn, 0, sizeof(new_insn));
 	memset(&new_insn, 0, sizeof(new_insn));
 	new_insn.insn = INSN_BITS;
 	new_insn.insn = INSN_BITS;
@@ -380,7 +379,7 @@ static int insn_rw_emulate_bits(comedi_device * dev, comedi_subdevice * s,
 	return 1;
 	return 1;
 }
 }
 
 
-static inline unsigned long uvirt_to_kva(pgd_t * pgd, unsigned long adr)
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
 {
 {
 	unsigned long ret = 0UL;
 	unsigned long ret = 0UL;
 	pmd_t *pmd;
 	pmd_t *pmd;
@@ -413,10 +412,10 @@ static inline unsigned long kvirt_to_kva(unsigned long adr)
 	return kva;
 	return kva;
 }
 }
 
 
-int comedi_buf_alloc(comedi_device * dev, comedi_subdevice * s,
+int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
 	unsigned long new_size)
 	unsigned long new_size)
 {
 {
-	comedi_async *async = s->async;
+	struct comedi_async *async = s->async;
 
 
 	/* Round up new_size to multiple of PAGE_SIZE */
 	/* Round up new_size to multiple of PAGE_SIZE */
 	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
 	new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
@@ -425,7 +424,7 @@ int comedi_buf_alloc(comedi_device * dev, comedi_subdevice * s,
 	if (async->prealloc_buf && async->prealloc_bufsz == new_size) {
 	if (async->prealloc_buf && async->prealloc_bufsz == new_size) {
 		return 0;
 		return 0;
 	}
 	}
-	// deallocate old buffer
+	/*  deallocate old buffer */
 	if (async->prealloc_buf) {
 	if (async->prealloc_buf) {
 		vunmap(async->prealloc_buf);
 		vunmap(async->prealloc_buf);
 		async->prealloc_buf = NULL;
 		async->prealloc_buf = NULL;
@@ -454,7 +453,7 @@ int comedi_buf_alloc(comedi_device * dev, comedi_subdevice * s,
 		async->buf_page_list = NULL;
 		async->buf_page_list = NULL;
 		async->n_buf_pages = 0;
 		async->n_buf_pages = 0;
 	}
 	}
-	// allocate new buffer
+	/*  allocate new buffer */
 	if (new_size) {
 	if (new_size) {
 		unsigned i = 0;
 		unsigned i = 0;
 		unsigned n_pages = new_size >> PAGE_SHIFT;
 		unsigned n_pages = new_size >> PAGE_SHIFT;
@@ -537,16 +536,15 @@ int comedi_buf_alloc(comedi_device * dev, comedi_subdevice * s,
 
 
 /* munging is applied to data by core as it passes between user
 /* munging is applied to data by core as it passes between user
  * and kernel space */
  * and kernel space */
-unsigned int comedi_buf_munge(comedi_async * async, unsigned int num_bytes)
+unsigned int comedi_buf_munge(struct comedi_async *async, unsigned int num_bytes)
 {
 {
-	comedi_subdevice *s = async->subdevice;
+	struct comedi_subdevice *s = async->subdevice;
 	unsigned int count = 0;
 	unsigned int count = 0;
 	const unsigned num_sample_bytes = bytes_per_sample(s);
 	const unsigned num_sample_bytes = bytes_per_sample(s);
 
 
 	if (s->munge == NULL || (async->cmd.flags & CMDF_RAWDATA)) {
 	if (s->munge == NULL || (async->cmd.flags & CMDF_RAWDATA)) {
 		async->munge_count += num_bytes;
 		async->munge_count += num_bytes;
-		if ((int)(async->munge_count - async->buf_write_count) > 0)
-			BUG();
+		BUG_ON((int)(async->munge_count - async->buf_write_count) > 0);
 		return num_bytes;
 		return num_bytes;
 	}
 	}
 	/* don't munge partial samples */
 	/* don't munge partial samples */
@@ -567,7 +565,7 @@ unsigned int comedi_buf_munge(comedi_async * async, unsigned int num_bytes)
 		s->munge(s->device, s, async->prealloc_buf + async->munge_ptr,
 		s->munge(s->device, s, async->prealloc_buf + async->munge_ptr,
 			block_size, async->munge_chan);
 			block_size, async->munge_chan);
 
 
-		smp_wmb();	//barrier insures data is munged in buffer before munge_count is incremented
+		smp_wmb();	/* barrier insures data is munged in buffer before munge_count is incremented */
 
 
 		async->munge_chan += block_size / num_sample_bytes;
 		async->munge_chan += block_size / num_sample_bytes;
 		async->munge_chan %= async->cmd.chanlist_len;
 		async->munge_chan %= async->cmd.chanlist_len;
@@ -576,12 +574,11 @@ unsigned int comedi_buf_munge(comedi_async * async, unsigned int num_bytes)
 		async->munge_ptr %= async->prealloc_bufsz;
 		async->munge_ptr %= async->prealloc_bufsz;
 		count += block_size;
 		count += block_size;
 	}
 	}
-	if ((int)(async->munge_count - async->buf_write_count) > 0)
-		BUG();
+	BUG_ON((int)(async->munge_count - async->buf_write_count) > 0);
 	return count;
 	return count;
 }
 }
 
 
-unsigned int comedi_buf_write_n_available(comedi_async * async)
+unsigned int comedi_buf_write_n_available(struct comedi_async *async)
 {
 {
 	unsigned int free_end;
 	unsigned int free_end;
 	unsigned int nbytes;
 	unsigned int nbytes;
@@ -601,7 +598,7 @@ unsigned int comedi_buf_write_n_available(comedi_async * async)
 }
 }
 
 
 /* allocates chunk for the writer from free buffer space */
 /* allocates chunk for the writer from free buffer space */
-unsigned int comedi_buf_write_alloc(comedi_async * async, unsigned int nbytes)
+unsigned int comedi_buf_write_alloc(struct comedi_async *async, unsigned int nbytes)
 {
 {
 	unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
 	unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
 
 
@@ -616,7 +613,7 @@ unsigned int comedi_buf_write_alloc(comedi_async * async, unsigned int nbytes)
 }
 }
 
 
 /* allocates nothing unless it can completely fulfill the request */
 /* allocates nothing unless it can completely fulfill the request */
-unsigned int comedi_buf_write_alloc_strict(comedi_async * async,
+unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async,
 	unsigned int nbytes)
 	unsigned int nbytes)
 {
 {
 	unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
 	unsigned int free_end = async->buf_read_count + async->prealloc_bufsz;
@@ -632,7 +629,7 @@ unsigned int comedi_buf_write_alloc_strict(comedi_async * async,
 }
 }
 
 
 /* transfers a chunk from writer to filled buffer space */
 /* transfers a chunk from writer to filled buffer space */
-unsigned comedi_buf_write_free(comedi_async * async, unsigned int nbytes)
+unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes)
 {
 {
 	if ((int)(async->buf_write_count + nbytes -
 	if ((int)(async->buf_write_count + nbytes -
 			async->buf_write_alloc_count) > 0) {
 			async->buf_write_alloc_count) > 0) {
@@ -650,7 +647,7 @@ unsigned comedi_buf_write_free(comedi_async * async, unsigned int nbytes)
 }
 }
 
 
 /* allocates a chunk for the reader from filled (and munged) buffer space */
 /* allocates a chunk for the reader from filled (and munged) buffer space */
-unsigned comedi_buf_read_alloc(comedi_async * async, unsigned nbytes)
+unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes)
 {
 {
 	if ((int)(async->buf_read_alloc_count + nbytes - async->munge_count) >
 	if ((int)(async->buf_read_alloc_count + nbytes - async->munge_count) >
 		0) {
 		0) {
@@ -664,9 +661,9 @@ unsigned comedi_buf_read_alloc(comedi_async * async, unsigned nbytes)
 }
 }
 
 
 /* transfers control of a chunk from reader to free buffer space */
 /* transfers control of a chunk from reader to free buffer space */
-unsigned comedi_buf_read_free(comedi_async * async, unsigned int nbytes)
+unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes)
 {
 {
-	// barrier insures data has been read out of buffer before read count is incremented
+	/*  barrier insures data has been read out of buffer before read count is incremented */
 	smp_mb();
 	smp_mb();
 	if ((int)(async->buf_read_count + nbytes -
 	if ((int)(async->buf_read_count + nbytes -
 			async->buf_read_alloc_count) > 0) {
 			async->buf_read_alloc_count) > 0) {
@@ -680,7 +677,7 @@ unsigned comedi_buf_read_free(comedi_async * async, unsigned int nbytes)
 	return nbytes;
 	return nbytes;
 }
 }
 
 
-void comedi_buf_memcpy_to(comedi_async * async, unsigned int offset,
+void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
 	const void *data, unsigned int num_bytes)
 	const void *data, unsigned int num_bytes)
 {
 {
 	unsigned int write_ptr = async->buf_write_ptr + offset;
 	unsigned int write_ptr = async->buf_write_ptr + offset;
@@ -705,7 +702,7 @@ void comedi_buf_memcpy_to(comedi_async * async, unsigned int offset,
 	}
 	}
 }
 }
 
 
-void comedi_buf_memcpy_from(comedi_async * async, unsigned int offset,
+void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
 	void *dest, unsigned int nbytes)
 	void *dest, unsigned int nbytes)
 {
 {
 	void *src;
 	void *src;
@@ -731,7 +728,7 @@ void comedi_buf_memcpy_from(comedi_async * async, unsigned int offset,
 	}
 	}
 }
 }
 
 
-unsigned int comedi_buf_read_n_available(comedi_async * async)
+unsigned int comedi_buf_read_n_available(struct comedi_async *async)
 {
 {
 	unsigned num_bytes;
 	unsigned num_bytes;
 
 
@@ -746,32 +743,32 @@ unsigned int comedi_buf_read_n_available(comedi_async * async)
 	return num_bytes;
 	return num_bytes;
 }
 }
 
 
-int comedi_buf_get(comedi_async * async, sampl_t * x)
+int comedi_buf_get(struct comedi_async *async, short *x)
 {
 {
 	unsigned int n = comedi_buf_read_n_available(async);
 	unsigned int n = comedi_buf_read_n_available(async);
 
 
-	if (n < sizeof(sampl_t))
+	if (n < sizeof(short))
 		return 0;
 		return 0;
-	comedi_buf_read_alloc(async, sizeof(sampl_t));
-	*x = *(sampl_t *) (async->prealloc_buf + async->buf_read_ptr);
-	comedi_buf_read_free(async, sizeof(sampl_t));
+	comedi_buf_read_alloc(async, sizeof(short));
+	*x = *(short *) (async->prealloc_buf + async->buf_read_ptr);
+	comedi_buf_read_free(async, sizeof(short));
 	return 1;
 	return 1;
 }
 }
 
 
-int comedi_buf_put(comedi_async * async, sampl_t x)
+int comedi_buf_put(struct comedi_async *async, short x)
 {
 {
-	unsigned int n = comedi_buf_write_alloc_strict(async, sizeof(sampl_t));
+	unsigned int n = comedi_buf_write_alloc_strict(async, sizeof(short));
 
 
-	if (n < sizeof(sampl_t)) {
+	if (n < sizeof(short)) {
 		async->events |= COMEDI_CB_ERROR;
 		async->events |= COMEDI_CB_ERROR;
 		return 0;
 		return 0;
 	}
 	}
-	*(sampl_t *) (async->prealloc_buf + async->buf_write_ptr) = x;
-	comedi_buf_write_free(async, sizeof(sampl_t));
+	*(short *) (async->prealloc_buf + async->buf_write_ptr) = x;
+	comedi_buf_write_free(async, sizeof(short));
 	return 1;
 	return 1;
 }
 }
 
 
-void comedi_reset_async_buf(comedi_async * async)
+void comedi_reset_async_buf(struct comedi_async *async)
 {
 {
 	async->buf_write_alloc_count = 0;
 	async->buf_write_alloc_count = 0;
 	async->buf_write_count = 0;
 	async->buf_write_count = 0;
@@ -792,14 +789,27 @@ void comedi_reset_async_buf(comedi_async * async)
 
 
 int comedi_auto_config(struct device *hardware_device, const char *board_name, const int *options, unsigned num_options)
 int comedi_auto_config(struct device *hardware_device, const char *board_name, const int *options, unsigned num_options)
 {
 {
-	comedi_devconfig it;
+	struct comedi_devconfig it;
 	int minor;
 	int minor;
 	struct comedi_device_file_info *dev_file_info;
 	struct comedi_device_file_info *dev_file_info;
 	int retval;
 	int retval;
+	unsigned *private_data = NULL;
+
+	if (!comedi_autoconfig) {
+		dev_set_drvdata(hardware_device, NULL);
+		return 0;
+	}
 
 
 	minor = comedi_alloc_board_minor(hardware_device);
 	minor = comedi_alloc_board_minor(hardware_device);
 	if(minor < 0) return minor;
 	if(minor < 0) return minor;
-	dev_set_drvdata(hardware_device, (void*)(unsigned long)minor);
+
+	private_data = kmalloc(sizeof(unsigned), GFP_KERNEL);
+	if (private_data == NULL) {
+		retval = -ENOMEM;
+		goto cleanup;
+	}
+	*private_data = minor;
+	dev_set_drvdata(hardware_device, private_data);
 
 
 	dev_file_info = comedi_get_device_file_info(minor);
 	dev_file_info = comedi_get_device_file_info(minor);
 
 
@@ -812,8 +822,11 @@ int comedi_auto_config(struct device *hardware_device, const char *board_name, c
 	mutex_lock(&dev_file_info->device->mutex);
 	mutex_lock(&dev_file_info->device->mutex);
 	retval = comedi_device_attach(dev_file_info->device, &it);
 	retval = comedi_device_attach(dev_file_info->device, &it);
 	mutex_unlock(&dev_file_info->device->mutex);
 	mutex_unlock(&dev_file_info->device->mutex);
+
+cleanup:
 	if(retval < 0)
 	if(retval < 0)
 	{
 	{
+		kfree(private_data);
 		comedi_free_board_minor(minor);
 		comedi_free_board_minor(minor);
 	}
 	}
 	return retval;
 	return retval;
@@ -821,20 +834,23 @@ int comedi_auto_config(struct device *hardware_device, const char *board_name, c
 
 
 void comedi_auto_unconfig(struct device *hardware_device)
 void comedi_auto_unconfig(struct device *hardware_device)
 {
 {
-	unsigned long minor = (unsigned long)dev_get_drvdata(hardware_device);
+	unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device);
+	if(minor == NULL) return;
 
 
-	BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+	BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS);
 
 
-	comedi_free_board_minor(minor);
+	comedi_free_board_minor(*minor);
+	dev_set_drvdata(hardware_device, NULL);
+	kfree(minor);
 }
 }
 
 
 int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
 int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
 {
 {
 	int options[2];
 	int options[2];
 
 
-	// pci bus
+	/*  pci bus */
 	options[0] = pcidev->bus->number;
 	options[0] = pcidev->bus->number;
-	// pci slot
+	/*  pci slot */
 	options[1] = PCI_SLOT(pcidev->devfn);
 	options[1] = PCI_SLOT(pcidev->devfn);
 
 
 	return comedi_auto_config(&pcidev->dev, board_name, options, sizeof(options) / sizeof(options[0]));
 	return comedi_auto_config(&pcidev->dev, board_name, options, sizeof(options) / sizeof(options[0]));
@@ -844,3 +860,16 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
 {
 {
 	comedi_auto_unconfig(&pcidev->dev);
 	comedi_auto_unconfig(&pcidev->dev);
 }
 }
+
+int comedi_usb_auto_config(struct usb_device *usbdev,
+	const char *board_name)
+{
+	BUG_ON(usbdev == NULL);
+	return comedi_auto_config(&usbdev->dev, board_name, NULL, 0);
+}
+
+void comedi_usb_auto_unconfig(struct usb_device *usbdev)
+{
+	BUG_ON(usbdev == NULL);
+	comedi_auto_unconfig(&usbdev->dev);
+}

+ 420 - 0
drivers/staging/comedi/drivers/8253.h

@@ -0,0 +1,420 @@
+/*
+    comedi/drivers/8253.h
+    Header file for 8253
+
+    COMEDI - Linux Control and Measurement Device Interface
+    Copyright (C) 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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _8253_H
+#define _8253_H
+
+#ifndef CMDTEST
+#include "../comedi.h"
+#else
+#include "../comedi.h"
+#endif
+
+#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div
+
+static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base,
+	unsigned int *d1, unsigned int *d2, unsigned int *nanosec,
+	int round_mode)
+{
+	int divider;
+	int div1, div2;
+	int div1_glb, div2_glb, ns_glb;
+	int div1_lub, div2_lub, ns_lub;
+	int ns;
+
+	divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base;
+
+	/* find 2 integers 1<={x,y}<=65536 such that x*y is
+	   close to divider */
+
+	div1_lub = div2_lub = 0;
+	div1_glb = div2_glb = 0;
+
+	ns_glb = 0;
+	ns_lub = 0xffffffff;
+
+	div2 = 0x10000;
+	for (div1 = divider / 65536 + 1; div1 < div2; div1++) {
+		div2 = divider / div1;
+
+		ns = i8253_osc_base * div1 * div2;
+		if (ns <= *nanosec && ns > ns_glb) {
+			ns_glb = ns;
+			div1_glb = div1;
+			div2_glb = div2;
+		}
+
+		div2++;
+		if (div2 <= 65536) {
+			ns = i8253_osc_base * div1 * div2;
+			if (ns > *nanosec && ns < ns_lub) {
+				ns_lub = ns;
+				div1_lub = div1;
+				div2_lub = div2;
+			}
+		}
+	}
+
+	*nanosec = div1_lub * div2_lub * i8253_osc_base;
+	*d1 = div1_lub & 0xffff;
+	*d2 = div2_lub & 0xffff;
+	return;
+}
+
+static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base,
+	unsigned int *d1, unsigned int *d2, unsigned int *nanosec,
+	int round_mode)
+{
+	int div1, div2;
+	int base;
+
+	for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) {
+		base = i8253_osc_base * div1;
+		round_mode &= TRIG_ROUND_MASK;
+		switch (round_mode) {
+		case TRIG_ROUND_NEAREST:
+		default:
+			div2 = (*nanosec + base / 2) / base;
+			break;
+		case TRIG_ROUND_DOWN:
+			div2 = (*nanosec) / base;
+			break;
+		case TRIG_ROUND_UP:
+			div2 = (*nanosec + base - 1) / base;
+			break;
+		}
+		if (div2 < 2)
+			div2 = 2;
+		if (div2 <= 65536) {
+			*nanosec = div2 * base;
+			*d1 = div1 & 0xffff;
+			*d2 = div2 & 0xffff;
+			return;
+		}
+	}
+
+	/* shouldn't get here */
+	div1 = 0x10000;
+	div2 = 0x10000;
+	*nanosec = div1 * div2 * i8253_osc_base;
+	*d1 = div1 & 0xffff;
+	*d2 = div2 & 0xffff;
+}
+
+static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base,
+	unsigned int *d1, unsigned int *d2, unsigned int *nanosec,
+	int round_mode)
+{
+	unsigned int divider;
+	unsigned int div1, div2;
+	unsigned int div1_glb, div2_glb, ns_glb;
+	unsigned int div1_lub, div2_lub, ns_lub;
+	unsigned int ns;
+	unsigned int start;
+	unsigned int ns_low, ns_high;
+	static const unsigned int max_count = 0x10000;
+	/* exit early if everything is already correct (this can save time
+	 * since this function may be called repeatedly during command tests
+	 * and execution) */
+	div1 = *d1 ? *d1 : max_count;
+	div2 = *d2 ? *d2 : max_count;
+	divider = div1 * div2;
+	if (div1 * div2 * i8253_osc_base == *nanosec &&
+		div1 > 1 && div1 <= max_count &&
+		div2 > 1 && div2 <= max_count &&
+		/* check for overflow */
+		divider > div1 && divider > div2 &&
+		divider * i8253_osc_base > divider &&
+		divider * i8253_osc_base > i8253_osc_base) {
+		return;
+	}
+
+	divider = *nanosec / i8253_osc_base;
+
+	div1_lub = div2_lub = 0;
+	div1_glb = div2_glb = 0;
+
+	ns_glb = 0;
+	ns_lub = 0xffffffff;
+
+	div2 = max_count;
+	start = divider / div2;
+	if (start < 2)
+		start = 2;
+	for (div1 = start; div1 <= divider / div1 + 1 && div1 <= max_count;
+		div1++) {
+		for (div2 = divider / div1;
+			div1 * div2 <= divider + div1 + 1 && div2 <= max_count;
+			div2++) {
+			ns = i8253_osc_base * div1 * div2;
+			if (ns <= *nanosec && ns > ns_glb) {
+				ns_glb = ns;
+				div1_glb = div1;
+				div2_glb = div2;
+			}
+			if (ns >= *nanosec && ns < ns_lub) {
+				ns_lub = ns;
+				div1_lub = div1;
+				div2_lub = div2;
+			}
+		}
+	}
+
+	round_mode &= TRIG_ROUND_MASK;
+	switch (round_mode) {
+	case TRIG_ROUND_NEAREST:
+	default:
+		ns_high = div1_lub * div2_lub * i8253_osc_base;
+		ns_low = div1_glb * div2_glb * i8253_osc_base;
+		if (ns_high - *nanosec < *nanosec - ns_low) {
+			div1 = div1_lub;
+			div2 = div2_lub;
+		} else {
+			div1 = div1_glb;
+			div2 = div2_glb;
+		}
+		break;
+	case TRIG_ROUND_UP:
+		div1 = div1_lub;
+		div2 = div2_lub;
+		break;
+	case TRIG_ROUND_DOWN:
+		div1 = div1_glb;
+		div2 = div2_glb;
+		break;
+	}
+
+	*nanosec = div1 * div2 * i8253_osc_base;
+	*d1 = div1 & 0xffff;	// masking is done since counter maps zero to 0x10000
+	*d2 = div2 & 0xffff;
+	return;
+}
+
+#ifndef CMDTEST
+/* i8254_load programs 8254 counter chip.  It should also work for the 8253.
+ * base_address is the lowest io address for the chip (the address of counter 0).
+ * counter_number is the counter you want to load (0,1 or 2)
+ * count is the number to load into the counter.
+ *
+ * You probably want to use mode 2.
+ *
+ * Use i8254_mm_load() if you board uses memory-mapped io, it is
+ * the same as i8254_load() except it uses writeb() instead of outb().
+ *
+ * Neither i8254_load() or i8254_read() do their loading/reading
+ * atomically.  The 16 bit read/writes are performed with two successive
+ * 8 bit read/writes.  So if two parts of your driver do a load/read on
+ * the same counter, it may be necessary to protect these functions
+ * with a spinlock.
+ *
+ * FMH
+ */
+
+#define i8254_control_reg	3
+
+static inline int i8254_load(unsigned long base_address, unsigned int regshift,
+	unsigned int counter_number, unsigned int count, unsigned int mode)
+{
+	unsigned int byte;
+
+	if (counter_number > 2)
+		return -1;
+	if (count > 0xffff)
+		return -1;
+	if (mode > 5)
+		return -1;
+	if ((mode == 2 || mode == 3) && count == 1)
+		return -1;
+
+	byte = counter_number << 6;
+	byte |= 0x30;		// load low then high byte
+	byte |= (mode << 1);	// set counter mode
+	outb(byte, base_address + (i8254_control_reg << regshift));
+	byte = count & 0xff;	// lsb of counter value
+	outb(byte, base_address + (counter_number << regshift));
+	byte = (count >> 8) & 0xff;	// msb of counter value
+	outb(byte, base_address + (counter_number << regshift));
+
+	return 0;
+}
+
+static inline int i8254_mm_load(void *base_address, unsigned int regshift,
+	unsigned int counter_number, unsigned int count, unsigned int mode)
+{
+	unsigned int byte;
+
+	if (counter_number > 2)
+		return -1;
+	if (count > 0xffff)
+		return -1;
+	if (mode > 5)
+		return -1;
+	if ((mode == 2 || mode == 3) && count == 1)
+		return -1;
+
+	byte = counter_number << 6;
+	byte |= 0x30;		// load low then high byte
+	byte |= (mode << 1);	// set counter mode
+	writeb(byte, base_address + (i8254_control_reg << regshift));
+	byte = count & 0xff;	// lsb of counter value
+	writeb(byte, base_address + (counter_number << regshift));
+	byte = (count >> 8) & 0xff;	// msb of counter value
+	writeb(byte, base_address + (counter_number << regshift));
+
+	return 0;
+}
+
+/* Returns 16 bit counter value, should work for 8253 also.*/
+static inline int i8254_read(unsigned long base_address, unsigned int regshift,
+	unsigned int counter_number)
+{
+	unsigned int byte;
+	int ret;
+
+	if (counter_number > 2)
+		return -1;
+
+	// latch counter
+	byte = counter_number << 6;
+	outb(byte, base_address + (i8254_control_reg << regshift));
+
+	// read lsb
+	ret = inb(base_address + (counter_number << regshift));
+	// read msb
+	ret += inb(base_address + (counter_number << regshift)) << 8;
+
+	return ret;
+}
+
+static inline int i8254_mm_read(void *base_address, unsigned int regshift,
+	unsigned int counter_number)
+{
+	unsigned int byte;
+	int ret;
+
+	if (counter_number > 2)
+		return -1;
+
+	// latch counter
+	byte = counter_number << 6;
+	writeb(byte, base_address + (i8254_control_reg << regshift));
+
+	// read lsb
+	ret = readb(base_address + (counter_number << regshift));
+	// read msb
+	ret += readb(base_address + (counter_number << regshift)) << 8;
+
+	return ret;
+}
+
+/* Loads 16 bit initial counter value, should work for 8253 also. */
+static inline void i8254_write(unsigned long base_address,
+	unsigned int regshift, unsigned int counter_number, unsigned int count)
+{
+	unsigned int byte;
+
+	if (counter_number > 2)
+		return;
+
+	byte = count & 0xff;	// lsb of counter value
+	outb(byte, base_address + (counter_number << regshift));
+	byte = (count >> 8) & 0xff;	// msb of counter value
+	outb(byte, base_address + (counter_number << regshift));
+}
+
+static inline void i8254_mm_write(void *base_address,
+	unsigned int regshift, unsigned int counter_number, unsigned int count)
+{
+	unsigned int byte;
+
+	if (counter_number > 2)
+		return;
+
+	byte = count & 0xff;	// lsb of counter value
+	writeb(byte, base_address + (counter_number << regshift));
+	byte = (count >> 8) & 0xff;	// msb of counter value
+	writeb(byte, base_address + (counter_number << regshift));
+}
+
+/* Set counter mode, should work for 8253 also.
+ * Note: the 'mode' value is different to that for i8254_load() and comes
+ * from the INSN_CONFIG_8254_SET_MODE command:
+ *   I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
+ * OR'ed with:
+ *   I8254_BCD, I8254_BINARY
+ */
+static inline int i8254_set_mode(unsigned long base_address,
+	unsigned int regshift, unsigned int counter_number, unsigned int mode)
+{
+	unsigned int byte;
+
+	if (counter_number > 2)
+		return -1;
+	if (mode > (I8254_MODE5 | I8254_BINARY))
+		return -1;
+
+	byte = counter_number << 6;
+	byte |= 0x30;		// load low then high byte
+	byte |= mode;		// set counter mode and BCD|binary
+	outb(byte, base_address + (i8254_control_reg << regshift));
+
+	return 0;
+}
+
+static inline int i8254_mm_set_mode(void *base_address,
+	unsigned int regshift, unsigned int counter_number, unsigned int mode)
+{
+	unsigned int byte;
+
+	if (counter_number > 2)
+		return -1;
+	if (mode > (I8254_MODE5 | I8254_BINARY))
+		return -1;
+
+	byte = counter_number << 6;
+	byte |= 0x30;		// load low then high byte
+	byte |= mode;		// set counter mode and BCD|binary
+	writeb(byte, base_address + (i8254_control_reg << regshift));
+
+	return 0;
+}
+
+static inline int i8254_status(unsigned long base_address,
+	unsigned int regshift, unsigned int counter_number)
+{
+	outb(0xE0 | (2 << counter_number),
+		base_address + (i8254_control_reg << regshift));
+	return inb(base_address + (counter_number << regshift));
+}
+
+static inline int i8254_mm_status(void *base_address,
+	unsigned int regshift, unsigned int counter_number)
+{
+	writeb(0xE0 | (2 << counter_number),
+		base_address + (i8254_control_reg << regshift));
+	return readb(base_address + (counter_number << regshift));
+}
+
+#endif
+
+#endif

+ 442 - 0
drivers/staging/comedi/drivers/8255.c

@@ -0,0 +1,442 @@
+/*
+    comedi/drivers/8255.c
+    Driver for 8255
+
+    COMEDI - Linux Control and Measurement Device Interface
+    Copyright (C) 1998 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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+/*
+Driver: 8255
+Description: generic 8255 support
+Devices: [standard] 8255 (8255)
+Author: ds
+Status: works
+Updated: Fri,  7 Jun 2002 12:56:45 -0700
+
+The classic in digital I/O.  The 8255 appears in Comedi as a single
+digital I/O subdevice with 24 channels.  The channel 0 corresponds
+to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
+7.  Direction configuration is done in blocks, with channels 0-7,
+8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
+supported is mode 0.
+
+You should enable compilation this driver if you plan to use a board
+that has an 8255 chip.  For multifunction boards, the main driver will
+configure the 8255 subdevice automatically.
+
+This driver also works independently with ISA and PCI cards that
+directly map the 8255 registers to I/O ports, including cards with
+multiple 8255 chips.  To configure the driver for such a card, the
+option list should be a list of the I/O port bases for each of the
+8255 chips.  For example,
+
+  comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
+
+Note that most PCI 8255 boards do NOT work with this driver, and
+need a separate driver as a wrapper.  For those that do work, the
+I/O port base address can be found in the output of 'lspci -v'.
+
+*/
+
+/*
+   This file contains an exported subdevice for driving an 8255.
+
+   To use this subdevice as part of another driver, you need to
+   set up the subdevice in the attach function of the driver by
+   calling:
+
+     subdev_8255_init(device, subdevice, callback_function, arg)
+
+   device and subdevice are pointers to the device and subdevice
+   structures.  callback_function will be called to provide the
+   low-level input/output to the device, i.e., actual register
+   access.  callback_function will be called with the value of arg
+   as the last parameter.  If the 8255 device is mapped as 4
+   consecutive I/O ports, you can use NULL for callback_function
+   and the I/O port base for arg, and an internal function will
+   handle the register access.
+
+   In addition, if the main driver handles interrupts, you can
+   enable commands on the subdevice by calling subdev_8255_init_irq()
+   instead.  Then, when you get an interrupt that is likely to be
+   from the 8255, you should call subdev_8255_interrupt(), which
+   will copy the latched value to a Comedi buffer.
+ */
+
+#include "../comedidev.h"
+
+#include <linux/ioport.h>
+
+#define _8255_SIZE 4
+
+#define _8255_DATA 0
+#define _8255_CR 3
+
+#define CR_C_LO_IO	0x01
+#define CR_B_IO		0x02
+#define CR_B_MODE	0x04
+#define CR_C_HI_IO	0x08
+#define CR_A_IO		0x10
+#define CR_A_MODE(a)	((a)<<5)
+#define CR_CW		0x80
+
+struct subdev_8255_struct {
+	unsigned long cb_arg;
+	int (*cb_func) (int, int, int, unsigned long);
+	int have_irq;
+};
+
+#define CALLBACK_ARG	(((struct subdev_8255_struct *)s->private)->cb_arg)
+#define CALLBACK_FUNC	(((struct subdev_8255_struct *)s->private)->cb_func)
+#define subdevpriv	((struct subdev_8255_struct *)s->private)
+
+static int dev_8255_attach(struct comedi_device *dev, struct comedi_devconfig * it);
+static int dev_8255_detach(struct comedi_device *dev);
+static struct comedi_driver driver_8255 = {
+      driver_name:"8255",
+      module:THIS_MODULE,
+      attach:dev_8255_attach,
+      detach:dev_8255_detach,
+};
+
+COMEDI_INITCLEANUP(driver_8255);
+
+static void do_config(struct comedi_device *dev, struct comedi_subdevice * s);
+
+void subdev_8255_interrupt(struct comedi_device *dev, struct comedi_subdevice * s)
+{
+	short d;
+
+	d = CALLBACK_FUNC(0, _8255_DATA, 0, CALLBACK_ARG);
+	d |= (CALLBACK_FUNC(0, _8255_DATA + 1, 0, CALLBACK_ARG) << 8);
+
+	comedi_buf_put(s->async, d);
+	s->async->events |= COMEDI_CB_EOS;
+
+	comedi_event(dev, s);
+}
+
+static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
+{
+	unsigned long iobase = arg;
+
+	if (dir) {
+		outb(data, iobase + port);
+		return 0;
+	} else {
+		return inb(iobase + port);
+	}
+}
+
+static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= (data[0] & data[1]);
+
+		if (data[0] & 0xff)
+			CALLBACK_FUNC(1, _8255_DATA, s->state & 0xff,
+				CALLBACK_ARG);
+		if (data[0] & 0xff00)
+			CALLBACK_FUNC(1, _8255_DATA + 1, (s->state >> 8) & 0xff,
+				CALLBACK_ARG);
+		if (data[0] & 0xff0000)
+			CALLBACK_FUNC(1, _8255_DATA + 2,
+				(s->state >> 16) & 0xff, CALLBACK_ARG);
+	}
+
+	data[1] = CALLBACK_FUNC(0, _8255_DATA, 0, CALLBACK_ARG);
+	data[1] |= (CALLBACK_FUNC(0, _8255_DATA + 1, 0, CALLBACK_ARG) << 8);
+	data[1] |= (CALLBACK_FUNC(0, _8255_DATA + 2, 0, CALLBACK_ARG) << 16);
+
+	return 2;
+}
+
+static int subdev_8255_insn_config(struct comedi_device *dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	unsigned int mask;
+	unsigned int bits;
+
+	mask = 1 << CR_CHAN(insn->chanspec);
+	if (mask & 0x0000ff) {
+		bits = 0x0000ff;
+	} else if (mask & 0x00ff00) {
+		bits = 0x00ff00;
+	} else if (mask & 0x0f0000) {
+		bits = 0x0f0000;
+	} else {
+		bits = 0xf00000;
+	}
+
+	switch (data[0]) {
+	case INSN_CONFIG_DIO_INPUT:
+		s->io_bits &= ~bits;
+		break;
+	case INSN_CONFIG_DIO_OUTPUT:
+		s->io_bits |= bits;
+		break;
+	case INSN_CONFIG_DIO_QUERY:
+		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
+		return insn->n;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	do_config(dev, s);
+
+	return 1;
+}
+
+static void do_config(struct comedi_device *dev, struct comedi_subdevice * s)
+{
+	int config;
+
+	config = CR_CW;
+	/* 1 in io_bits indicates output, 1 in config indicates input */
+	if (!(s->io_bits & 0x0000ff))
+		config |= CR_A_IO;
+	if (!(s->io_bits & 0x00ff00))
+		config |= CR_B_IO;
+	if (!(s->io_bits & 0x0f0000))
+		config |= CR_C_LO_IO;
+	if (!(s->io_bits & 0xf00000))
+		config |= CR_C_HI_IO;
+	CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
+}
+
+static int subdev_8255_cmdtest(struct comedi_device *dev, struct comedi_subdevice * s,
+	struct comedi_cmd * cmd)
+{
+	int err = 0;
+	unsigned int tmp;
+
+	/* step 1 */
+
+	tmp = cmd->start_src;
+	cmd->start_src &= TRIG_NOW;
+	if (!cmd->start_src || tmp != cmd->start_src)
+		err++;
+
+	tmp = cmd->scan_begin_src;
+	cmd->scan_begin_src &= TRIG_EXT;
+	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
+		err++;
+
+	tmp = cmd->convert_src;
+	cmd->convert_src &= TRIG_FOLLOW;
+	if (!cmd->convert_src || tmp != cmd->convert_src)
+		err++;
+
+	tmp = cmd->scan_end_src;
+	cmd->scan_end_src &= TRIG_COUNT;
+	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
+		err++;
+
+	tmp = cmd->stop_src;
+	cmd->stop_src &= TRIG_NONE;
+	if (!cmd->stop_src || tmp != cmd->stop_src)
+		err++;
+
+	if (err)
+		return 1;
+
+	/* step 2 */
+
+	if (err)
+		return 2;
+
+	/* step 3 */
+
+	if (cmd->start_arg != 0) {
+		cmd->start_arg = 0;
+		err++;
+	}
+	if (cmd->scan_begin_arg != 0) {
+		cmd->scan_begin_arg = 0;
+		err++;
+	}
+	if (cmd->convert_arg != 0) {
+		cmd->convert_arg = 0;
+		err++;
+	}
+	if (cmd->scan_end_arg != 1) {
+		cmd->scan_end_arg = 1;
+		err++;
+	}
+	if (cmd->stop_arg != 0) {
+		cmd->stop_arg = 0;
+		err++;
+	}
+
+	if (err)
+		return 3;
+
+	/* step 4 */
+
+	if (err)
+		return 4;
+
+	return 0;
+}
+
+static int subdev_8255_cmd(struct comedi_device *dev, struct comedi_subdevice * s)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+static int subdev_8255_cancel(struct comedi_device *dev, struct comedi_subdevice * s)
+{
+	/* FIXME */
+
+	return 0;
+}
+
+int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice * s, int (*cb) (int,
+		int, int, unsigned long), unsigned long arg)
+{
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+	s->n_chan = 24;
+	s->range_table = &range_digital;
+	s->maxdata = 1;
+
+	s->private = kmalloc(sizeof(struct subdev_8255_struct), GFP_KERNEL);
+	if (!s->private)
+		return -ENOMEM;
+
+	CALLBACK_ARG = arg;
+	if (cb == NULL) {
+		CALLBACK_FUNC = subdev_8255_cb;
+	} else {
+		CALLBACK_FUNC = cb;
+	}
+	s->insn_bits = subdev_8255_insn;
+	s->insn_config = subdev_8255_insn_config;
+
+	s->state = 0;
+	s->io_bits = 0;
+	do_config(dev, s);
+
+	return 0;
+}
+
+int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice * s,
+	int (*cb) (int, int, int, unsigned long), unsigned long arg)
+{
+	int ret;
+
+	ret = subdev_8255_init(dev, s, cb, arg);
+	if (ret < 0)
+		return ret;
+
+	s->do_cmdtest = subdev_8255_cmdtest;
+	s->do_cmd = subdev_8255_cmd;
+	s->cancel = subdev_8255_cancel;
+
+	subdevpriv->have_irq = 1;
+
+	return 0;
+}
+
+void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice * s)
+{
+	if (s->private) {
+		if (subdevpriv->have_irq) {
+		}
+
+		kfree(s->private);
+	}
+}
+
+/*
+
+   Start of the 8255 standalone device
+
+ */
+
+static int dev_8255_attach(struct comedi_device *dev, struct comedi_devconfig * it)
+{
+	int ret;
+	unsigned long iobase;
+	int i;
+
+	printk("comedi%d: 8255:", dev->minor);
+
+	dev->board_name = "8255";
+
+	for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
+		iobase = it->options[i];
+		if (!iobase)
+			break;
+	}
+	if (i == 0) {
+		printk(" no devices specified\n");
+		return -EINVAL;
+	}
+
+	if ((ret = alloc_subdevices(dev, i)) < 0)
+		return ret;
+
+	for (i = 0; i < dev->n_subdevices; i++) {
+		iobase = it->options[i];
+
+		printk(" 0x%04lx", iobase);
+		if (!request_region(iobase, _8255_SIZE, "8255")) {
+			printk(" (I/O port conflict)");
+
+			dev->subdevices[i].type = COMEDI_SUBD_UNUSED;
+		} else {
+			subdev_8255_init(dev, dev->subdevices + i, NULL,
+				iobase);
+		}
+	}
+
+	printk("\n");
+
+	return 0;
+}
+
+static int dev_8255_detach(struct comedi_device *dev)
+{
+	int i;
+	unsigned long iobase;
+	struct comedi_subdevice *s;
+
+	printk("comedi%d: 8255: remove\n", dev->minor);
+
+	for (i = 0; i < dev->n_subdevices; i++) {
+		s = dev->subdevices + i;
+		if (s->type != COMEDI_SUBD_UNUSED) {
+			iobase = CALLBACK_ARG;
+			release_region(iobase, _8255_SIZE);
+		}
+		subdev_8255_cleanup(dev, s);
+	}
+
+	return 0;
+}
+
+EXPORT_SYMBOL(subdev_8255_init);
+EXPORT_SYMBOL(subdev_8255_init_irq);
+EXPORT_SYMBOL(subdev_8255_cleanup);
+EXPORT_SYMBOL(subdev_8255_interrupt);

+ 57 - 0
drivers/staging/comedi/drivers/8255.h

@@ -0,0 +1,57 @@
+/*
+    module/8255.h
+    Header file for 8255
+
+    COMEDI - Linux Control and Measurement Device Interface
+    Copyright (C) 1998 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.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef _8255_H
+#define _8255_H
+
+#include "../comedidev.h"
+
+#if defined(CONFIG_COMEDI_8255) || defined(CONFIG_COMEDI_8255_MODULE)
+
+int subdev_8255_init(struct comedi_device * dev, struct comedi_subdevice * s,
+	int (*cb) (int, int, int, unsigned long), unsigned long arg);
+int subdev_8255_init_irq(struct comedi_device * dev, struct comedi_subdevice * s,
+	int (*cb) (int, int, int, unsigned long), unsigned long arg);
+void subdev_8255_cleanup(struct comedi_device * dev, struct comedi_subdevice * s);
+void subdev_8255_interrupt(struct comedi_device * dev, struct comedi_subdevice * s);
+
+#else
+
+static inline int subdev_8255_init(struct comedi_device * dev, struct comedi_subdevice * s,
+	void *x, unsigned long y)
+{
+	printk("8255 support not configured -- disabling subdevice\n");
+
+	s->type = COMEDI_SUBD_UNUSED;
+
+	return 0;
+}
+
+static inline void subdev_8255_cleanup(struct comedi_device * dev,
+	struct comedi_subdevice * s)
+{
+}
+
+#endif
+
+#endif

+ 111 - 2
drivers/staging/comedi/drivers/Makefile

@@ -8,12 +8,121 @@ obj-$(CONFIG_COMEDI)			+= comedi_test.o
 obj-$(CONFIG_COMEDI)			+= comedi_parport.o
 obj-$(CONFIG_COMEDI)			+= comedi_parport.o
 
 
 # Comedi PCI drivers
 # Comedi PCI drivers
-obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= mite.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= 8255.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= acl7225b.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_035.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_1032.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_1500.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_1516.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_1564.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_16xx.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_2016.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_2032.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_2200.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_3001.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_3120.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_3501.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= addi_apci_3xxx.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adl_pci6208.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adl_pci7296.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adl_pci7432.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adl_pci8164.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adl_pci9111.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adl_pci9118.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adq12b.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adv_pci1710.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adv_pci1723.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= adv_pci_dio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= aio_aio12_8.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= aio_iiro_16.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= amplc_dio200.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= amplc_pc236.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= amplc_pc263.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= amplc_pci224.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= amplc_pci230.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= c6xdigio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= cb_pcidas64.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= cb_pcidas.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= cb_pcidda.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= cb_pcidio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= cb_pcimdas.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= cb_pcimdda.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= comedi_bond.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= comedi_parport.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= comedi_test.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= contec_pci_dio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= daqboard2000.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= das08.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= das16m1.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= das16.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= das1800.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= das6402.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= das800.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dmm32at.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt2801.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt2811.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt2814.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt2815.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt2817.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt282x.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= dt3000.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= fl512.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= gsc_hpdi.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= icp_multi.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= icp_multi.o
-obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= me_daq.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ii_pci20kc.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= jr3_pci.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ke_counter.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= me4000.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= me4000.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= me_daq.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= mite.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= mpc624.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= multiq3.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_6527.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_65xx.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_660x.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_670x.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_at_a2150.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_at_ao.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_atmio16d.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_atmio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_labpc.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_pcidio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_pcimio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_tiocmd.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ni_tio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl711.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl724.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl725.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl726.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl730.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl812.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl816.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcl818.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcm3724.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcm3730.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcmad.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcmda12.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcmmio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= pcmuio.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= poc.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= rtd520.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= rtd520.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= rti800.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= rti802.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= s526.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= s626.o
 obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= s626.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= serial2002.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= skel.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= ssv_dnp.o
+obj-$(CONFIG_COMEDI_PCI_DRIVERS)	+= unioxx5.o
+
+# Comedi PCMCIA drivers
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= cb_das16_cs.o
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= das08_cs.o
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= ni_daq_700.o
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= ni_daq_dio24.o
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= ni_labpc_cs.o
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= ni_mio_cs.o
+obj-$(CONFIG_COMEDI_PCMCIA_DRIVERS)	+= quatech_daqp_cs.o
 
 
 # Comedi USB drivers
 # Comedi USB drivers
 obj-$(CONFIG_COMEDI_USB_DRIVERS)	+= usbdux.o
 obj-$(CONFIG_COMEDI_USB_DRIVERS)	+= usbdux.o

+ 149 - 0
drivers/staging/comedi/drivers/acl7225b.c

@@ -0,0 +1,149 @@
+/*
+ * comedi/drivers/acl7225b.c
+ * Driver for Adlink NuDAQ ACL-7225b and clones
+ * José Luis Sánchez
+ */
+/*
+Driver: acl7225b
+Description: Adlink NuDAQ ACL-7225b & compatibles
+Author: José Luis Sánchez (jsanchezv@teleline.es)
+Status: testing
+Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio)
+*/
+
+#include "../comedidev.h"
+
+#include <linux/ioport.h>
+
+#define ACL7225_SIZE   8	/* Requires 8 ioports, but only 4 are used */
+#define P16R16DIO_SIZE 4
+#define ACL7225_RIO_LO 0	/* Relays input/output low byte (R0-R7) */
+#define ACL7225_RIO_HI 1	/* Relays input/output high byte (R8-R15) */
+#define ACL7225_DI_LO  2	/* Digital input low byte (DI0-DI7) */
+#define ACL7225_DI_HI  3	/* Digital input high byte (DI8-DI15) */
+
+static int acl7225b_attach(struct comedi_device *dev, struct comedi_devconfig * it);
+static int acl7225b_detach(struct comedi_device *dev);
+
+struct boardtype {
+	const char *name;	// driver name
+	int io_range;		// len of I/O space
+};
+
+static const struct boardtype boardtypes[] = {
+	{"acl7225b", ACL7225_SIZE,},
+	{"p16r16dio", P16R16DIO_SIZE,},
+};
+
+#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
+#define this_board ((const struct boardtype *)dev->board_ptr)
+
+static struct comedi_driver driver_acl7225b = {
+      driver_name:"acl7225b",
+      module:THIS_MODULE,
+      attach:acl7225b_attach,
+      detach:acl7225b_detach,
+      board_name:&boardtypes[0].name,
+      num_names:n_boardtypes,
+      offset:sizeof(struct boardtype),
+};
+
+COMEDI_INITCLEANUP(driver_acl7225b);
+
+static int acl7225b_do_insn(struct comedi_device *dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
+
+	if (data[0]) {
+		s->state &= ~data[0];
+		s->state |= (data[0] & data[1]);
+	}
+	if (data[0] & 0x00ff)
+		outb(s->state & 0xff, dev->iobase + (unsigned long)s->private);
+	if (data[0] & 0xff00)
+		outb((s->state >> 8),
+			dev->iobase + (unsigned long)s->private + 1);
+
+	data[1] = s->state;
+
+	return 2;
+}
+
+static int acl7225b_di_insn(struct comedi_device *dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if (insn->n != 2)
+		return -EINVAL;
+
+	data[1] = inb(dev->iobase + (unsigned long)s->private) |
+		(inb(dev->iobase + (unsigned long)s->private + 1) << 8);
+
+	return 2;
+}
+
+static int acl7225b_attach(struct comedi_device *dev, struct comedi_devconfig * it)
+{
+	struct comedi_subdevice *s;
+	int iobase, iorange;
+
+	iobase = it->options[0];
+	iorange = this_board->io_range;
+	printk("comedi%d: acl7225b: board=%s 0x%04x ", dev->minor,
+		this_board->name, iobase);
+	if (!request_region(iobase, iorange, "acl7225b")) {
+		printk("I/O port conflict\n");
+		return -EIO;
+	}
+	dev->board_name = this_board->name;
+	dev->iobase = iobase;
+	dev->irq = 0;
+
+	if (alloc_subdevices(dev, 3) < 0)
+		return -ENOMEM;
+
+	s = dev->subdevices + 0;
+	/* Relays outputs */
+	s->type = COMEDI_SUBD_DO;
+	s->subdev_flags = SDF_WRITABLE;
+	s->maxdata = 1;
+	s->n_chan = 16;
+	s->insn_bits = acl7225b_do_insn;
+	s->range_table = &range_digital;
+	s->private = (void *)ACL7225_RIO_LO;
+
+	s = dev->subdevices + 1;
+	/* Relays status */
+	s->type = COMEDI_SUBD_DI;
+	s->subdev_flags = SDF_READABLE;
+	s->maxdata = 1;
+	s->n_chan = 16;
+	s->insn_bits = acl7225b_di_insn;
+	s->range_table = &range_digital;
+	s->private = (void *)ACL7225_RIO_LO;
+
+	s = dev->subdevices + 2;
+	/* Isolated digital inputs */
+	s->type = COMEDI_SUBD_DI;
+	s->subdev_flags = SDF_READABLE;
+	s->maxdata = 1;
+	s->n_chan = 16;
+	s->insn_bits = acl7225b_di_insn;
+	s->range_table = &range_digital;
+	s->private = (void *)ACL7225_DI_LO;
+
+	printk("\n");
+
+	return 0;
+}
+
+static int acl7225b_detach(struct comedi_device *dev)
+{
+	printk("comedi%d: acl7225b: remove\n", dev->minor);
+
+	if (dev->iobase)
+		release_region(dev->iobase, this_board->io_range);
+
+	return 0;
+}

+ 1047 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c

@@ -0,0 +1,1047 @@
+/*
+ *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+/*
+  | Description :   APCI-1710 82X54 timer module                          |
+*/
+
+#include "APCI1710_82x54.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_InitTimer                         |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                BYTE_   b_TimerNbr,                         |
+|                                BYTE_   b_TimerMode,                        |
+|                                ULONG_ ul_ReloadValue,                      |
+|                                BYTE_   b_InputClockSelection,              |
+|                                BYTE_   b_InputClockLevel,                  |
+|                                BYTE_   b_OutputLevel,                      |
+|                                BYTE_   b_HardwareGateLevel)
+INT i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s,
+	struct comedi_insn *insn,unsigned int *data)
+|
++----------------------------------------------------------------------------+
+| Task              : Configure the Timer (b_TimerNbr) operating mode        |
+|                     (b_TimerMode) from selected module (b_ModulNbr).       |
+|                     You must calling this function be for you call any     |
+|                     other function witch access of the timer.              |
+|                                                                            |
+|                                                                            |
+|                       Timer mode description table                         |
+|                                                                            |
+|+--------+-----------------------------+--------------+--------------------+|
+||Selected+      Mode description       +u_ReloadValue | Hardware gate input||
+||  mode  |                             |  description |      action        ||
+|+--------+-----------------------------+--------------+--------------------+|
+||        |Mode 0 is typically used     |              |                    ||
+||        |for event counting. After    |              |                    ||
+||        |the initialisation, OUT      |              |                    ||
+||        |is initially low, and        |              |                    ||
+||   0    |will remain low until the    |Start counting|   Hardware gate    ||
+||        |counter reaches zero.        |   value      |                    ||
+||        |OUT then goes high and       |              |                    ||
+||        |remains high until a new     |              |                    ||
+||        |count is written. See        |              |                    ||
+||        |"i_APCI1710_WriteTimerValue" |              |                    ||
+||        |function.                    |              |                    ||
+|+--------+-----------------------------+--------------+--------------------+|
+||        |Mode 1 is similar to mode 0  |              |                    ||
+||        |except for the gate input    |              |                    ||
+||   1    |action. The gate input is not|Start counting|  Hardware trigger  ||
+||        |used for enabled or disabled |   value      |                    ||
+||        |the timer.                   |              |                    ||
+||        |The gate input is used for   |              |                    ||
+||        |triggered the timer.         |              |                    ||
+|+--------+-----------------------------+--------------+--------------------+|
+||        |This mode functions like a   |              |                    ||
+||        |divide-by-ul_ReloadValue     |              |                    ||
+||        |counter. It is typically used|              |                    ||
+||        |to generate a real time clock|              |                    ||
+||        |interrupt. OUT will initially|              |                    ||
+||   2    |be high after the            |   Division   |  Hardware gate     ||
+||        |initialisation. When the     |    factor    |                    ||
+||        |initial count has decremented|              |                    ||
+||        |to 1, OUT goes low for one   |              |                    ||
+||        |CLK pule. OUT then goes high |              |                    ||
+||        |again, the counter reloads   |              |                    ||
+||        |the initial count            |              |                    ||
+||        |(ul_ReloadValue) and the     |              |                    ||
+||        |process is repeated.         |              |                    ||
+||        |This action can generated a  |              |                    ||
+||        |interrupt. See function      |              |                    ||
+||        |"i_APCI1710_SetBoardInt-     |              |                    ||
+||        |RoutineX"                    |              |                    ||
+||        |and "i_APCI1710_EnableTimer" |              |                    ||
+|+--------+-----------------------------+--------------+--------------------+|
+||        |Mode 3 is typically used for |              |                    ||
+||        |baud rate generation. This   |              |                    ||
+||        |mode is similar to mode 2    |              |                    ||
+||        |except for the duty cycle of |              |                    ||
+||   3    |OUT. OUT will initially be   |  Division    |   Hardware gate    ||
+||        |high after the initialisation|   factor     |                    ||
+||        |When half the initial count  |              |                    ||
+||        |(ul_ReloadValue) has expired,|              |                    ||
+||        |OUT goes low for the         |              |                    ||
+||        |remainder of the count. The  |              |                    ||
+||        |mode is periodic; the        |              |                    ||
+||        |sequence above is repeated   |              |                    ||
+||        |indefinitely.                |              |                    ||
+|+--------+-----------------------------+--------------+--------------------+|
+||        |OUT will be initially high   |              |                    ||
+||        |after the initialisation.    |              |                    ||
+||        |When the initial count       |              |                    ||
+||   4    |expires OUT will go low for  |Start counting|  Hardware gate     ||
+||        |one CLK pulse and then go    |    value     |                    ||
+||        |high again.                  |              |                    ||
+||        |The counting sequences is    |              |                    ||
+||        |triggered by writing a new   |              |                    ||
+||        |value. See                   |              |                    ||
+||        |"i_APCI1710_WriteTimerValue" |              |                    ||
+||        |function. If a new count is  |              |                    ||
+||        |written during counting,     |              |                    ||
+||        |it will be loaded on the     |              |                    ||
+||        |next CLK pulse               |              |                    ||
+|+--------+-----------------------------+--------------+--------------------+|
+||        |Mode 5 is similar to mode 4  |              |                    ||
+||        |except for the gate input    |              |                    ||
+||        |action. The gate input is not|              |                    ||
+||   5    |used for enabled or disabled |Start counting|  Hardware trigger  ||
+||        |the timer. The gate input is |    value     |                    ||
+||        |used for triggered the timer.|              |                    ||
+|+--------+-----------------------------+--------------+--------------------+|
+|                                                                            |
+|                                                                            |
+|                                                                            |
+|                      Input clock selection table                           |
+|                                                                            |
+|  +--------------------------------+------------------------------------+   |
+|  |       b_InputClockSelection    |           Description              |   |
+|  |           parameter            |                                    |   |
+|  +--------------------------------+------------------------------------+   |
+|  |    APCI1710_PCI_BUS_CLOCK      | For the timer input clock, the PCI |   |
+|  |                                | bus clock / 4 is used. This PCI bus|   |
+|  |                                | clock can be 30MHz or 33MHz. For   |   |
+|  |                                | Timer 0 only this selection are    |   |
+|  |                                | available.                         |   |
+|  +--------------------------------+------------------------------------+   |
+|  | APCI1710_ FRONT_CONNECTOR_INPUT| Of the front connector you have the|   |
+|  |                                | possibility to inject a input clock|   |
+|  |                                | for Timer 1 or Timer 2. The source |   |
+|  |                                | from this clock can eat the output |   |
+|  |                                | clock from Timer 0 or any other    |   |
+|  |                                | clock source.                      |   |
+|  +--------------------------------+------------------------------------+   |
+|                                                                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle        : Handle of board         |
+|                                                    APCI-1710               |
+|                     BYTE_   b_ModulNbr           : Module number to        |
+|                                                    configure (0 to 3)      |
+|                     BYTE_   b_TimerNbr           : Timer number to         |
+|                                                    configure (0 to 2)      |
+|                     BYTE_   b_TimerMode          : Timer mode selection    |
+|                                                    (0 to 5)                |
+|                                                    0: Interrupt on terminal|
+|                                                       count                |
+|                                                    1: Hardware             |
+|                                                       retriggerable one-   |
+|                                                       shot                 |
+|                                                    2: Rate generator       |
+|                                                    3: Square wave mode     |
+|                                                    4: Software triggered   |
+|                                                       strobe               |
+|                                                    5: Hardware triggered   |
+|                                                       strobe               |
+|                                                       See timer mode       |
+|                                                       description table.   |
+|                     ULONG_ ul_ReloadValue         : Start counting value   |
+|                                                     or division factor     |
+|                                                     See timer mode         |
+|                                                     description table.     |
+|                     BYTE_   b_InputClockSelection : Selection from input   |
+|                                                     timer clock.           |
+|                                                     See input clock        |
+|                                                     selection table.       |
+|                     BYTE_   b_InputClockLevel     : Selection from input   |
+|                                                     clock level.           |
+|                                                     0 : Low active         |
+|                                                         (Input inverted)   |
+|                                                     1 : High active        |
+|                     BYTE_   b_OutputLevel,        : Selection from output  |
+|                                                     clock level.           |
+|                                                     0 : Low active         |
+|                                                     1 : High active        |
+|                                                         (Output inverted)  |
+|                     BYTE_   b_HardwareGateLevel   : Selection from         |
+|                                                     hardware gate level.   |
+|                                                     0 : Low active         |
+|                                                         (Input inverted)   |
+|                                                     1 : High active        |
+|                                                     If you will not used   |
+|                                                     the hardware gate set  |
+|                                                     this value to 0.
+|b_ModulNbr        = (BYTE) CR_AREF(insn->chanspec);
+	b_TimerNbr		  = (BYTE) CR_CHAN(insn->chanspec);
+	b_TimerMode		  = (BYTE) data[0];
+	ul_ReloadValue	  = (ULONG) data[1];
+	b_InputClockSelection	=(BYTE) data[2];
+	b_InputClockLevel		=(BYTE) data[3];
+	b_OutputLevel			=(BYTE) data[4];
+	b_HardwareGateLevel		=(BYTE) data[5];
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: Timer selection wrong                               |
+|                    -4: The module is not a TIMER module                    |
+|                    -5: Timer mode selection is wrong                       |
+|                    -6: Input timer clock selection is wrong                |
+|                    -7: Selection from input clock level is wrong           |
+|                    -8: Selection from output clock level is wrong          |
+|                    -9: Selection from hardware gate level is wrong         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigInitTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+				   struct comedi_insn * insn, unsigned int * data)
+{
+
+	INT i_ReturnValue = 0;
+	BYTE b_ModulNbr;
+	BYTE b_TimerNbr;
+	BYTE b_TimerMode;
+	ULONG ul_ReloadValue;
+	BYTE b_InputClockSelection;
+	BYTE b_InputClockLevel;
+	BYTE b_OutputLevel;
+	BYTE b_HardwareGateLevel;
+
+	//BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
+	DWORD dw_Test = 0;
+	//END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec);
+	b_TimerMode = (BYTE) data[0];
+	ul_ReloadValue = (ULONG) data[1];
+	b_InputClockSelection = (BYTE) data[2];
+	b_InputClockLevel = (BYTE) data[3];
+	b_OutputLevel = (BYTE) data[4];
+	b_HardwareGateLevel = (BYTE) data[5];
+
+	/* Test the module number */
+	if (b_ModulNbr < 4) {
+		/* Test if 82X54 timer */
+		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+			/* Test the timer number */
+
+			if (b_TimerNbr <= 2) {
+				/* Test the timer mode */
+				if (b_TimerMode <= 5) {
+					//BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
+					/* Test te imput clock selection */
+					/*
+					   if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) ||
+					   ((b_TimerNbr != 0) && ((b_InputClockSelection == 0) || (b_InputClockSelection == 1))))
+					 */
+
+					if (((b_TimerNbr == 0) &&
+					     (b_InputClockSelection == APCI1710_PCI_BUS_CLOCK)) ||
+					    ((b_TimerNbr == 0) &&
+					     (b_InputClockSelection == APCI1710_10MHZ)) ||
+					    ((b_TimerNbr != 0) &&
+					     ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) ||
+					      (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) ||
+					      (b_InputClockSelection == APCI1710_10MHZ)))) {
+						//BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
+						if (((b_InputClockSelection == APCI1710_10MHZ) &&
+						     ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) ||
+						     (b_InputClockSelection != APCI1710_10MHZ)) {
+							//END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz
+							/* Test the input clock level selection */
+
+							if ((b_InputClockLevel == 0) ||
+							    (b_InputClockLevel == 1)) {
+								/* Test the output clock level selection */
+								if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) {
+									/* Test the hardware gate level selection */
+									if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) {
+										//BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
+										/* Test if version > 1.1 and clock selection = 10MHz */
+										if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) {
+											/* Test if 40MHz quartz on board */
+											dw_Test = inl(devpriv->s_BoardInfos.ui_Address + (16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)));
+
+											dw_Test = (dw_Test >> 16) & 1;
+										} else {
+											dw_Test = 1;
+										}
+
+										/* Test if detection OK */
+										if (dw_Test == 1) {
+											//END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
+											/* Initialisation OK */
+											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1;
+
+											/* Save the input clock selection */
+											devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockSelection = b_InputClockSelection;
+
+											/* Save the input clock level */
+											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockLevel = ~b_InputClockLevel & 1;
+
+											/* Save the output level */
+											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel = ~b_OutputLevel & 1;
+
+											/* Save the gate level */
+											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel;
+
+											/* Set the configuration word and disable the timer */
+											//BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
+											/*
+											   devpriv->s_ModuleInfo [b_ModulNbr].
+											   s_82X54ModuleInfo.
+											   s_82X54TimerInfo  [b_TimerNbr].
+											   dw_ConfigurationWord = (DWORD) (((b_HardwareGateLevel         << 0) & 0x1) |
+											   ((b_InputClockLevel           << 1) & 0x2) |
+											   (((~b_OutputLevel       & 1)  << 2) & 0x4) |
+											   ((b_InputClockSelection       << 4) & 0x10));
+											 */
+											/* Test if 10MHz selected */
+											if (b_InputClockSelection == APCI1710_10MHZ) {
+												b_InputClockSelection = 2;
+											}
+
+											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (DWORD)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30));
+											//END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
+											outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+											/* Initialise the 82X54 Timer */
+											outl((DWORD) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+											/* Write the reload value */
+											outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+											//BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
+										}	// if (dw_Test == 1)
+										else {
+											/* Input timer clock selection is wrong */
+											i_ReturnValue = -6;
+										}	// if (dw_Test == 1)
+										//END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz
+									}	// if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1))
+									else {
+										/* Selection from hardware gate level is wrong */
+										DPRINTK("Selection from hardware gate level is wrong\n");
+										i_ReturnValue = -9;
+									}	// if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1))
+								}	// if ((b_OutputLevel == 0) || (b_OutputLevel == 1))
+								else {
+									/* Selection from output clock level is wrong */
+									DPRINTK("Selection from output clock level is wrong\n");
+									i_ReturnValue = -8;
+								}	// if ((b_OutputLevel == 0) || (b_OutputLevel == 1))
+							}	// if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1))
+							else {
+								/* Selection from input clock level is wrong */
+								DPRINTK("Selection from input clock level is wrong\n");
+								i_ReturnValue = -7;
+							}	// if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1))
+						} else {
+							/* Input timer clock selection is wrong */
+							DPRINTK("Input timer clock selection is wrong\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+						/* Input timer clock selection is wrong */
+						DPRINTK("Input timer clock selection is wrong\n");
+						i_ReturnValue = -6;
+					}
+				}	// if ((b_TimerMode >= 0) && (b_TimerMode <= 5))
+				else {
+					/* Timer mode selection is wrong */
+					DPRINTK("Timer mode selection is wrong\n");
+					i_ReturnValue = -5;
+				}	// if ((b_TimerMode >= 0) && (b_TimerMode <= 5))
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+			else {
+				/* Timer selection wrong */
+				DPRINTK("Timer selection wrong\n");
+				i_ReturnValue = -3;
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+		} else {
+			/* The module is not a TIMER module */
+			DPRINTK("The module is not a TIMER module\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+		/* Module number error */
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_EnableTimer                       |
+|                               (BYTE_ b_BoardHandle,                        |
+|                                BYTE_ b_ModulNbr,                           |
+|                                BYTE_ b_TimerNbr,                           |
+|                                BYTE_ b_InterruptEnable)
+INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s,
+	struct comedi_insn *insn,unsigned int *data)                |
++----------------------------------------------------------------------------+
+| Task              : Enable OR Disable the Timer (b_TimerNbr) from selected module     |
+|                     (b_ModulNbr). You must calling the                     |
+|                     "i_APCI1710_InitTimer" function be for you call this   |
+|                     function. If you enable the timer interrupt, the timer |
+|                     generate a interrupt after the timer value reach       |
+|                     the zero. See function "i_APCI1710_SetBoardIntRoutineX"|
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
+|                                                 APCI-1710                  |
+|                     BYTE_   b_ModulNbr        : Selected module number     |
+|                                                 (0 to 3)                   |
+|                     BYTE_   b_TimerNbr        : Timer number to enable     |
+|                                                 (0 to 2)                   |
+|                     BYTE_   b_InterruptEnable : Enable or disable the      |
+|                                                 timer interrupt.           |
+|                                                 APCI1710_ENABLE :          |
+|                                                 Enable the timer interrupt |
+|                                                 APCI1710_DISABLE :         |
+|                                                 Disable the timer interrupt|
+i_ReturnValue=insn->n;
+	b_ModulNbr        = (BYTE) CR_AREF(insn->chanspec);
+	b_TimerNbr		  = (BYTE) CR_CHAN(insn->chanspec);
+	b_ActionType      = (BYTE) data[0]; // enable disable
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: Timer selection wrong                               |
+|                    -4: The module is not a TIMER module                    |
+|                    -5: Timer not initialised see function                  |
+|                        "i_APCI1710_InitTimer"                              |
+|                    -6: Interrupt parameter is wrong                        |
+|                    -7: Interrupt function not initialised.                 |
+|                        See function "i_APCI1710_SetBoardIntRoutineX"       |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device * dev,
+					   struct comedi_subdevice * s,
+					   struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_DummyRead;
+	BYTE b_ModulNbr;
+	BYTE b_TimerNbr;
+	BYTE b_ActionType;
+	BYTE b_InterruptEnable;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_TimerNbr = (BYTE) CR_CHAN(insn->chanspec);
+	b_ActionType = (BYTE) data[0];	// enable disable
+
+	/* Test the module number */
+	if (b_ModulNbr < 4) {
+		/* Test if 82X54 timer */
+		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+			/* Test the timer number */
+			if (b_TimerNbr <= 2) {
+				/* Test if timer initialised */
+				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
+
+					switch (b_ActionType) {
+					case APCI1710_ENABLE:
+						b_InterruptEnable = (BYTE) data[1];
+						/* Test the interrupt selection */
+						if ((b_InterruptEnable == APCI1710_ENABLE) ||
+						    (b_InterruptEnable == APCI1710_DISABLE)) {
+							if (b_InterruptEnable == APCI1710_ENABLE) {
+
+								dw_DummyRead = inl(devpriv->s_BoardInfos.ui_Address + 12 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+								/* Enable the interrupt */
+								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8;
+
+								outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+								devpriv->tsk_Current = current;	// Save the current process task structure
+
+							}	// if (b_InterruptEnable == APCI1710_ENABLE)
+							else {
+								/* Disable the interrupt */
+								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
+
+								outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+								/* Save the interrupt flag */
+								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
+							}	// if (b_InterruptEnable == APCI1710_ENABLE)
+
+							/* Test if error occur */
+							if (i_ReturnValue >= 0) {
+								/* Save the interrupt flag */
+								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask | ((1 & b_InterruptEnable) << b_TimerNbr);
+
+								/* Enable the timer */
+								outl(1, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+							}
+						} else {
+							/* Interrupt parameter is wrong */
+							DPRINTK("\n");
+							i_ReturnValue = -6;
+						}
+						break;
+					case APCI1710_DISABLE:
+						/* Test the interrupt flag */
+						if (((devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask >> b_TimerNbr) & 1) == 1) {
+							/* Disable the interrupt */
+
+							devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr]. dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
+
+							outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+							/* Save the interrupt flag */
+							devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
+						}
+
+						/* Disable the timer */
+						outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+						break;
+					}	// Switch end
+				} else {
+					/* Timer not initialised see function */
+					DPRINTK ("Timer not initialised see function\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+				/* Timer selection wrong */
+				DPRINTK("Timer selection wrong\n");
+				i_ReturnValue = -3;
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+		} else {
+			/* The module is not a TIMER module */
+			DPRINTK("The module is not a TIMER module\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+		/* Module number error */
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_ReadAllTimerValue                 |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        PULONG_ pul_TimerValueArray)
+INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s,
+	struct comedi_insn *insn,unsigned int *data)        |
++----------------------------------------------------------------------------+
+| Task              : Return the all timer values from selected timer        |
+|                     module (b_ModulNbr).                                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
+|                                                 APCI-1710                  |
+|                     BYTE_   b_ModulNbr        : Selected module number     |
+|                                                 (0 to 3)                   |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_ pul_TimerValueArray : Timer value array.       |
+|                           Element 0 contain the timer 0 value.             |
+|                           Element 1 contain the timer 1 value.             |
+|                           Element 2 contain the timer 2 value.             |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: The module is not a TIMER module                    |
+|                    -4: Timer 0 not initialised see function                |
+|                        "i_APCI1710_InitTimer"                              |
+|                    -5: Timer 1 not initialised see function                |
+|                        "i_APCI1710_InitTimer"                              |
+|                    -6: Timer 2 not initialised see function                |
+|                        "i_APCI1710_InitTimer"                              |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data)
+{
+	INT i_ReturnValue = 0;
+	BYTE b_ModulNbr, b_ReadType;
+	PULONG pul_TimerValueArray;
+
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_ReadType = CR_CHAN(insn->chanspec);
+	pul_TimerValueArray = (PULONG) data;
+	i_ReturnValue = insn->n;
+
+	switch (b_ReadType) {
+	case APCI1710_TIMER_READINTERRUPT:
+
+		data[0] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].b_OldModuleMask;
+		data[1] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldInterruptMask;
+		data[2] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
+
+		/* Increment the read FIFO */
+		devpriv->s_InterruptParameters.ui_Read = (devpriv->s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
+
+		break;
+
+	case APCI1710_TIMER_READALLTIMER:
+		/* Test the module number */
+		if (b_ModulNbr < 4) {
+			/* Test if 82X54 timer */
+			if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+				/* Test if timer 0 iniutialised */
+				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[0].b_82X54Init == 1) {
+					/* Test if timer 1 iniutialised */
+					if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[1].b_82X54Init == 1) {
+						/* Test if timer 2 iniutialised */
+						if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[2].b_82X54Init == 1) {
+							/* Latch all counter */
+							outl(0x17, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
+
+							/* Read the timer 0 value */
+							pul_TimerValueArray[0] = inl(devpriv->s_BoardInfos.ui_Address + 0 + (64 * b_ModulNbr));
+
+							/* Read the timer 1 value */
+							pul_TimerValueArray[1] = inl(devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
+
+							/* Read the timer 2 value */
+							pul_TimerValueArray[2] = inl(devpriv->s_BoardInfos.ui_Address + 8 + (64 * b_ModulNbr));
+						} else {
+							/* Timer 2 not initialised see function */
+							DPRINTK("Timer 2 not initialised see function\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+						/* Timer 1 not initialised see function */
+						DPRINTK("Timer 1 not initialised see function\n");
+						i_ReturnValue = -5;
+					}
+				} else {
+					/* Timer 0 not initialised see function */
+					DPRINTK("Timer 0 not initialised see function\n");
+					i_ReturnValue = -4;
+				}
+			} else {
+				/* The module is not a TIMER module */
+				DPRINTK("The module is not a TIMER module\n");
+				i_ReturnValue = -3;
+			}
+		} else {
+			/* Module number error */
+			DPRINTK("Module number error\n");
+			i_ReturnValue = -2;
+		}
+
+	}			// End of Switch
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev,
+struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                   |
++----------------------------------------------------------------------------+
+| Task              : Read write functions for Timer                                          |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnBitsTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+			     struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_BitsType;
+	INT i_ReturnValue = 0;
+	b_BitsType = data[0];
+
+	printk("\n82X54");
+
+	switch (b_BitsType) {
+	case APCI1710_TIMER_READVALUE:
+		i_ReturnValue = i_APCI1710_ReadTimerValue(dev,
+							  (BYTE)CR_AREF(insn->chanspec),
+							  (BYTE)CR_CHAN(insn->chanspec),
+							  (PULONG) & data[0]);
+		break;
+
+	case APCI1710_TIMER_GETOUTPUTLEVEL:
+		i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev,
+							       (BYTE)CR_AREF(insn->chanspec),
+							       (BYTE)CR_CHAN(insn->chanspec),
+							       (PBYTE) &data[0]);
+		break;
+
+	case APCI1710_TIMER_GETPROGRESSSTATUS:
+		i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev,
+								  (BYTE)CR_AREF(insn->chanspec),
+								  (BYTE)CR_CHAN(insn->chanspec),
+								  (PBYTE)&data[0]);
+		break;
+
+	case APCI1710_TIMER_WRITEVALUE:
+		i_ReturnValue = i_APCI1710_WriteTimerValue(dev,
+							   (BYTE)CR_AREF(insn->chanspec),
+							   (BYTE)CR_CHAN(insn->chanspec),
+							   (ULONG)data[1]);
+
+		break;
+
+	default:
+		printk("Bits Config Parameter Wrong\n");
+		i_ReturnValue = -1;
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_ReadTimerValue                    |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_TimerNbr,               |
+|                                        PULONG_ pul_TimerValue)             |
++----------------------------------------------------------------------------+
+| Task              : Return the timer value from selected digital timer     |
+|                     (b_TimerNbr) from selected timer  module (b_ModulNbr). |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
+|                                                 APCI-1710                  |
+|                     BYTE_   b_ModulNbr        : Selected module number     |
+|                                                 (0 to 3)                   |
+|                     BYTE_   b_TimerNbr        : Timer number to read       |
+|                                                 (0 to 2)                   |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_ pul_TimerValue    : Timer value                |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: Timer selection wrong                               |
+|                    -4: The module is not a TIMER module                    |
+|                    -5: Timer not initialised see function                  |
+|                        "i_APCI1710_InitTimer"                              |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ReadTimerValue(struct comedi_device * dev,
+			      BYTE b_ModulNbr, BYTE b_TimerNbr,
+			      PULONG pul_TimerValue)
+{
+	INT i_ReturnValue = 0;
+
+	/* Test the module number */
+	if (b_ModulNbr < 4) {
+		/* Test if 82X54 timer */
+		if ((devpriv->s_BoardInfos.
+		     dw_MolduleConfiguration[b_ModulNbr] &
+		     0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+			/* Test the timer number */
+			if (b_TimerNbr <= 2) {
+				/* Test if timer initialised */
+				if (devpriv->
+				    s_ModuleInfo[b_ModulNbr].
+				    s_82X54ModuleInfo.
+				    s_82X54TimerInfo[b_TimerNbr].
+				    b_82X54Init == 1) {
+					/* Latch the timer value */
+					outl((2 << b_TimerNbr) | 0xD0,
+					     devpriv->s_BoardInfos.
+					     ui_Address + 12 +
+					     (64 * b_ModulNbr));
+
+					/* Read the counter value */
+					*pul_TimerValue =
+					    inl(devpriv->s_BoardInfos.
+						ui_Address + (b_TimerNbr * 4) +
+						(64 * b_ModulNbr));
+				} else {
+					/* Timer not initialised see function */
+					DPRINTK("Timer not initialised see function\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+				/* Timer selection wrong */
+				DPRINTK("Timer selection wrong\n");
+				i_ReturnValue = -3;
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+		} else {
+			/* The module is not a TIMER module */
+			DPRINTK("The module is not a TIMER module\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+		/* Module number error */
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+	/*
+	   +----------------------------------------------------------------------------+
+	   | Function Name     : _INT_     i_APCI1710_GetTimerOutputLevel               |
+	   |                                       (BYTE_     b_BoardHandle,            |
+	   |                                        BYTE_     b_ModulNbr,               |
+	   |                                        BYTE_     b_TimerNbr,               |
+	   |                                        PBYTE_   pb_OutputLevel)            |
+	   +----------------------------------------------------------------------------+
+	   | Task              : Return the output signal level (pb_OutputLevel) from   |
+	   |                     selected digital timer (b_TimerNbr) from selected timer|
+	   |                     module (b_ModulNbr).                                   |
+	   +----------------------------------------------------------------------------+
+	   | Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
+	   |                                                 APCI-1710                  |
+	   |                     BYTE_   b_ModulNbr        : Selected module number     |
+	   |                                                 (0 to 3)                   |
+	   |                     BYTE_   b_TimerNbr        : Timer number to test       |
+	   |                                                 (0 to 2)                   |
+	   +----------------------------------------------------------------------------+
+	   | Output Parameters : PBYTE_ pb_OutputLevel     : Output signal level        |
+	   |                                                 0 : The output is low      |
+	   |                                                 1 : The output is high     |
+	   +----------------------------------------------------------------------------+
+	   | Return Value      : 0: No error                                            |
+	   |                    -1: The handle parameter of the board is wrong          |
+	   |                    -2: Module selection wrong                              |
+	   |                    -3: Timer selection wrong                               |
+	   |                    -4: The module is not a TIMER module                    |
+	   |                    -5: Timer not initialised see function                  |
+	   |                        "i_APCI1710_InitTimer"                              |
+	   +----------------------------------------------------------------------------+
+	 */
+
+INT i_APCI1710_GetTimerOutputLevel(struct comedi_device * dev,
+				   BYTE b_ModulNbr, BYTE b_TimerNbr,
+				   PBYTE pb_OutputLevel)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_TimerStatus;
+
+	/* Test the module number */
+	if (b_ModulNbr < 4) {
+		/* Test if 82X54 timer */
+		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+			/* Test the timer number */
+			if (b_TimerNbr <= 2) {
+				/* Test if timer initialised */
+				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
+					/* Latch the timer value */
+					outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
+
+					/* Read the timer status */
+					dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+					*pb_OutputLevel = (BYTE) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel);
+				} else {
+					/* Timer not initialised see function */
+					DPRINTK("Timer not initialised see function\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+				/* Timer selection wrong */
+				DPRINTK("Timer selection wrong\n");
+				i_ReturnValue = -3;
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+		} else {
+			/* The module is not a TIMER module */
+			DPRINTK("The module is not a TIMER module\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+		/* Module number error */
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_GetTimerProgressStatus            |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_TimerNbr,               |
+|                                        PBYTE_   pb_TimerStatus)            |
++----------------------------------------------------------------------------+
+| Task              : Return the progress status (pb_TimerStatus) from       |
+|                     selected digital timer (b_TimerNbr) from selected timer|
+|                     module (b_ModulNbr).                                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
+|                                                 APCI-1710                  |
+|                     BYTE_   b_ModulNbr        : Selected module number     |
+|                                                 (0 to 3)                   |
+|                     BYTE_   b_TimerNbr        : Timer number to test       |
+|                                                 (0 to 2)                   |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_TimerStatus     : Output signal level        |
+|                                                 0 : Timer not in progress  |
+|                                                 1 : Timer in progress      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: Timer selection wrong                               |
+|                    -4: The module is not a TIMER module                    |
+|                    -5: Timer not initialised see function                  |
+|                        "i_APCI1710_InitTimer"                              |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev,
+				      BYTE b_ModulNbr, BYTE b_TimerNbr,
+				      PBYTE pb_TimerStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_TimerStatus;
+
+	/* Test the module number */
+	if (b_ModulNbr < 4) {
+		/* Test if 82X54 timer */
+
+		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+			/* Test the timer number */
+			if (b_TimerNbr <= 2) {
+				/* Test if timer initialised */
+				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
+					/* Latch the timer value */
+					outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
+
+					/* Read the timer status */
+					dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+
+					*pb_TimerStatus = (BYTE) ((dw_TimerStatus) >> 8) & 1;
+					printk("ProgressStatus : %d", *pb_TimerStatus);
+				} else {
+					/* Timer not initialised see function */
+					i_ReturnValue = -5;
+				}
+			} else {
+				/* Timer selection wrong */
+				i_ReturnValue = -3;
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+		} else {
+			/* The module is not a TIMER module */
+
+			i_ReturnValue = -4;
+		}
+	} else {
+		/* Module number error */
+
+		i_ReturnValue = -2;
+	}
+
+	return i_ReturnValue;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_WriteTimerValue                   |
+|                                       (BYTE_   b_BoardHandle,              |
+|                                        BYTE_   b_ModulNbr,                 |
+|                                        BYTE_   b_TimerNbr,                 |
+|                                        ULONG_ ul_WriteValue)               |
++----------------------------------------------------------------------------+
+| Task              : Write the value (ul_WriteValue) into the selected timer|
+|                     (b_TimerNbr) from selected timer module (b_ModulNbr).  |
+|                     The action in depend of the time mode selection.       |
+|                     See timer mode description table.                      |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle     : Handle of board            |
+|                                                 APCI-1710                  |
+|                     BYTE_   b_ModulNbr        : Selected module number     |
+|                                                 (0 to 3)                   |
+|                     BYTE_   b_TimerNbr        : Timer number to write      |
+|                                                 (0 to 2)                   |
+|                     ULONG_ ul_WriteValue      : Value to write             |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: Timer selection wrong                               |
+|                    -4: The module is not a TIMER module                    |
+|                    -5: Timer not initialised see function                  |
+|                        "i_APCI1710_InitTimer"                              |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_WriteTimerValue(struct comedi_device * dev,
+			       BYTE b_ModulNbr, BYTE b_TimerNbr,
+			       ULONG ul_WriteValue)
+{
+	INT i_ReturnValue = 0;
+
+	/* Test the module number */
+	if (b_ModulNbr < 4) {
+		/* Test if 82X54 timer */
+		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+			/* Test the timer number */
+			if (b_TimerNbr <= 2) {
+				/* Test if timer initialised */
+				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
+					/* Write the value */
+					outl(ul_WriteValue, devpriv->s_BoardInfos.ui_Address + (b_TimerNbr * 4) + (64 * b_ModulNbr));
+				} else {
+					/* Timer not initialised see function */
+					DPRINTK("Timer not initialised see function\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+				/* Timer selection wrong */
+				DPRINTK("Timer selection wrong\n");
+				i_ReturnValue = -3;
+			}	// if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2))
+		} else {
+			/* The module is not a TIMER module */
+			DPRINTK("The module is not a TIMER module\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+		/* Module number error */
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return i_ReturnValue;
+}

+ 73 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h

@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_PCI_BUS_CLOCK 			0
+#define APCI1710_FRONT_CONNECTOR_INPUT 		1
+#define APCI1710_TIMER_READVALUE		0
+#define APCI1710_TIMER_GETOUTPUTLEVEL		1
+#define APCI1710_TIMER_GETPROGRESSSTATUS	2
+#define APCI1710_TIMER_WRITEVALUE		3
+
+#define APCI1710_TIMER_READINTERRUPT		1
+#define APCI1710_TIMER_READALLTIMER		2
+
+/* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
+#ifndef APCI1710_10MHZ
+#define APCI1710_10MHZ	10
+#endif
+/* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
+
+/*
+ * 82X54 TIMER INISIALISATION FUNCTION
+ */
+INT i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,
+					   struct comedi_subdevice *s,
+					   struct comedi_insn *insn, unsigned int *data);
+
+/*
+ * 82X54 READ FUNCTION
+ */
+INT i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev, struct comedi_subdevice *s,
+			     struct comedi_insn *insn, unsigned int *data);
+
+/*
+ * 82X54 READ & WRITE FUNCTION
+ */
+INT i_APCI1710_ReadTimerValue(struct comedi_device *dev,
+			      BYTE b_ModulNbr, BYTE b_TimerNbr,
+			      PULONG pul_TimerValue);
+
+INT i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev,
+				   BYTE b_ModulNbr, BYTE b_TimerNbr,
+				   PBYTE pb_OutputLevel);
+
+INT i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev,
+				      BYTE b_ModulNbr, BYTE b_TimerNbr,
+				      PBYTE pb_TimerStatus);
+
+/*
+ * 82X54 WRITE FUNCTION
+ */
+INT i_APCI1710_WriteTimerValue(struct comedi_device *dev,
+			       BYTE b_ModulNbr, BYTE b_TimerNbr,
+			       ULONG ul_WriteValue);

+ 2032 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c

@@ -0,0 +1,2032 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : CHRONO.C        | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 chronometer module                          |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 29/06/98 | S. Weber  | Digital input / output implementation          |
+  |----------|-----------|------------------------------------------------|
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "APCI1710_Chrono.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_InitChrono                        |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_ChronoMode,             |
+|                                        BYTE_     b_PCIInputClock,          |
+|                                        BYTE_     b_TimingUnit,             |
+|                                        ULONG_   ul_TimingInterval,         |
+|                                        PULONG_ pul_RealTimingInterval)
+
++----------------------------------------------------------------------------+
+| Task              : Configure the chronometer operating mode (b_ChronoMode)|
+|                     from selected module (b_ModulNbr).                     |
+|                     The ul_TimingInterval and ul_TimingUnit determine the  |
+|                     timing base for the measurement.                       |
+|                     The pul_RealTimingInterval return the real timing      |
+|                     value. You must calling this function be for you call  |
+|                     any other function witch access of the chronometer.    |
+|                                                                            |
+|                     Witch this functionality from the APCI-1710 you have   |
+|                     the possibility to measure the timing witch two event. |
+|                                                                            |
+|                     The mode 0 and 1 is appropriate for period measurement.|
+|                     The mode 2 and 3 is appropriate for frequent           |
+|                     measurement.                                           |
+|                     The mode 4 to 7 is appropriate for measuring the timing|
+|                     between  two event.                                    |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle    : Handle of board APCI-1710   |
+| BYTE_   b_ModulNbr  CR_AREF(insn->chanspec)  : Module number to configure  |
+|                                                (0 to 3)                    |
+| BYTE_   b_ChronoMode				data[0]    : Chronometer action mode     |
+|                                                (0 to 7).                   |
+| BYTE_   b_PCIInputClock			data[1] : Selection from PCI bus clock|
+|                                                - APCI1710_30MHZ :          |
+|                                                  The PC have a PCI bus     |
+|                                                  clock from 30 MHz         |
+|                                                - APCI1710_33MHZ :          |
+|                                                  The PC have a PCI bus     |
+|                                                  clock from 33 MHz         |
+|                                                - APCI1710_40MHZ            |
+|                                                  The APCI-1710 have a      |
+|                                                  integrated 40Mhz          |
+|                                                  quartz.                   |
+|               BYTE_   b_TimingUnit	data[2]    : Base timing unity (0 to 4) |
+|                                                 0 : ns                     |
+|                                                 1 : µs                     |
+|                                                 2 : ms                     |
+|                                                 3 : s                      |
+|                                                 4 : mn                     |
+|         ULONG_ ul_TimingInterval : data[3]	 Base timing value.          |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pul_RealTimingInterval : Real  base timing    |
+|                                                       value.
+|                     data[0]
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: Chronometer mode selection is wrong                |
+|                     -5: The selected PCI input clock is wrong              |
+|                     -6: Timing unity selection is wrong                    |
+|                     -7: Base timing selection is wrong                     |
+|                     -8: You can not used the 40MHz clock selection wich    |
+|                         this board                                         |
+|                     -9: You can not used the 40MHz clock selection wich    |
+|                         this CHRONOS version                               |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigInitChrono(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	ULONG ul_TimerValue = 0;
+	ULONG ul_TimingInterval = 0;
+	ULONG ul_RealTimingInterval = 0;
+	double d_RealTimingInterval = 0;
+	DWORD dw_ModeArray[8] =
+		{ 0x01, 0x05, 0x00, 0x04, 0x02, 0x0E, 0x0A, 0x06 };
+	BYTE b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit;
+
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_ChronoMode = (BYTE) data[0];
+	b_PCIInputClock = (BYTE) data[1];
+	b_TimingUnit = (BYTE) data[2];
+	ul_TimingInterval = (ULONG) data[3];
+	i_ReturnValue = insn->n;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if chronometer */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+	      /*****************************/
+			/* Test the chronometer mode */
+	      /*****************************/
+
+			if (b_ChronoMode <= 7) {
+		 /**************************/
+				/* Test the PCI bus clock */
+		 /**************************/
+
+				if ((b_PCIInputClock == APCI1710_30MHZ) ||
+					(b_PCIInputClock == APCI1710_33MHZ) ||
+					(b_PCIInputClock == APCI1710_40MHZ)) {
+		    /*************************/
+					/* Test the timing unity */
+		    /*************************/
+
+					if (b_TimingUnit <= 4) {
+		       /**********************************/
+						/* Test the base timing selection */
+		       /**********************************/
+
+						if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 66) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165576UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 60) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150240UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 50) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374182UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 1UL))) {
+			  /**************************/
+							/* Test the board version */
+			  /**************************/
+
+							if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) {
+			     /************************/
+								/* Test the TOR version */
+			     /************************/
+
+								if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || (b_PCIInputClock != APCI1710_40MHZ)) {
+									fpu_begin
+										();
+
+				/****************************************/
+									/* Calculate the timer 0 division fator */
+				/****************************************/
+
+									switch (b_TimingUnit) {
+				   /******/
+										/* ns */
+				   /******/
+
+									case 0:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_TimerValue
+											=
+											(ULONG)
+											(ul_TimingInterval
+											*
+											(0.001 * b_PCIInputClock));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_TimingInterval * (0.001 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+											ul_TimerValue
+												=
+												ul_TimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										ul_RealTimingInterval
+											=
+											(ULONG)
+											(ul_TimerValue
+											/
+											(0.001 * (double)b_PCIInputClock));
+										d_RealTimingInterval
+											=
+											(double)
+											ul_TimerValue
+											/
+											(0.001
+											*
+											(double)
+											b_PCIInputClock);
+
+										if ((double)((double)ul_TimerValue / (0.001 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+											ul_RealTimingInterval
+												=
+												ul_RealTimingInterval
+												+
+												1;
+										}
+
+										ul_TimingInterval
+											=
+											ul_TimingInterval
+											-
+											1;
+										ul_TimerValue
+											=
+											ul_TimerValue
+											-
+											2;
+										if (b_PCIInputClock != APCI1710_40MHZ) {
+											ul_TimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_TimerValue)
+												*
+												0.99392);
+										}
+
+										break;
+
+				   /******/
+										/* æs */
+				   /******/
+
+									case 1:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_TimerValue
+											=
+											(ULONG)
+											(ul_TimingInterval
+											*
+											(1.0 * b_PCIInputClock));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_TimingInterval * (1.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+											ul_TimerValue
+												=
+												ul_TimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										ul_RealTimingInterval
+											=
+											(ULONG)
+											(ul_TimerValue
+											/
+											(1.0 * (double)b_PCIInputClock));
+										d_RealTimingInterval
+											=
+											(double)
+											ul_TimerValue
+											/
+											(
+											(double)
+											1.0
+											*
+											(double)
+											b_PCIInputClock);
+
+										if ((double)((double)ul_TimerValue / (1.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+											ul_RealTimingInterval
+												=
+												ul_RealTimingInterval
+												+
+												1;
+										}
+
+										ul_TimingInterval
+											=
+											ul_TimingInterval
+											-
+											1;
+										ul_TimerValue
+											=
+											ul_TimerValue
+											-
+											2;
+										if (b_PCIInputClock != APCI1710_40MHZ) {
+											ul_TimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_TimerValue)
+												*
+												0.99392);
+										}
+
+										break;
+
+				   /******/
+										/* ms */
+				   /******/
+
+									case 2:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_TimerValue
+											=
+											ul_TimingInterval
+											*
+											(1000
+											*
+											b_PCIInputClock);
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_TimingInterval * (1000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+											ul_TimerValue
+												=
+												ul_TimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										ul_RealTimingInterval
+											=
+											(ULONG)
+											(ul_TimerValue
+											/
+											(1000.0 * (double)b_PCIInputClock));
+										d_RealTimingInterval
+											=
+											(double)
+											ul_TimerValue
+											/
+											(1000.0
+											*
+											(double)
+											b_PCIInputClock);
+
+										if ((double)((double)ul_TimerValue / (1000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+											ul_RealTimingInterval
+												=
+												ul_RealTimingInterval
+												+
+												1;
+										}
+
+										ul_TimingInterval
+											=
+											ul_TimingInterval
+											-
+											1;
+										ul_TimerValue
+											=
+											ul_TimerValue
+											-
+											2;
+										if (b_PCIInputClock != APCI1710_40MHZ) {
+											ul_TimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_TimerValue)
+												*
+												0.99392);
+										}
+
+										break;
+
+				   /*****/
+										/* s */
+				   /*****/
+
+									case 3:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_TimerValue
+											=
+											(ULONG)
+											(ul_TimingInterval
+											*
+											(1000000.0
+												*
+												b_PCIInputClock));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_TimingInterval * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+											ul_TimerValue
+												=
+												ul_TimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										ul_RealTimingInterval
+											=
+											(ULONG)
+											(ul_TimerValue
+											/
+											(1000000.0
+												*
+												(double)
+												b_PCIInputClock));
+										d_RealTimingInterval
+											=
+											(double)
+											ul_TimerValue
+											/
+											(1000000.0
+											*
+											(double)
+											b_PCIInputClock);
+
+										if ((double)((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+											ul_RealTimingInterval
+												=
+												ul_RealTimingInterval
+												+
+												1;
+										}
+
+										ul_TimingInterval
+											=
+											ul_TimingInterval
+											-
+											1;
+										ul_TimerValue
+											=
+											ul_TimerValue
+											-
+											2;
+										if (b_PCIInputClock != APCI1710_40MHZ) {
+											ul_TimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_TimerValue)
+												*
+												0.99392);
+										}
+
+										break;
+
+				   /******/
+										/* mn */
+				   /******/
+
+									case 4:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_TimerValue
+											=
+											(ULONG)
+											(
+											(ul_TimingInterval
+												*
+												60)
+											*
+											(1000000.0
+												*
+												b_PCIInputClock));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)(ul_TimingInterval * 60.0) * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+											ul_TimerValue
+												=
+												ul_TimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										ul_RealTimingInterval
+											=
+											(ULONG)
+											(ul_TimerValue
+											/
+											(1000000.0
+												*
+												(double)
+												b_PCIInputClock))
+											/
+											60;
+										d_RealTimingInterval
+											=
+											(
+											(double)
+											ul_TimerValue
+											/
+											(0.001 * (double)b_PCIInputClock)) / 60.0;
+
+										if ((double)(((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+											ul_RealTimingInterval
+												=
+												ul_RealTimingInterval
+												+
+												1;
+										}
+
+										ul_TimingInterval
+											=
+											ul_TimingInterval
+											-
+											1;
+										ul_TimerValue
+											=
+											ul_TimerValue
+											-
+											2;
+										if (b_PCIInputClock != APCI1710_40MHZ) {
+											ul_TimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_TimerValue)
+												*
+												0.99392);
+										}
+
+										break;
+									}
+
+									fpu_end();
+
+				/****************************/
+									/* Save the PCI input clock */
+				/****************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_ChronoModuleInfo.
+										b_PCIInputClock
+										=
+										b_PCIInputClock;
+
+				/*************************/
+									/* Save the timing unity */
+				/*************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_ChronoModuleInfo.
+										b_TimingUnit
+										=
+										b_TimingUnit;
+
+				/************************/
+									/* Save the base timing */
+				/************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_ChronoModuleInfo.
+										d_TimingInterval
+										=
+										d_RealTimingInterval;
+
+				/****************************/
+									/* Set the chronometer mode */
+				/****************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_ChronoModuleInfo.
+										dw_ConfigReg
+										=
+										dw_ModeArray
+										[b_ChronoMode];
+
+				/***********************/
+									/* Test if 40 MHz used */
+				/***********************/
+
+									if (b_PCIInputClock == APCI1710_40MHZ) {
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_ChronoModuleInfo.
+											dw_ConfigReg
+											=
+											devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_ChronoModuleInfo.
+											dw_ConfigReg
+											|
+											0x80;
+									}
+
+									outl(devpriv->s_ModuleInfo[b_ModulNbr].s_ChronoModuleInfo.dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr));
+
+				/***********************/
+									/* Write timer 0 value */
+				/***********************/
+
+									outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
+
+				/*********************/
+									/* Chronometer init. */
+				/*********************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_ChronoModuleInfo.
+										b_ChronoInit
+										=
+										1;
+								} else {
+				/***********************************************/
+									/* TOR version error for 40MHz clock selection */
+				/***********************************************/
+
+									DPRINTK("TOR version error for 40MHz clock selection\n");
+									i_ReturnValue
+										=
+										-9;
+								}
+							} else {
+			     /**************************************************************/
+								/* You can not used the 40MHz clock selection wich this board */
+			     /**************************************************************/
+
+								DPRINTK("You can not used the 40MHz clock selection wich this board\n");
+								i_ReturnValue =
+									-8;
+							}
+						} else {
+			  /**********************************/
+							/* Base timing selection is wrong */
+			  /**********************************/
+
+							DPRINTK("Base timing selection is wrong\n");
+							i_ReturnValue = -7;
+						}
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+					else {
+		       /***********************************/
+						/* Timing unity selection is wrong */
+		       /***********************************/
+
+						DPRINTK("Timing unity selection is wrong\n");
+						i_ReturnValue = -6;
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+				}	// if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ))
+				else {
+		    /*****************************************/
+					/* The selected PCI input clock is wrong */
+		    /*****************************************/
+
+					DPRINTK("The selected PCI input clock is wrong\n");
+					i_ReturnValue = -5;
+				}	// if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ))
+			}	// if (b_ChronoMode >= 0 && b_ChronoMode <= 7)
+			else {
+		 /***************************************/
+				/* Chronometer mode selection is wrong */
+		 /***************************************/
+
+				DPRINTK("Chronometer mode selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_ChronoMode >= 0 && b_ChronoMode <= 7)
+		} else {
+	      /******************************************/
+			/* The module is not a Chronometer module */
+	      /******************************************/
+
+			DPRINTK("The module is not a Chronometer module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+	data[0] = ul_RealTimingInterval;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_EnableChrono                          |
+|                                               (BYTE_ b_BoardHandle,        |
+|                                                BYTE_ b_ModulNbr,           |
+|                                                BYTE_ b_CycleMode,          |
+|                                                BYTE_ b_InterruptEnable)
+INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev,
+struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)						 |
++----------------------------------------------------------------------------+
+| Task              : Enable the chronometer from selected module            |
+|                     (b_ModulNbr). You must calling the                     |
+|                     "i_APCI1710_InitChrono" function be for you call this  |
+|                     function.                                              |
+|                     If you enable the chronometer interrupt, the           |
+|                     chronometer generate a interrupt after the stop signal.|
+|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
+|                     Interrupt mask description chapter from this manual.   |
+|                     The b_CycleMode parameter determine if you will        |
+|                     measured a single or more cycle.
+
+|					  Disable the chronometer from selected module           |
+|                     (b_ModulNbr). If you disable the chronometer after a   |
+|                     start signal occur and you restart the chronometer     |
+|                     witch the " i_APCI1710_EnableChrono" function, if no   |
+|                     stop signal occur this start signal is ignored.
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr   CR_AREF(chanspec)  : Selected module number (0 to 3) |
+                                  data[0]  ENABle/Disable chrono
+|                     BYTE_ b_CycleMode    : Selected the chronometer        |
+|                                  data[1]           acquisition mode                |
+|                     BYTE_ b_InterruptEnable : Enable or disable the        |
+|                                   data[2]            chronometer interrupt.       |
+|                                               APCI1710_ENABLE:             |
+|                                               Enable the chronometer       |
+|                                               interrupt                    |
+|                                               APCI1710_DISABLE:            |
+|                                               Disable the chronometer      |
+|                                               interrupt                    |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
+|                     -5: Chronometer acquisition mode cycle is wrong        |
+|                     -6: Interrupt parameter is wrong                       |
+|                     -7: Interrupt function not initialised.                |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"
+                      -8: data[0] wrong input    |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	BYTE b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action;
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_Action = (BYTE) data[0];
+	b_CycleMode = (BYTE) data[1];
+	b_InterruptEnable = (BYTE) data[2];
+	i_ReturnValue = insn->n;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if chronometer */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+	      /***********************************/
+			/* Test if chronometer initialised */
+	      /***********************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_ChronoModuleInfo.b_ChronoInit == 1) {
+
+				switch (b_Action) {
+
+				case APCI1710_ENABLE:
+
+		 /*********************************/
+					/* Test the cycle mode parameter */
+		 /*********************************/
+
+					if ((b_CycleMode == APCI1710_SINGLE)
+						|| (b_CycleMode ==
+							APCI1710_CONTINUOUS)) {
+		    /***************************/
+						/* Test the interrupt flag */
+		    /***************************/
+
+						if ((b_InterruptEnable ==
+								APCI1710_ENABLE)
+							|| (b_InterruptEnable ==
+								APCI1710_DISABLE))
+						{
+
+			  /***************************/
+							/* Save the interrupt flag */
+			  /***************************/
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_ChronoModuleInfo.
+								b_InterruptMask
+								=
+								b_InterruptEnable;
+
+			  /***********************/
+							/* Save the cycle mode */
+			  /***********************/
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_ChronoModuleInfo.
+								b_CycleMode =
+								b_CycleMode;
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_ChronoModuleInfo.
+								dw_ConfigReg =
+								(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_ChronoModuleInfo.
+								dw_ConfigReg &
+								0x8F) | ((1 &
+									b_InterruptEnable)
+								<< 5) | ((1 &
+									b_CycleMode)
+								<< 6) | 0x10;
+
+			  /*****************************/
+							/* Test if interrupt enabled */
+			  /*****************************/
+
+							if (b_InterruptEnable ==
+								APCI1710_ENABLE)
+							{
+			     /****************************/
+								/* Clear the interrupt flag */
+			     /****************************/
+
+								outl(devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_ChronoModuleInfo.
+									dw_ConfigReg,
+									devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 32 +
+									(64 * b_ModulNbr));
+								devpriv->tsk_Current = current;	// Save the current process task structure
+							}
+
+			  /***********************************/
+							/* Enable or disable the interrupt */
+							/* Enable the chronometer          */
+			  /***********************************/
+
+							outl(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_ChronoModuleInfo.
+								dw_ConfigReg,
+								devpriv->
+								s_BoardInfos.
+								ui_Address +
+								16 +
+								(64 * b_ModulNbr));
+
+			  /*************************/
+							/* Clear status register */
+			  /*************************/
+
+							outl(0, devpriv->
+								s_BoardInfos.
+								ui_Address +
+								36 +
+								(64 * b_ModulNbr));
+
+						}	// if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE))
+						else {
+		       /********************************/
+							/* Interrupt parameter is wrong */
+		       /********************************/
+
+							DPRINTK("Interrupt parameter is wrong\n");
+							i_ReturnValue = -6;
+						}	// if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE))
+					}	// if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS))
+					else {
+		    /***********************************************/
+						/* Chronometer acquisition mode cycle is wrong */
+		    /***********************************************/
+
+						DPRINTK("Chronometer acquisition mode cycle is wrong\n");
+						i_ReturnValue = -5;
+					}	// if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS))
+					break;
+
+				case APCI1710_DISABLE:
+
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_ChronoModuleInfo.
+						b_InterruptMask = 0;
+
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_ChronoModuleInfo.
+						dw_ConfigReg =
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_ChronoModuleInfo.
+						dw_ConfigReg & 0x2F;
+
+		 /***************************/
+					/* Disable the interrupt   */
+					/* Disable the chronometer */
+		 /***************************/
+
+					outl(devpriv->s_ModuleInfo[b_ModulNbr].
+						s_ChronoModuleInfo.dw_ConfigReg,
+						devpriv->s_BoardInfos.
+						ui_Address + 16 +
+						(64 * b_ModulNbr));
+
+		 /***************************/
+					/* Test if continuous mode */
+		 /***************************/
+
+					if (devpriv->s_ModuleInfo[b_ModulNbr].
+						s_ChronoModuleInfo.
+						b_CycleMode ==
+						APCI1710_CONTINUOUS) {
+		    /*************************/
+						/* Clear status register */
+		    /*************************/
+
+						outl(0, devpriv->s_BoardInfos.
+							ui_Address + 36 +
+							(64 * b_ModulNbr));
+					}
+					break;
+
+				default:
+					DPRINTK("Inputs wrong! Enable or Disable chrono\n");
+					i_ReturnValue = -8;
+				}	// switch ENABLE/DISABLE
+			} else {
+		 /*******************************/
+				/* Chronometer not initialised */
+		 /*******************************/
+
+				DPRINTK("Chronometer not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a Chronometer module */
+	      /******************************************/
+
+			DPRINTK("The module is not a Chronometer module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT	i_APCI1710_InsnReadChrono(struct comedi_device *dev,struct comedi_subdevice *s,
+struct comedi_insn *insn,unsigned int *data)                   |
++----------------------------------------------------------------------------+
+| Task              : Read  functions for Timer                                     |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnReadChrono(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_ReadType;
+	INT i_ReturnValue = insn->n;
+
+	b_ReadType = CR_CHAN(insn->chanspec);
+
+	switch (b_ReadType) {
+	case APCI1710_CHRONO_PROGRESS_STATUS:
+		i_ReturnValue = i_APCI1710_GetChronoProgressStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_CHRONO_READVALUE:
+		i_ReturnValue = i_APCI1710_ReadChronoValue(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(UINT) insn->unused[0],
+			(PBYTE) & data[0], (PULONG) & data[1]);
+		break;
+
+	case APCI1710_CHRONO_CONVERTVALUE:
+		i_ReturnValue = i_APCI1710_ConvertChronoValue(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(ULONG) insn->unused[0],
+			(PULONG) & data[0],
+			(PBYTE) & data[1],
+			(PBYTE) & data[2],
+			(PUINT) & data[3],
+			(PUINT) & data[4], (PUINT) & data[5]);
+		break;
+
+	case APCI1710_CHRONO_READINTERRUPT:
+		printk("In Chrono Read Interrupt\n");
+
+		data[0] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].b_OldModuleMask;
+		data[1] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].ul_OldInterruptMask;
+		data[2] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
+
+			     /**************************/
+		/* Increment the read FIFO */
+			     /***************************/
+
+		devpriv->
+			s_InterruptParameters.
+			ui_Read = (devpriv->
+			s_InterruptParameters.
+			ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
+		break;
+
+	default:
+		printk("ReadType Parameter wrong\n");
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetChronoProgressStatus               |
+|                               (BYTE_    b_BoardHandle,                     |
+|                                BYTE_    b_ModulNbr,                        |
+|                                PBYTE_  pb_ChronoStatus)                    |
++----------------------------------------------------------------------------+
+| Task              : Return the chronometer status (pb_ChronoStatus) from   |
+|                     selected chronometer module (b_ModulNbr).              |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr     : Selected module number (0 to 3) |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pb_ChronoStatus : Return the chronometer      |
+|                                                status.                     |
+|                                                0 : Measurement not started.|
+|                                                    No start signal occur.  |
+|                                                1 : Measurement started.    |
+|                                                    A start signal occur.   |
+|                                                2 : Measurement stopped.    |
+|                                                    A stop signal occur.    |
+|                                                    The measurement is      |
+|                                                    terminate.              |
+|                                                3: A overflow occur. You    |
+|                                                   must change the base     |
+|                                                   timing witch the         |
+|                                                   function                 |
+|                                                   "i_APCI1710_InitChrono"  |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetChronoProgressStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_ChronoStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if chronometer */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+	      /***********************************/
+			/* Test if chronometer initialised */
+	      /***********************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_ChronoModuleInfo.b_ChronoInit == 1) {
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 8 + (64 * b_ModulNbr));
+
+		 /********************/
+				/* Test if overflow */
+		 /********************/
+
+				if ((dw_Status & 8) == 8) {
+		    /******************/
+					/* Overflow occur */
+		    /******************/
+
+					*pb_ChronoStatus = 3;
+				}	// if ((dw_Status & 8) == 8)
+				else {
+		    /*******************************/
+					/* Test if measurement stopped */
+		    /*******************************/
+
+					if ((dw_Status & 2) == 2) {
+		       /***********************/
+						/* A stop signal occur */
+		       /***********************/
+
+						*pb_ChronoStatus = 2;
+					}	// if ((dw_Status & 2) == 2)
+					else {
+		       /*******************************/
+						/* Test if measurement started */
+		       /*******************************/
+
+						if ((dw_Status & 1) == 1) {
+			  /************************/
+							/* A start signal occur */
+			  /************************/
+
+							*pb_ChronoStatus = 1;
+						}	// if ((dw_Status & 1) == 1)
+						else {
+			  /***************************/
+							/* Measurement not started */
+			  /***************************/
+
+							*pb_ChronoStatus = 0;
+						}	// if ((dw_Status & 1) == 1)
+					}	// if ((dw_Status & 2) == 2)
+				}	// if ((dw_Status & 8) == 8)
+			} else {
+		 /*******************************/
+				/* Chronometer not initialised */
+		 /*******************************/
+				DPRINTK("Chronometer not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a Chronometer module */
+	      /******************************************/
+			DPRINTK("The module is not a Chronometer module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadChronoValue                       |
+|                               (BYTE_     b_BoardHandle,                    |
+|                                BYTE_     b_ModulNbr,                       |
+|                                UINT_    ui_TimeOut,                        |
+|                                PBYTE_   pb_ChronoStatus,                   |
+|                                PULONG_ pul_ChronoValue)                    |
++----------------------------------------------------------------------------+
+| Task              : Return the chronometer status (pb_ChronoStatus) and the|
+|                     timing value (pul_ChronoValue) after a stop signal     |
+|                     occur from selected chronometer module (b_ModulNbr).   |
+|                     This function are only avaible if you have disabled    |
+|                     the interrupt functionality. See function              |
+|                     "i_APCI1710_EnableChrono" and the Interrupt mask       |
+|                     description chapter.                                   |
+|                     You can test the chronometer status witch the          |
+|                     "i_APCI1710_GetChronoProgressStatus" function.         |
+|                                                                            |
+|                     The returned value from pul_ChronoValue parameter is   |
+|                     not real measured timing.                              |
+|                     You must used the "i_APCI1710_ConvertChronoValue"      |
+|                     function or make this operation for calculate the      |
+|                     timing:                                                |
+|                                                                            |
+|                     Timing = pul_ChronoValue * pul_RealTimingInterval.     |
+|                                                                            |
+|                     pul_RealTimingInterval is the returned parameter from  |
+|                     "i_APCI1710_InitChrono" function and the time unity is |
+|                     the b_TimingUnit from "i_APCI1710_InitChrono" function|
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr     : Selected module number (0 to 3) |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pb_ChronoStatus : Return the chronometer      |
+|                                                status.                     |
+|                                                0 : Measurement not started.|
+|                                                    No start signal occur.  |
+|                                                1 : Measurement started.    |
+|                                                    A start signal occur.   |
+|                                                2 : Measurement stopped.    |
+|                                                    A stop signal occur.    |
+|                                                    The measurement is      |
+|                                                    terminate.              |
+|                                                3: A overflow occur. You    |
+|                                                   must change the base     |
+|                                                   timing witch the         |
+|                                                   function                 |
+|                                                   "i_APCI1710_InitChrono"  |
+|                     PULONG  pul_ChronoValue  : Chronometer timing value.   |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
+|                     -5: Timeout parameter is wrong (0 to 65535)            |
+|                     -6: Interrupt routine installed. You can not read      |
+|                         directly the chronometer measured timing.          |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ReadChronoValue(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	UINT ui_TimeOut, PBYTE pb_ChronoStatus, PULONG pul_ChronoValue)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+	DWORD dw_TimeOut = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if chronometer */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+	      /***********************************/
+			/* Test if chronometer initialised */
+	      /***********************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_ChronoModuleInfo.b_ChronoInit == 1) {
+		 /*****************************/
+				/* Test the timout parameter */
+		 /*****************************/
+
+				if ((ui_TimeOut >= 0)
+					&& (ui_TimeOut <= 65535UL)) {
+
+					for (;;) {
+			  /*******************/
+						/* Read the status */
+			  /*******************/
+
+						dw_Status =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 8 +
+							(64 * b_ModulNbr));
+
+			  /********************/
+						/* Test if overflow */
+			  /********************/
+
+						if ((dw_Status & 8) == 8) {
+			     /******************/
+							/* Overflow occur */
+			     /******************/
+
+							*pb_ChronoStatus = 3;
+
+			     /***************************/
+							/* Test if continuous mode */
+			     /***************************/
+
+							if (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_ChronoModuleInfo.
+								b_CycleMode ==
+								APCI1710_CONTINUOUS)
+							{
+				/*************************/
+								/* Clear status register */
+				/*************************/
+
+								outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr));
+							}
+
+							break;
+						}	// if ((dw_Status & 8) == 8)
+						else {
+			     /*******************************/
+							/* Test if measurement stopped */
+			     /*******************************/
+
+							if ((dw_Status & 2) ==
+								2) {
+				/***********************/
+								/* A stop signal occur */
+				/***********************/
+
+								*pb_ChronoStatus
+									= 2;
+
+				/***************************/
+								/* Test if continnous mode */
+				/***************************/
+
+								if (devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_ChronoModuleInfo.
+									b_CycleMode
+									==
+									APCI1710_CONTINUOUS)
+								{
+				   /*************************/
+									/* Clear status register */
+				   /*************************/
+
+									outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr));
+								}
+								break;
+							}	// if ((dw_Status & 2) == 2)
+							else {
+				/*******************************/
+								/* Test if measurement started */
+				/*******************************/
+
+								if ((dw_Status & 1) == 1) {
+				   /************************/
+									/* A start signal occur */
+				   /************************/
+
+									*pb_ChronoStatus
+										=
+										1;
+								}	// if ((dw_Status & 1) == 1)
+								else {
+				   /***************************/
+									/* Measurement not started */
+				   /***************************/
+
+									*pb_ChronoStatus
+										=
+										0;
+								}	// if ((dw_Status & 1) == 1)
+							}	// if ((dw_Status & 2) == 2)
+						}	// if ((dw_Status & 8) == 8)
+
+						if (dw_TimeOut == ui_TimeOut) {
+			     /*****************/
+							/* Timeout occur */
+			     /*****************/
+
+							break;
+						} else {
+			     /*************************/
+							/* Increment the timeout */
+			     /*************************/
+
+							dw_TimeOut =
+								dw_TimeOut + 1;
+							mdelay(1000);
+
+						}
+					}	// for (;;)
+
+		       /*****************************/
+					/* Test if stop signal occur */
+		       /*****************************/
+
+					if (*pb_ChronoStatus == 2) {
+			  /**********************************/
+						/* Read the measured timing value */
+			  /**********************************/
+
+						*pul_ChronoValue =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 4 +
+							(64 * b_ModulNbr));
+
+						if (*pul_ChronoValue != 0) {
+							*pul_ChronoValue =
+								*pul_ChronoValue
+								- 1;
+						}
+					} else {
+			  /*************************/
+						/* Test if timeout occur */
+			  /*************************/
+
+						if ((*pb_ChronoStatus != 3)
+							&& (dw_TimeOut ==
+								ui_TimeOut)
+							&& (ui_TimeOut != 0)) {
+			     /*****************/
+							/* Timeout occur */
+			     /*****************/
+
+							*pb_ChronoStatus = 4;
+						}
+					}
+
+				} else {
+		    /******************************/
+					/* Timeout parameter is wrong */
+		    /******************************/
+					DPRINTK("Timeout parameter is wrong\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /*******************************/
+				/* Chronometer not initialised */
+		 /*******************************/
+				DPRINTK("Chronometer not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a Chronometer module */
+	      /******************************************/
+			DPRINTK("The module is not a Chronometer module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ConvertChronoValue                    |
+|                               (BYTE_     b_BoardHandle,                    |
+|                                BYTE_     b_ModulNbr,                       |
+|                                ULONG_   ul_ChronoValue,                    |
+|                                PULONG_ pul_Hour,                           |
+|                                PBYTE_   pb_Minute,                         |
+|                                PBYTE_   pb_Second,                         |
+|                                PUINT_  pui_MilliSecond,                    |
+|                                PUINT_  pui_MicroSecond,                    |
+|                                PUINT_  pui_NanoSecond)                     |
++----------------------------------------------------------------------------+
+| Task              : Convert the chronometer measured timing                |
+|                     (ul_ChronoValue) in to h, mn, s, ms, µs, ns.           |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle : Handle of board APCI-1710      |
+|                     BYTE_   b_ModulNbr    : Selected module number (0 to 3)|
+|                     ULONG_ ul_ChronoValue : Measured chronometer timing    |
+|                                             value.                         |
+|                                             See"i_APCI1710_ReadChronoValue"|
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_   pul_Hour        : Chronometer timing hour    |
+|                     PBYTE_     pb_Minute      : Chronometer timing minute  |
+|                     PBYTE_     pb_Second      : Chronometer timing second  |
+|                     PUINT_    pui_MilliSecond  : Chronometer timing mini   |
+|                                                 second                     |
+|                     PUINT_    pui_MicroSecond : Chronometer timing micro   |
+|                                                 second                     |
+|                     PUINT_    pui_NanoSecond  : Chronometer timing nano    |
+|                                                 second                     |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ConvertChronoValue(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	ULONG ul_ChronoValue,
+	PULONG pul_Hour,
+	PBYTE pb_Minute,
+	PBYTE pb_Second,
+	PUINT pui_MilliSecond, PUINT pui_MicroSecond, PUINT pui_NanoSecond)
+{
+	INT i_ReturnValue = 0;
+	double d_Hour;
+	double d_Minute;
+	double d_Second;
+	double d_MilliSecond;
+	double d_MicroSecond;
+	double d_NanoSecond;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if chronometer */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+	      /***********************************/
+			/* Test if chronometer initialised */
+	      /***********************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_ChronoModuleInfo.b_ChronoInit == 1) {
+				fpu_begin();
+
+				d_Hour = (double)ul_ChronoValue *(double)
+					devpriv->s_ModuleInfo[b_ModulNbr].
+					s_ChronoModuleInfo.d_TimingInterval;
+
+				switch (devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_ChronoModuleInfo.b_TimingUnit) {
+				case 0:
+					d_Hour = d_Hour / (double)1000.0;
+
+				case 1:
+					d_Hour = d_Hour / (double)1000.0;
+
+				case 2:
+					d_Hour = d_Hour / (double)1000.0;
+
+				case 3:
+					d_Hour = d_Hour / (double)60.0;
+
+				case 4:
+			    /**********************/
+					/* Calculate the hour */
+			    /**********************/
+
+					d_Hour = d_Hour / (double)60.0;
+					*pul_Hour = (ULONG) d_Hour;
+
+			    /************************/
+					/* Calculate the minute */
+			    /************************/
+
+					d_Minute = d_Hour - *pul_Hour;
+					d_Minute = d_Minute * 60;
+					*pb_Minute = (BYTE) d_Minute;
+
+			    /************************/
+					/* Calculate the second */
+			    /************************/
+
+					d_Second = d_Minute - *pb_Minute;
+					d_Second = d_Second * 60;
+					*pb_Second = (BYTE) d_Second;
+
+			    /*****************************/
+					/* Calculate the mini second */
+			    /*****************************/
+
+					d_MilliSecond = d_Second - *pb_Second;
+					d_MilliSecond = d_MilliSecond * 1000;
+					*pui_MilliSecond = (UINT) d_MilliSecond;
+
+			    /******************************/
+					/* Calculate the micro second */
+			    /******************************/
+
+					d_MicroSecond =
+						d_MilliSecond -
+						*pui_MilliSecond;
+					d_MicroSecond = d_MicroSecond * 1000;
+					*pui_MicroSecond = (UINT) d_MicroSecond;
+
+			    /******************************/
+					/* Calculate the micro second */
+			    /******************************/
+
+					d_NanoSecond =
+						d_MicroSecond -
+						*pui_MicroSecond;
+					d_NanoSecond = d_NanoSecond * 1000;
+					*pui_NanoSecond = (UINT) d_NanoSecond;
+					break;
+				}
+
+				fpu_end();
+			} else {
+		 /*******************************/
+				/* Chronometer not initialised */
+		 /*******************************/
+				DPRINTK("Chronometer not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a Chronometer module */
+	      /******************************************/
+			DPRINTK("The module is not a Chronometer module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s,
+	struct comedi_insn *insn,unsigned int *data)                    |
++----------------------------------------------------------------------------+
+| Task              : Sets the output witch has been passed with the         |
+|                     parameter b_Channel. Setting an output means setting an|
+|                     output high.                                           |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle   : Handle of board APCI-1710      |
+|                     BYTE_ b_ModulNbr      : Selected module number (0 to 3)|
+|                     BYTE_ b_OutputChannel : Selection from digital output  |
+|                           CR_CHAN()                  channel (0 to 2)               |
+|                                              0 : Channel H                 |
+|                                              1 : Channel A                 |
+|                                              2 : Channel B                 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: The selected digital output is wrong               |
+|                     -5: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_SetChronoChlOff                       |
+|                               (BYTE_  b_BoardHandle,                       |
+|                                BYTE_  b_ModulNbr,                          |
+|                                BYTE_  b_OutputChannel)                     |
++----------------------------------------------------------------------------+
+| Task              : Resets the output witch has been passed with the       |
+|                     parameter b_Channel. Resetting an output means setting |
+|                     an output low.                                         |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle   : Handle of board APCI-1710
+                        data[0] : Chl ON, Chl OFF , Chl Read , Port Read
+
+|                     BYTE_ b_ModulNbr  CR_AREF    : Selected module number (0 to 3)|
+|                     BYTE_ b_OutputChannel CR_CHAN : Selection from digital output  |
+|                                             channel (0 to 2)               |
+|                                              0 : Channel H                 |
+|                                              1 : Channel A                 |
+|                                              2 : Channel B                 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: The selected digital output is wrong               |
+|                     -5: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadChronoChlValue                    |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                BYTE_   b_InputChannel,                     |
+|                                PBYTE_ pb_ChannelStatus)                    |
++----------------------------------------------------------------------------+
+| Task              : Return the status from selected digital input          |
+|                     (b_InputChannel) from selected chronometer             |
+|                     module (b_ModulNbr).                                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle   : Handle of board APCI-1710      |
+|                     BYTE_ b_ModulNbr      : Selected module number (0 to 3)|
+|                     BYTE_ b_InputChannel  : Selection from digital input   |
+|                                             channel (0 to 2)               |
+|                                   CR_CHAN()             0 : Channel E               |
+|                                                1 : Channel F               |
+|                                                2 : Channel G               |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_ChannelStatus : Digital input channel status.|
+|                                data[0]                0 : Channel is not active   |
+|                                                1 : Channel is active       |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: The selected digital input is wrong                |
+|                     -5: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadChronoPortValue                   |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                PBYTE_ pb_PortValue)                        |
++----------------------------------------------------------------------------+
+| Task              : Return the status from digital inputs port from        |
+|                     selected  (b_ModulNbr) chronometer module.             |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle   : Handle of board APCI-1710      |
+|                     BYTE_ b_ModulNbr      : Selected module number (0 to 3)|
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_PortValue   : Digital inputs port status.
+|                     data[0]
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a Chronometer module             |
+|                     -4: Chronometer not initialised see function           |
+|                         "i_APCI1710_InitChrono"                            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	BYTE b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType;
+	DWORD dw_Status;
+	PBYTE pb_ChannelStatus;
+	PBYTE pb_PortValue;
+
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	i_ReturnValue = insn->n;
+	b_IOType = (BYTE) data[0];
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if chronometer */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+	      /***********************************/
+			/* Test if chronometer initialised */
+	      /***********************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_ChronoModuleInfo.b_ChronoInit == 1) {
+		 /***********************************/
+				/* Test the digital output channel */
+		 /***********************************/
+				switch (b_IOType) {
+
+				case APCI1710_CHRONO_SET_CHANNELOFF:
+
+					b_OutputChannel =
+						(BYTE) CR_CHAN(insn->chanspec);
+					if (b_OutputChannel <= 2) {
+
+						outl(0, devpriv->s_BoardInfos.
+							ui_Address + 20 +
+							(b_OutputChannel * 4) +
+							(64 * b_ModulNbr));
+					}	// if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2))
+					else {
+		    /****************************************/
+						/* The selected digital output is wrong */
+		    /****************************************/
+
+						DPRINTK("The selected digital output is wrong\n");
+						i_ReturnValue = -4;
+
+					}	// if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2))
+
+					break;
+
+				case APCI1710_CHRONO_SET_CHANNELON:
+
+					b_OutputChannel =
+						(BYTE) CR_CHAN(insn->chanspec);
+					if (b_OutputChannel <= 2) {
+
+						outl(1, devpriv->s_BoardInfos.
+							ui_Address + 20 +
+							(b_OutputChannel * 4) +
+							(64 * b_ModulNbr));
+					}	// if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2))
+					else {
+		    /****************************************/
+						/* The selected digital output is wrong */
+		    /****************************************/
+
+						DPRINTK("The selected digital output is wrong\n");
+						i_ReturnValue = -4;
+
+					}	// if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2))
+
+					break;
+
+				case APCI1710_CHRONO_READ_CHANNEL:
+		 /**********************************/
+					/* Test the digital input channel */
+		 /**********************************/
+					pb_ChannelStatus = (PBYTE) & data[0];
+					b_InputChannel =
+						(BYTE) CR_CHAN(insn->chanspec);
+
+					if (b_InputChannel <= 2) {
+
+						dw_Status =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 12 +
+							(64 * b_ModulNbr));
+
+						*pb_ChannelStatus =
+							(BYTE) (((dw_Status >>
+									b_InputChannel)
+								& 1) ^ 1);
+					}	// if ((b_InputChannel >= 0) && (b_InputChannel <= 2))
+					else {
+		    /***************************************/
+						/* The selected digital input is wrong */
+		    /***************************************/
+
+						DPRINTK("The selected digital input is wrong\n");
+						i_ReturnValue = -4;
+					}	// if ((b_InputChannel >= 0) && (b_InputChannel <= 2))
+
+					break;
+
+				case APCI1710_CHRONO_READ_PORT:
+
+					pb_PortValue = (PBYTE) & data[0];
+
+					dw_Status =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 12 +
+						(64 * b_ModulNbr));
+
+					*pb_PortValue =
+						(BYTE) ((dw_Status & 0x7) ^ 7);
+					break;
+				}
+			} else {
+		 /*******************************/
+				/* Chronometer not initialised */
+		 /*******************************/
+
+				DPRINTK("Chronometer not initialised\n");
+				i_ReturnValue = -5;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a Chronometer module */
+	      /******************************************/
+
+			DPRINTK("The module is not a Chronometer module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}

+ 74 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h

@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_30MHZ			30
+#define APCI1710_33MHZ			33
+#define APCI1710_40MHZ			40
+
+#define APCI1710_SINGLE			0
+#define APCI1710_CONTINUOUS		1
+
+#define APCI1710_CHRONO_PROGRESS_STATUS	0
+#define APCI1710_CHRONO_READVALUE	1
+#define APCI1710_CHRONO_CONVERTVALUE	2
+#define APCI1710_CHRONO_READINTERRUPT	3
+
+#define APCI1710_CHRONO_SET_CHANNELON	0
+#define APCI1710_CHRONO_SET_CHANNELOFF	1
+#define APCI1710_CHRONO_READ_CHANNEL	2
+#define APCI1710_CHRONO_READ_PORT	3
+
+/*
+ * CHRONOMETER INISIALISATION FUNCTION
+ */
+INT i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev,
+					    struct comedi_subdevice *s,
+					    struct comedi_insn *insn,
+					    unsigned int *data);
+
+/*
+ * CHRONOMETER READ FUNCTION
+ */
+INT i_APCI1710_InsnReadChrono(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev,
+				       BYTE b_ModulNbr, PBYTE pb_ChronoStatus);
+
+INT i_APCI1710_ReadChronoValue(struct comedi_device *dev,
+			       BYTE b_ModulNbr,
+			       UINT ui_TimeOut, PBYTE pb_ChronoStatus,
+			       PULONG pul_ChronoValue);
+
+INT i_APCI1710_ConvertChronoValue(struct comedi_device *dev,
+				  BYTE b_ModulNbr,
+				  ULONG ul_ChronoValue,
+				  PULONG pul_Hour,
+				  PBYTE pb_Minute,
+				  PBYTE pb_Second,
+				  PUINT pui_MilliSecond, PUINT pui_MicroSecond,
+				  PUINT pui_NanoSecond);
+
+/*
+ * CHRONOMETER DIGITAL INPUT OUTPUT FUNCTION
+ */
+INT i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,
+				       struct comedi_subdevice *s, struct comedi_insn *insn,
+				       unsigned int *data);

+ 1020 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c

@@ -0,0 +1,1020 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : DIG_IO.C        | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 digital I/O module                          |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 16/06/98 | S. Weber  | Digital input / output implementation          |
+  |----------|-----------|------------------------------------------------|
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "APCI1710_Dig_io.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, |
+|						struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
++----------------------------------------------------------------------------+
+| Task              : Configure the digital I/O operating mode from selected |
+|                     module  (b_ModulNbr). You must calling this function be|
+|                     for you call any other function witch access of digital|
+|                     I/O.                                                   |
++----------------------------------------------------------------------------+
+| Input Parameters  :													     |
+|                  BYTE_ b_ModulNbr      data[0]: Module number to               |
+|                                             configure (0 to 3)             |
+|                     BYTE_ b_ChannelAMode data[1]  : Channel A mode selection       |
+|                                             0 : Channel used for digital   |
+|                                                 input                      |
+|                                             1 : Channel used for digital   |
+|                                                 output                     |
+|                     BYTE_ b_ChannelBMode data[2] : Channel B mode selection       |
+|                                             0 : Channel used for digital   |
+|                                                 input                      |
+|                                             1 : Channel used for digital   |
+|                                                 output					 |
+						data[0]	  memory on/off
+Activates and deactivates the digital output memory.
+						After having      |
+|                 called up this function with memory on,the output you have previously|
+|                     activated with the function are not reset
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a digital I/O module              |
+|                    -4: Bi-directional channel A configuration error        |
+|                    -5: Bi-directional channel B configuration error        |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_ModulNbr, b_ChannelAMode, b_ChannelBMode;
+	BYTE b_MemoryOnOff, b_ConfigType;
+	INT i_ReturnValue = 0;
+	DWORD dw_WriteConfig = 0;
+
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_ConfigType = (BYTE) data[0];	// Memory or  Init
+	b_ChannelAMode = (BYTE) data[1];
+	b_ChannelBMode = (BYTE) data[2];
+	b_MemoryOnOff = (BYTE) data[1];	// if memory operation
+	i_ReturnValue = insn->n;
+
+		/**************************/
+	/* Test the module number */
+		/**************************/
+
+	if (b_ModulNbr >= 4) {
+		DPRINTK("Module Number invalid\n");
+		i_ReturnValue = -2;
+		return i_ReturnValue;
+	}
+	switch (b_ConfigType) {
+	case APCI1710_DIGIO_MEMORYONOFF:
+
+		if (b_MemoryOnOff)	// If Memory ON
+		{
+		 /****************************/
+			/* Set the output memory on */
+		 /****************************/
+
+			devpriv->s_ModuleInfo[b_ModulNbr].
+				s_DigitalIOInfo.b_OutputMemoryEnabled = 1;
+
+		 /***************************/
+			/* Clear the output memory */
+		 /***************************/
+			devpriv->s_ModuleInfo[b_ModulNbr].
+				s_DigitalIOInfo.dw_OutputMemory = 0;
+		} else		// If memory off
+		{
+		 /*****************************/
+			/* Set the output memory off */
+		 /*****************************/
+
+			devpriv->s_ModuleInfo[b_ModulNbr].
+				s_DigitalIOInfo.b_OutputMemoryEnabled = 0;
+		}
+		break;
+
+	case APCI1710_DIGIO_INIT:
+
+	/*******************************/
+		/* Test if digital I/O counter */
+	/*******************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
+
+	/***************************************************/
+			/* Test the bi-directional channel A configuration */
+	/***************************************************/
+
+			if ((b_ChannelAMode == 0) || (b_ChannelAMode == 1)) {
+	/***************************************************/
+				/* Test the bi-directional channel B configuration */
+	/***************************************************/
+
+				if ((b_ChannelBMode == 0)
+					|| (b_ChannelBMode == 1)) {
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_DigitalIOInfo.b_DigitalInit =
+						1;
+
+	/********************************/
+					/* Save channel A configuration */
+	/********************************/
+
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_DigitalIOInfo.
+						b_ChannelAMode = b_ChannelAMode;
+
+	/********************************/
+					/* Save channel B configuration */
+	/********************************/
+
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_DigitalIOInfo.
+						b_ChannelBMode = b_ChannelBMode;
+
+	/*****************************************/
+					/* Set the channel A and B configuration */
+	/*****************************************/
+
+					dw_WriteConfig =
+						(DWORD) (b_ChannelAMode |
+						(b_ChannelBMode * 2));
+
+	/***************************/
+					/* Write the configuration */
+	/***************************/
+
+					outl(dw_WriteConfig,
+						devpriv->s_BoardInfos.
+						ui_Address + 4 +
+						(64 * b_ModulNbr));
+
+				} else {
+	/************************************************/
+					/* Bi-directional channel B configuration error */
+	/************************************************/
+					DPRINTK("Bi-directional channel B configuration error\n");
+					i_ReturnValue = -5;
+				}
+
+			} else {
+	/************************************************/
+				/* Bi-directional channel A configuration error */
+	/************************************************/
+				DPRINTK("Bi-directional channel A configuration error\n");
+				i_ReturnValue = -4;
+
+			}
+
+		} else {
+	/******************************************/
+			/* The module is not a digital I/O module */
+	/******************************************/
+			DPRINTK("The module is not a digital I/O module\n");
+			i_ReturnValue = -3;
+		}
+	}			// end of Switch
+	printk("Return Value %d\n", i_ReturnValue);
+	return i_ReturnValue;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            INPUT FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+
+|INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,comedi_subdevice
+*s,	struct comedi_insn *insn,unsigned int *data)
+
++----------------------------------------------------------------------------+
+| Task              : Read the status from selected digital I/O digital input|
+|                     (b_InputChannel)                                       |
++----------------------------------------------------------------------------|
+
+
+|
+|  BYTE_ b_ModulNbr  CR_AREF(chanspec)          : Selected module number   |
+|                                                   (0 to 3)                 |
+|  BYTE_ b_InputChannel CR_CHAN(chanspec)        : Selection from digital   |
+|                                                   input ( 0 to 6)          |
+|                                                      0 : Channel C         |
+|                                                      1 : Channel D         |
+|                                                      2 : Channel E         |
+|                                                      3 : Channel F         |
+|                                                      4 : Channel G         |
+|                                                      5 : Channel A         |
+|                                                      6 : Channel B
+
+
+	|
++----------------------------------------------------------------------------+
+| Output Parameters :					 data[0]   : Digital input channel    |
+|                                                   status                   |
+|                                                   0 : Channle is not active|
+|                                                   1 : Channle is active    |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a digital I/O module              |
+|                    -4: The selected digital I/O digital input is wrong     |
+|                    -5: Digital I/O not initialised                         |
+|                    -6: The digital channel A is used for output            |
+|                    -7: The digital channel B is used for output            |
++----------------------------------------------------------------------------+
+*/
+
+//_INT_   i_APCI1710_ReadDigitalIOChlValue      (BYTE_    b_BoardHandle,
+//                                             BYTE_    b_ModulNbr,
+//                                             BYTE_    b_InputChannel,
+//
+//                                             PBYTE_  pb_ChannelStatus)
+INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg;
+	BYTE b_ModulNbr, b_InputChannel;
+	PBYTE pb_ChannelStatus;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_InputChannel = (BYTE) CR_CHAN(insn->chanspec);
+	data[0] = 0;
+	pb_ChannelStatus = (PBYTE) & data[0];
+	i_ReturnValue = insn->n;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if digital I/O counter */
+	   /*******************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
+	      /******************************************/
+			/* Test the digital imnput channel number */
+	      /******************************************/
+
+			if (b_InputChannel <= 6) {
+		 /**********************************************/
+				/* Test if the digital I/O module initialised */
+		 /**********************************************/
+
+				if (devpriv->s_ModuleInfo[b_ModulNbr].
+					s_DigitalIOInfo.b_DigitalInit == 1) {
+		    /**********************************/
+					/* Test if channel A or channel B */
+		    /**********************************/
+
+					if (b_InputChannel > 4) {
+		       /*********************/
+						/* Test if channel A */
+		       /*********************/
+
+						if (b_InputChannel == 5) {
+			  /***************************/
+							/* Test the channel A mode */
+			  /***************************/
+
+							if (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								b_ChannelAMode
+								!= 0) {
+			     /********************************************/
+								/* The digital channel A is used for output */
+			     /********************************************/
+
+								i_ReturnValue =
+									-6;
+							}
+						}	// if (b_InputChannel == 5)
+						else {
+			  /***************************/
+							/* Test the channel B mode */
+			  /***************************/
+
+							if (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								b_ChannelBMode
+								!= 0) {
+			     /********************************************/
+								/* The digital channel B is used for output */
+			     /********************************************/
+
+								i_ReturnValue =
+									-7;
+							}
+						}	// if (b_InputChannel == 5)
+					}	// if (b_InputChannel > 4)
+
+		    /***********************/
+					/* Test if error occur */
+		    /***********************/
+
+					if (i_ReturnValue >= 0) {
+		       /**************************/
+						/* Read all digital input */
+		       /**************************/
+
+						//INPDW (ps_APCI1710Variable->
+						//   s_Board [b_BoardHandle].
+						//   s_BoardInfos.
+						//  ui_Address + (64 * b_ModulNbr),
+						// &dw_StatusReg);
+
+						dw_StatusReg =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address +
+							(64 * b_ModulNbr));
+
+						*pb_ChannelStatus =
+							(BYTE) ((dw_StatusReg ^
+								0x1C) >>
+							b_InputChannel) & 1;
+
+					}	// if (i_ReturnValue == 0)
+				} else {
+		    /*******************************/
+					/* Digital I/O not initialised */
+		    /*******************************/
+					DPRINTK("Digital I/O not initialised\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /********************************/
+				/* Selected digital input error */
+		 /********************************/
+				DPRINTK("Selected digital input error\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a digital I/O module */
+	      /******************************************/
+			DPRINTK("The module is not a digital I/O module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            OUTPUT FUNCTIONS                                |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device
+|*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)
+
++----------------------------------------------------------------------------+
+| Task              : Sets or resets the output witch has been passed with the         |
+|                     parameter b_Channel. Setting an output means setting   |
+|                     an ouput high.                                         |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle   : Handle of board APCI-1710      |
+|                     BYTE_ b_ModulNbr (aref )    : Selected module number (0 to 3)|
+|                     BYTE_ b_OutputChannel (CR_CHAN) : Selection from digital output  |
+|                                             channel (0 to 2)               |
+|                                                0 : Channel H               |
+|                                                1 : Channel A               |
+|                                                2 : Channel B               |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a digital I/O module              |
+|                    -4: The selected digital output is wrong                |
+|                    -5: digital I/O not initialised see function            |
+|                        " i_APCI1710_InitDigitalIO"                         |
+|                    -6: The digital channel A is used for input             |
+|                    -7: The digital channel B is used for input
+					 -8: Digital Output Memory OFF.                          |
+|                        Use previously the function                         |
+|                        "i_APCI1710_SetDigitalIOMemoryOn".            |
++----------------------------------------------------------------------------+
+*/
+
+//_INT_   i_APCI1710_SetDigitalIOChlOn    (BYTE_ b_BoardHandle,
+//                                       BYTE_ b_ModulNbr,
+//                                       BYTE_ b_OutputChannel)
+INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_WriteValue = 0;
+	BYTE b_ModulNbr, b_OutputChannel;
+	i_ReturnValue = insn->n;
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_OutputChannel = CR_CHAN(insn->chanspec);
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if digital I/O counter */
+	   /*******************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
+	      /**********************************************/
+			/* Test if the digital I/O module initialised */
+	      /**********************************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_DigitalIOInfo.b_DigitalInit == 1) {
+		 /******************************************/
+				/* Test the digital output channel number */
+		 /******************************************/
+
+				switch (b_OutputChannel) {
+		    /*************/
+					/* Channel H */
+		    /*************/
+
+				case 0:
+					break;
+
+		    /*************/
+					/* Channel A */
+		    /*************/
+
+				case 1:
+					if (devpriv->s_ModuleInfo[b_ModulNbr].
+						s_DigitalIOInfo.
+						b_ChannelAMode != 1) {
+			    /*******************************************/
+						/* The digital channel A is used for input */
+			    /*******************************************/
+
+						i_ReturnValue = -6;
+					}
+					break;
+
+		    /*************/
+					/* Channel B */
+		    /*************/
+
+				case 2:
+					if (devpriv->s_ModuleInfo[b_ModulNbr].
+						s_DigitalIOInfo.
+						b_ChannelBMode != 1) {
+			    /*******************************************/
+						/* The digital channel B is used for input */
+			    /*******************************************/
+
+						i_ReturnValue = -7;
+					}
+					break;
+
+				default:
+			 /****************************************/
+					/* The selected digital output is wrong */
+			 /****************************************/
+
+					i_ReturnValue = -4;
+					break;
+				}
+
+		 /***********************/
+				/* Test if error occur */
+		 /***********************/
+
+				if (i_ReturnValue >= 0) {
+
+			/*********************************/
+					/* Test if set channel ON        */
+		    /*********************************/
+					if (data[0]) {
+		    /*********************************/
+						/* Test if output memory enabled */
+		    /*********************************/
+
+						if (devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_DigitalIOInfo.
+							b_OutputMemoryEnabled ==
+							1) {
+							dw_WriteValue =
+								devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								dw_OutputMemory
+								| (1 <<
+								b_OutputChannel);
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								dw_OutputMemory
+								= dw_WriteValue;
+						} else {
+							dw_WriteValue =
+								1 <<
+								b_OutputChannel;
+						}
+					}	// set channel off
+					else {
+						if (devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_DigitalIOInfo.
+							b_OutputMemoryEnabled ==
+							1) {
+							dw_WriteValue =
+								devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								dw_OutputMemory
+								& (0xFFFFFFFFUL
+								-
+								(1 << b_OutputChannel));
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								dw_OutputMemory
+								= dw_WriteValue;
+						} else {
+		       /*****************************/
+							/* Digital Output Memory OFF */
+		       /*****************************/
+							// +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn"
+							i_ReturnValue = -8;
+						}
+
+					}
+		    /*******************/
+					/* Write the value */
+		    /*******************/
+
+					//OUTPDW (ps_APCI1710Variable->
+					//    s_Board [b_BoardHandle].
+					//   s_BoardInfos.
+					//   ui_Address + (64 * b_ModulNbr),
+					//   dw_WriteValue);
+					outl(dw_WriteValue,
+						devpriv->s_BoardInfos.
+						ui_Address + (64 * b_ModulNbr));
+				}
+			} else {
+		 /*******************************/
+				/* Digital I/O not initialised */
+		 /*******************************/
+
+				i_ReturnValue = -5;
+			}
+		} else {
+	      /******************************************/
+			/* The module is not a digital I/O module */
+	      /******************************************/
+
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+
+|INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,comedi_subdevice
+	*s,	struct comedi_insn *insn,unsigned int *data)
++----------------------------------------------------------------------------+
+| Task              : write:
+					  Sets or resets one or several outputs from port.                 |
+|                     Setting an output means setting an output high.        |
+|                     If you have switched OFF the digital output memory     |
+|                     (OFF), all the other output are set to "0".
+
+|                      read:
+					  Read the status from digital input port                |
+|                     from selected digital I/O module (b_ModulNbr)
++----------------------------------------------------------------------------+
+| Input Parameters  :
+	BYTE_ b_BoardHandle   : Handle of board APCI-1710      |
+|   BYTE_ b_ModulNbr  CR_AREF(aref)    : Selected module number (0 to 3)|
+|   BYTE_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 )
+|                       data[0]           read or write port
+                        data[1]            if write then indicate ON or OFF
+
+                        if read : data[1] will return port status.
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
+
+                INPUT :
+
+					  0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a digital I/O module              |
+|                    -4: Digital I/O not initialised
+
+				OUTPUT:	  0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a digital I/O module              |
+|                    -4: Output value wrong                                  |
+|                    -5: digital I/O not initialised see function            |
+|                        " i_APCI1710_InitDigitalIO"                         |
+|                    -6: The digital channel A is used for input             |
+|                    -7: The digital channel B is used for input
+					-8: Digital Output Memory OFF.                          |
+|                        Use previously the function                         |
+|                        "i_APCI1710_SetDigitalIOMemoryOn".               |
++----------------------------------------------------------------------------+
+*/
+
+//_INT_   i_APCI1710_SetDigitalIOPortOn   (BYTE_ b_BoardHandle,
+//                                       BYTE_ b_ModulNbr,
+//                                       BYTE_ b_PortValue)
+INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_WriteValue = 0;
+	DWORD dw_StatusReg;
+	BYTE b_ModulNbr, b_PortValue;
+	BYTE b_PortOperation, b_PortOnOFF;
+
+	PBYTE pb_PortValue;
+
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_PortOperation = (BYTE) data[0];	// Input or output
+	b_PortOnOFF = (BYTE) data[1];	// if output then On or Off
+	b_PortValue = (BYTE) data[2];	// if out put then Value
+	i_ReturnValue = insn->n;
+	pb_PortValue = (PBYTE) & data[0];
+// if input then read value
+
+	switch (b_PortOperation) {
+	case APCI1710_INPUT:
+	/**************************/
+		/* Test the module number */
+	/**************************/
+
+		if (b_ModulNbr < 4) {
+	   /*******************************/
+			/* Test if digital I/O counter */
+	   /*******************************/
+
+			if ((devpriv->s_BoardInfos.
+					dw_MolduleConfiguration[b_ModulNbr] &
+					0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
+	      /**********************************************/
+				/* Test if the digital I/O module initialised */
+	      /**********************************************/
+
+				if (devpriv->s_ModuleInfo[b_ModulNbr].
+					s_DigitalIOInfo.b_DigitalInit == 1) {
+		 /**************************/
+					/* Read all digital input */
+		 /**************************/
+
+					//INPDW (ps_APCI1710Variable->
+					//      s_Board [b_BoardHandle].
+					//      s_BoardInfos.
+					//      ui_Address + (64 * b_ModulNbr),
+					//      &dw_StatusReg);
+
+					dw_StatusReg =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + (64 * b_ModulNbr));
+					*pb_PortValue =
+						(BYTE) (dw_StatusReg ^ 0x1C);
+
+				} else {
+		 /*******************************/
+					/* Digital I/O not initialised */
+		 /*******************************/
+
+					i_ReturnValue = -4;
+				}
+			} else {
+	      /******************************************/
+				/* The module is not a digital I/O module */
+	      /******************************************/
+
+				i_ReturnValue = -3;
+			}
+		} else {
+	   /***********************/
+			/* Module number error */
+	   /***********************/
+
+			i_ReturnValue = -2;
+		}
+
+		break;
+
+	case APCI1710_OUTPUT:
+	/**************************/
+		/* Test the module number */
+	/**************************/
+
+		if (b_ModulNbr < 4) {
+	   /*******************************/
+			/* Test if digital I/O counter */
+	   /*******************************/
+
+			if ((devpriv->s_BoardInfos.
+					dw_MolduleConfiguration[b_ModulNbr] &
+					0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
+	      /**********************************************/
+				/* Test if the digital I/O module initialised */
+	      /**********************************************/
+
+				if (devpriv->s_ModuleInfo[b_ModulNbr].
+					s_DigitalIOInfo.b_DigitalInit == 1) {
+		 /***********************/
+					/* Test the port value */
+		 /***********************/
+
+					if (b_PortValue <= 7) {
+		    /***********************************/
+						/* Test the digital output channel */
+		    /***********************************/
+
+		    /**************************/
+						/* Test if channel A used */
+		    /**************************/
+
+						if ((b_PortValue & 2) == 2) {
+							if (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								b_ChannelAMode
+								!= 1) {
+			  /*******************************************/
+								/* The digital channel A is used for input */
+			  /*******************************************/
+
+								i_ReturnValue =
+									-6;
+							}
+						}	// if ((b_PortValue & 2) == 2)
+
+		    /**************************/
+						/* Test if channel B used */
+		    /**************************/
+
+						if ((b_PortValue & 4) == 4) {
+							if (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_DigitalIOInfo.
+								b_ChannelBMode
+								!= 1) {
+			  /*******************************************/
+								/* The digital channel B is used for input */
+			  /*******************************************/
+
+								i_ReturnValue =
+									-7;
+							}
+						}	// if ((b_PortValue & 4) == 4)
+
+		    /***********************/
+						/* Test if error occur */
+		    /***********************/
+
+						if (i_ReturnValue >= 0) {
+
+							//if(data[1])
+							//{
+							switch (b_PortOnOFF) {
+			   /*********************************/
+								/* Test if set Port ON                   */
+		       /*********************************/
+
+							case APCI1710_ON:
+
+		       /*********************************/
+								/* Test if output memory enabled */
+		       /*********************************/
+
+								if (devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_DigitalIOInfo.
+									b_OutputMemoryEnabled
+									== 1) {
+									dw_WriteValue
+										=
+										devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_DigitalIOInfo.
+										dw_OutputMemory
+										|
+										b_PortValue;
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_DigitalIOInfo.
+										dw_OutputMemory
+										=
+										dw_WriteValue;
+								} else {
+									dw_WriteValue
+										=
+										b_PortValue;
+								}
+								break;
+
+								// If Set PORT  OFF
+							case APCI1710_OFF:
+
+			   /*********************************/
+								/* Test if output memory enabled */
+		       /*********************************/
+
+								if (devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_DigitalIOInfo.
+									b_OutputMemoryEnabled
+									== 1) {
+									dw_WriteValue
+										=
+										devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_DigitalIOInfo.
+										dw_OutputMemory
+										&
+										(0xFFFFFFFFUL
+										-
+										b_PortValue);
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_DigitalIOInfo.
+										dw_OutputMemory
+										=
+										dw_WriteValue;
+								} else {
+			  /*****************************/
+									/* Digital Output Memory OFF */
+			  /*****************************/
+
+									i_ReturnValue
+										=
+										-8;
+								}
+							}	// switch
+
+		       /*******************/
+							/* Write the value */
+		       /*******************/
+
+							//  OUTPDW (ps_APCI1710Variable->
+							//      s_Board [b_BoardHandle].
+							//      s_BoardInfos.
+							//      ui_Address + (64 * b_ModulNbr),
+							//      dw_WriteValue);
+							outl(dw_WriteValue,
+								devpriv->
+								s_BoardInfos.
+								ui_Address +
+								(64 * b_ModulNbr));
+						}
+					} else {
+		    /**********************/
+						/* Output value wrong */
+		    /**********************/
+
+						i_ReturnValue = -4;
+					}
+				} else {
+		 /*******************************/
+					/* Digital I/O not initialised */
+		 /*******************************/
+
+					i_ReturnValue = -5;
+				}
+			} else {
+	      /******************************************/
+				/* The module is not a digital I/O module */
+	      /******************************************/
+
+				i_ReturnValue = -3;
+			}
+		} else {
+	   /***********************/
+			/* Module number error */
+	   /***********************/
+
+			i_ReturnValue = -2;
+		}
+		break;
+
+	default:
+		i_ReturnValue = -9;
+		DPRINTK("NO INPUT/OUTPUT specified\n");
+	}			//switch INPUT / OUTPUT
+	return (i_ReturnValue);
+}

+ 46 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h

@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_ON			1	/* Digital  Output ON or OFF */
+#define APCI1710_OFF			0
+
+#define APCI1710_INPUT			0	/* Digital I/O */
+#define APCI1710_OUTPUT			1
+
+#define APCI1710_DIGIO_MEMORYONOFF	0x10
+#define APCI1710_DIGIO_INIT		0x11
+
+/*
+ * DIGITAL I/O INISIALISATION FUNCTION
+ */
+INT i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+
+/*
+ * INPUT OUTPUT  FUNCTIONS
+ */
+INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);

+ 5363 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c

@@ -0,0 +1,5363 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : INC_CPT.C       | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 incremental counter module                  |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |----------|-----------|------------------------------------------------|
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+  | 29/06/01 | Guinot C. | - 1100/0231 -> 0701/0232                       |
+  |          |           | See i_APCI1710_DisableFrequencyMeasurement     |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "APCI1710_INCCPT.h"
+
+/*
++----------------------------------------------------------------------------+
+| INT	i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev,struct comedi_subdevice *s,
+struct comedi_insn *insn,unsigned int *data)
+
++----------------------------------------------------------------------------+
+| Task              : Configuration function for INC_CPT                             |
++----------------------------------------------------------------------------+
+| Input Parameters  :														 |
++----------------------------------------------------------------------------+
+| Output Parameters : *data
++----------------------------------------------------------------------------+
+| Return Value      :                 |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigINCCPT(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_ConfigType;
+	INT i_ReturnValue = 0;
+	ui_ConfigType = CR_CHAN(insn->chanspec);
+
+	printk("\nINC_CPT");
+
+	devpriv->tsk_Current = current;	// Save the current process task structure
+	switch (ui_ConfigType) {
+	case APCI1710_INCCPT_INITCOUNTER:
+		i_ReturnValue = i_APCI1710_InitCounter(dev,
+			CR_AREF(insn->chanspec),
+			(BYTE) data[0],
+			(BYTE) data[1],
+			(BYTE) data[2], (BYTE) data[3], (BYTE) data[4]);
+		break;
+
+	case APCI1710_INCCPT_COUNTERAUTOTEST:
+		i_ReturnValue = i_APCI1710_CounterAutoTest(dev,
+			(PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_INITINDEX:
+		i_ReturnValue = i_APCI1710_InitIndex(dev,
+			CR_AREF(insn->chanspec),
+			(BYTE) data[0],
+			(BYTE) data[1], (BYTE) data[2], (BYTE) data[3]);
+		break;
+
+	case APCI1710_INCCPT_INITREFERENCE:
+		i_ReturnValue = i_APCI1710_InitReference(dev,
+			CR_AREF(insn->chanspec), (BYTE) data[0]);
+		break;
+
+	case APCI1710_INCCPT_INITEXTERNALSTROBE:
+		i_ReturnValue = i_APCI1710_InitExternalStrobe(dev,
+			CR_AREF(insn->chanspec),
+			(BYTE) data[0], (BYTE) data[1]);
+		break;
+
+	case APCI1710_INCCPT_INITCOMPARELOGIC:
+		i_ReturnValue = i_APCI1710_InitCompareLogic(dev,
+			CR_AREF(insn->chanspec), (UINT) data[0]);
+		break;
+
+	case APCI1710_INCCPT_INITFREQUENCYMEASUREMENT:
+		i_ReturnValue = i_APCI1710_InitFrequencyMeasurement(dev,
+			CR_AREF(insn->chanspec),
+			(BYTE) data[0],
+			(BYTE) data[1], (ULONG) data[2], (PULONG) & data[0]);
+		break;
+
+	default:
+		printk("Insn Config : Config Parameter Wrong\n");
+
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitCounter                           |
+|                               (BYTE_          b_BoardHandle,               |
+|                                BYTE_          b_ModulNbr,                  |
+|                                BYTE_          b_CounterRange,              |
+|                                BYTE_          b_FirstCounterModus,         |
+|                                BYTE_          b_FirstCounterOption,        |
+|                                BYTE_          b_SecondCounterModus,        |
+|                                BYTE_          b_SecondCounterOption)       |
++----------------------------------------------------------------------------+
+| Task              : Configure the counter operating mode from selected     |
+|                     module (b_ModulNbr). You must calling this function be |
+|                     for you call any other function witch access of        |
+|                     counters.                                              |
+|                                                                            |
+|                          Counter range                                     |
+|                          -------------                                     |
+| +------------------------------------+-----------------------------------+ |
+| | Parameter       Passed value       |        Description                | |
+| |------------------------------------+-----------------------------------| |
+| |b_ModulNbr   APCI1710_16BIT_COUNTER |  The module is configured for     | |
+| |                                    |  two 16-bit counter.              | |
+| |                                    |  - b_FirstCounterModus and        | |
+| |                                    |    b_FirstCounterOption           | |
+| |                                    |    configure the first 16 bit     | |
+| |                                    |    counter.                       | |
+| |                                    |  - b_SecondCounterModus and       | |
+| |                                    |    b_SecondCounterOption          | |
+| |                                    |    configure the second 16 bit    | |
+| |                                    |    counter.                       | |
+| |------------------------------------+-----------------------------------| |
+| |b_ModulNbr   APCI1710_32BIT_COUNTER |  The module is configured for one | |
+| |                                    |  32-bit counter.                  | |
+| |                                    |  - b_FirstCounterModus and        | |
+| |                                    |    b_FirstCounterOption           | |
+| |                                    |    configure the 32 bit counter.  | |
+| |                                    |  - b_SecondCounterModus and       | |
+| |                                    |    b_SecondCounterOption          | |
+| |                                    |    are not used and have no       | |
+| |                                    |    importance.                    | |
+| +------------------------------------+-----------------------------------+ |
+|                                                                            |
+|                      Counter operating mode                                |
+|                      ----------------------                                |
+|                                                                            |
+| +--------------------+-------------------------+-------------------------+ |
+| |    Parameter       |     Passed value        |    Description          | |
+| |--------------------+-------------------------+-------------------------| |
+| |b_FirstCounterModus | APCI1710_QUADRUPLE_MODE | In the quadruple mode,  | |
+| |       or           |                         | the edge analysis       | |
+| |b_SecondCounterModus|                         | circuit generates a     | |
+| |                    |                         | counting pulse from     | |
+| |                    |                         | each edge of 2 signals  | |
+| |                    |                         | which are phase shifted | |
+| |                    |                         | in relation to each     | |
+| |                    |                         | other.                  | |
+| |--------------------+-------------------------+-------------------------| |
+| |b_FirstCounterModus |   APCI1710_DOUBLE_MODE  | Functions in the same   | |
+| |       or           |                         | way as the quadruple    | |
+| |b_SecondCounterModus|                         | mode, except that only  | |
+| |                    |                         | two of the four edges   | |
+| |                    |                         | are analysed per        | |
+| |                    |                         | period                  | |
+| |--------------------+-------------------------+-------------------------| |
+| |b_FirstCounterModus |   APCI1710_SIMPLE_MODE  | Functions in the same   | |
+| |       or           |                         | way as the quadruple    | |
+| |b_SecondCounterModus|                         | mode, except that only  | |
+| |                    |                         | one of the four edges   | |
+| |                    |                         | is analysed per         | |
+| |                    |                         | period.                 | |
+| |--------------------+-------------------------+-------------------------| |
+| |b_FirstCounterModus |   APCI1710_DIRECT_MODE  | In the direct mode the  | |
+| |       or           |                         | both edge analysis      | |
+| |b_SecondCounterModus|                         | circuits are inactive.  | |
+| |                    |                         | The inputs A, B in the  | |
+| |                    |                         | 32-bit mode or A, B and | |
+| |                    |                         | C, D in the 16-bit mode | |
+| |                    |                         | represent, each, one    | |
+| |                    |                         | clock pulse gate circuit| |
+| |                    |                         | There by frequency and  | |
+| |                    |                         | pulse duration          | |
+| |                    |                         | measurements can be     | |
+| |                    |                         | performed.              | |
+| +--------------------+-------------------------+-------------------------+ |
+|                                                                            |
+|                                                                            |
+|       IMPORTANT!                                                           |
+|       If you have configured the module for two 16-bit counter, a mixed    |
+|       mode with a counter in quadruple/double/single mode                  |
+|       and the other counter in direct mode is not possible!                |
+|                                                                            |
+|                                                                            |
+|         Counter operating option for quadruple/double/simple mode          |
+|         ---------------------------------------------------------          |
+|                                                                            |
+| +----------------------+-------------------------+------------------------+|
+| |       Parameter      |     Passed value        |  Description           ||
+| |----------------------+-------------------------+------------------------||
+| |b_FirstCounterOption  | APCI1710_HYSTERESIS_ON  | In both edge analysis  ||
+| |        or            |                         | circuits is available  ||
+| |b_SecondCounterOption |                         | one hysteresis circuit.||
+| |                      |                         | It suppresses each     ||
+| |                      |                         | time the first counting||
+| |                      |                         | pulse after a change   ||
+| |                      |                         | of rotation.           ||
+| |----------------------+-------------------------+------------------------||
+| |b_FirstCounterOption  | APCI1710_HYSTERESIS_OFF | The first counting     ||
+| |       or             |                         | pulse is not suppress  ||
+| |b_SecondCounterOption |                         | after a change of      ||
+| |                      |                         | rotation.              ||
+| +----------------------+-------------------------+------------------------+|
+|                                                                            |
+|                                                                            |
+|       IMPORTANT!                                                           |
+|       This option are only avaible if you have selected the direct mode.   |
+|                                                                            |
+|                                                                            |
+|               Counter operating option for direct mode                     |
+|               ----------------------------------------                     |
+|                                                                            |
+| +----------------------+--------------------+----------------------------+ |
+| |      Parameter       |     Passed value   |       Description          | |
+| |----------------------+--------------------+----------------------------| |
+| |b_FirstCounterOption  | APCI1710_INCREMENT | The counter increment for  | |
+| |       or             |                    | each counting pulse        | |
+| |b_SecondCounterOption |                    |                            | |
+| |----------------------+--------------------+----------------------------| |
+| |b_FirstCounterOption  | APCI1710_DECREMENT | The counter decrement for  | |
+| |       or             |                    | each counting pulse        | |
+| |b_SecondCounterOption |                    |                            | |
+| +----------------------+--------------------+----------------------------+ |
+|                                                                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 3)       |
+|                     BYTE_ b_CounterRange        : Selection form counter   |
+|                                                   range.                   |
+|                     BYTE_ b_FirstCounterModus   : First counter operating  |
+|                                                   mode.                    |
+|                     BYTE_ b_FirstCounterOption  : First counter  option.   |
+|                     BYTE_ b_SecondCounterModus  : Second counter operating |
+|                                                   mode.                    |
+|                     BYTE_ b_SecondCounterOption : Second counter  option.  |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module is not a counter module                  |
+|                    -3: The selected counter range is wrong.                |
+|                    -4: The selected first counter operating mode is wrong. |
+|                    -5: The selected first counter operating option is wrong|
+|                    -6: The selected second counter operating mode is wrong.|
+|                    -7: The selected second counter operating option is     |
+|                        wrong.                                              |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InitCounter(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_CounterRange,
+	BYTE b_FirstCounterModus,
+	BYTE b_FirstCounterOption,
+	BYTE b_SecondCounterModus, BYTE b_SecondCounterOption)
+{
+	INT i_ReturnValue = 0;
+
+	/*******************************/
+	/* Test if incremental counter */
+	/*******************************/
+
+	if ((devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER) {
+	   /**************************/
+		/* Test the counter range */
+	   /**************************/
+
+		if (b_CounterRange == APCI1710_16BIT_COUNTER
+			|| b_CounterRange == APCI1710_32BIT_COUNTER) {
+	      /********************************/
+			/* Test the first counter modus */
+	      /********************************/
+
+			if (b_FirstCounterModus == APCI1710_QUADRUPLE_MODE ||
+				b_FirstCounterModus == APCI1710_DOUBLE_MODE ||
+				b_FirstCounterModus == APCI1710_SIMPLE_MODE ||
+				b_FirstCounterModus == APCI1710_DIRECT_MODE) {
+		 /*********************************/
+				/* Test the first counter option */
+		 /*********************************/
+
+				if ((b_FirstCounterModus == APCI1710_DIRECT_MODE
+						&& (b_FirstCounterOption ==
+							APCI1710_INCREMENT
+							|| b_FirstCounterOption
+							== APCI1710_DECREMENT))
+					|| (b_FirstCounterModus !=
+						APCI1710_DIRECT_MODE
+						&& (b_FirstCounterOption ==
+							APCI1710_HYSTERESIS_ON
+							|| b_FirstCounterOption
+							==
+							APCI1710_HYSTERESIS_OFF)))
+				{
+		    /**************************/
+					/* Test if 16-bit counter */
+		    /**************************/
+
+					if (b_CounterRange ==
+						APCI1710_16BIT_COUNTER) {
+		       /*********************************/
+						/* Test the second counter modus */
+		       /*********************************/
+
+						if ((b_FirstCounterModus !=
+								APCI1710_DIRECT_MODE
+								&&
+								(b_SecondCounterModus
+									==
+									APCI1710_QUADRUPLE_MODE
+									||
+									b_SecondCounterModus
+									==
+									APCI1710_DOUBLE_MODE
+									||
+									b_SecondCounterModus
+									==
+									APCI1710_SIMPLE_MODE))
+							|| (b_FirstCounterModus
+								==
+								APCI1710_DIRECT_MODE
+								&&
+								b_SecondCounterModus
+								==
+								APCI1710_DIRECT_MODE))
+						{
+			  /**********************************/
+							/* Test the second counter option */
+			  /**********************************/
+
+							if ((b_SecondCounterModus == APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_INCREMENT || b_SecondCounterOption == APCI1710_DECREMENT)) || (b_SecondCounterModus != APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_HYSTERESIS_ON || b_SecondCounterOption == APCI1710_HYSTERESIS_OFF))) {
+								i_ReturnValue =
+									0;
+							} else {
+			     /*********************************************************/
+								/* The selected second counter operating option is wrong */
+			     /*********************************************************/
+
+								DPRINTK("The selected second counter operating option is wrong\n");
+								i_ReturnValue =
+									-7;
+							}
+						} else {
+			  /*******************************************************/
+							/* The selected second counter operating mode is wrong */
+			  /*******************************************************/
+
+							DPRINTK("The selected second counter operating mode is wrong\n");
+							i_ReturnValue = -6;
+						}
+					}
+				} else {
+		    /********************************************************/
+					/* The selected first counter operating option is wrong */
+		    /********************************************************/
+
+					DPRINTK("The selected first counter operating option is wrong\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /******************************************************/
+				/* The selected first counter operating mode is wrong */
+		 /******************************************************/
+				DPRINTK("The selected first counter operating mode is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /***************************************/
+			/* The selected counter range is wrong */
+	      /***************************************/
+
+			DPRINTK("The selected counter range is wrong\n");
+			i_ReturnValue = -3;
+		}
+
+	   /*************************/
+		/* Test if a error occur */
+	   /*************************/
+
+		if (i_ReturnValue == 0) {
+	      /**************************/
+			/* Test if 16-Bit counter */
+	      /**************************/
+
+			if (b_CounterRange == APCI1710_32BIT_COUNTER) {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister1 = b_CounterRange |
+					b_FirstCounterModus |
+					b_FirstCounterOption;
+			} else {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister1 = b_CounterRange |
+					(b_FirstCounterModus & 0x5) |
+					(b_FirstCounterOption & 0x20) |
+					(b_SecondCounterModus & 0xA) |
+					(b_SecondCounterOption & 0x40);
+
+		 /***********************/
+				/* Test if direct mode */
+		 /***********************/
+
+				if (b_FirstCounterModus == APCI1710_DIRECT_MODE) {
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister1 = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister1 |
+						APCI1710_DIRECT_MODE;
+				}
+			}
+
+	      /***************************/
+			/* Write the configuration */
+	      /***************************/
+
+			outl(devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				dw_ModeRegister1_2_3_4,
+				devpriv->s_BoardInfos.
+				ui_Address + 20 + (64 * b_ModulNbr));
+
+			devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_CounterInit = 1;
+		}
+	} else {
+	   /**************************************/
+		/* The module is not a counter module */
+	   /**************************************/
+
+		DPRINTK("The module is not a counter module\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_CounterAutoTest                       |
+|                                               (BYTE_     b_BoardHandle,    |
+|                                                PBYTE_   pb_TestStatus)     |
++----------------------------------------------------------------------------+
+| Task              : A test mode is intended for testing the component and  |
+|                     the connected periphery. All the 8-bit counter chains  |
+|                     are operated internally as down counters.              |
+|                     Independently from the external signals,               |
+|                     all the four 8-bit counter chains are decremented in   |
+|                     parallel by each negative clock pulse edge of CLKX.    |
+|                                                                            |
+|                       Counter auto test conclusion                         |
+|                       ----------------------------                         |
+|              +-----------------+-----------------------------+             |
+|              | pb_TestStatus   |    Error description        |             |
+|              |     mask        |                             |             |
+|              |-----------------+-----------------------------|             |
+|              |    0000         |     No error detected       |             |
+|              |-----------------|-----------------------------|             |
+|              |    0001         | Error detected of counter 0 |             |
+|              |-----------------|-----------------------------|             |
+|              |    0010         | Error detected of counter 1 |             |
+|              |-----------------|-----------------------------|             |
+|              |    0100         | Error detected of counter 2 |             |
+|              |-----------------|-----------------------------|             |
+|              |    1000         | Error detected of counter 3 |             |
+|              +-----------------+-----------------------------+             |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle : Handle of board APCI-1710      |  |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_TestStatus  : Auto test conclusion. See table|
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_CounterAutoTest(struct comedi_device * dev, PBYTE pb_TestStatus)
+{
+	BYTE b_ModulCpt = 0;
+	INT i_ReturnValue = 0;
+	DWORD dw_LathchValue;
+
+	*pb_TestStatus = 0;
+
+	/********************************/
+	/* Test if counter module found */
+	/********************************/
+
+	if ((devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[0] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER
+		|| (devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[1] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER
+		|| (devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[2] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER
+		|| (devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[3] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER) {
+		for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) {
+	      /*******************************/
+			/* Test if incremental counter */
+	      /*******************************/
+
+			if ((devpriv->s_BoardInfos.
+					dw_MolduleConfiguration[b_ModulCpt] &
+					0xFFFF0000UL) ==
+				APCI1710_INCREMENTAL_COUNTER) {
+		 /******************/
+				/* Start the test */
+		 /******************/
+
+				outl(3, devpriv->s_BoardInfos.
+					ui_Address + 16 + (64 * b_ModulCpt));
+
+		 /*********************/
+				/* Tatch the counter */
+		 /*********************/
+
+				outl(1, devpriv->s_BoardInfos.
+					ui_Address + (64 * b_ModulCpt));
+
+		 /************************/
+				/* Read the latch value */
+		 /************************/
+
+				dw_LathchValue = inl(devpriv->s_BoardInfos.
+					ui_Address + 4 + (64 * b_ModulCpt));
+
+				if ((dw_LathchValue & 0xFF) !=
+					((dw_LathchValue >> 8) & 0xFF)
+					&& (dw_LathchValue & 0xFF) !=
+					((dw_LathchValue >> 16) & 0xFF)
+					&& (dw_LathchValue & 0xFF) !=
+					((dw_LathchValue >> 24) & 0xFF)) {
+					*pb_TestStatus =
+						*pb_TestStatus | (1 <<
+						b_ModulCpt);
+				}
+
+		 /*****************/
+				/* Stop the test */
+		 /*****************/
+
+				outl(0, devpriv->s_BoardInfos.
+					ui_Address + 16 + (64 * b_ModulCpt));
+			}
+		}
+	} else {
+	   /***************************/
+		/* No counter module found */
+	   /***************************/
+
+		DPRINTK("No counter module found\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitIndex (BYTE_ b_BoardHandle,       |
+|                                                 BYTE_ b_ModulNbr,          |
+|                                                 BYTE_ b_ReferenceAction,   |
+|                                                 BYTE_ b_IndexOperation,    |
+|                                                 BYTE_ b_AutoMode,          |
+|                                                 BYTE_ b_InterruptEnable)   |
++----------------------------------------------------------------------------+
+| Task              : Initialise the index corresponding to the selected     |
+|                     module (b_ModulNbr). If a INDEX flag occur, you have   |
+|                     the possibility to clear the 32-Bit counter or to latch|
+|                     the current 32-Bit value in to the first latch         |
+|                     register. The b_IndexOperation parameter give the      |
+|                     possibility to choice the INDEX action.                |
+|                     If you have enabled the automatic mode, each INDEX     |
+|                     action is cleared automatically, else you must read    |
+|                     the index status ("i_APCI1710_ReadIndexStatus")        |
+|                     after each INDEX action.                               |
+|                                                                            |
+|                                                                            |
+|                               Index action                                 |
+|                               ------------                                 |
+|                                                                            |
+|           +------------------------+------------------------------------+  |
+|           |   b_IndexOperation     |         Operation                  |  |
+|           |------------------------+------------------------------------|  |
+|           |APCI1710_LATCH_COUNTER  | After a index signal, the counter  |  |
+|           |                        | value (32-Bit) is latched in to    |  |
+|           |                        | the first latch register           |  |
+|           |------------------------|------------------------------------|  |
+|           |APCI1710_CLEAR_COUNTER  | After a index signal, the counter  |  |
+|           |                        | value is cleared (32-Bit)          |  |
+|           +------------------------+------------------------------------+  |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
+|                     BYTE_ b_ReferenceAction : Determine if the reference   |
+|                                               must set or no for the       |
+|                                               acceptance from index        |
+|                                               APCI1710_ENABLE :            |
+|                                                  Reference must be set for |
+|                                                  accepted the index        |
+|                                               APCI1710_DISABLE :           |
+|                                                  Reference have not        |
+|                                                  importance                |
+|                     BYTE_ b_IndexOperation  : Index operating mode.        |
+|                                               See table.                   |
+|                     BYTE_ b_AutoMode        : Enable or disable the        |
+|                                               automatic index reset.       |
+|                                               APCI1710_ENABLE :            |
+|                                                 Enable the automatic mode  |
+|                                               APCI1710_DISABLE :           |
+|                                                 Disable the automatic mode |
+|                     BYTE_ b_InterruptEnable : Enable or disable the        |
+|                                               interrupt.                   |
+|                                               APCI1710_ENABLE :            |
+|                                               Enable the interrupt         |
+|                                               APCI1710_DISABLE :           |
+|                                               Disable the interrupt        |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4  The reference action parameter is wrong            |
+|                     -5: The index operating mode parameter is wrong        |
+|                     -6: The auto mode parameter is wrong                   |
+|                     -7: Interrupt parameter is wrong                       |
+|                     -8: Interrupt function not initialised.                |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InitIndex(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_ReferenceAction,
+	BYTE b_IndexOperation, BYTE b_AutoMode, BYTE b_InterruptEnable)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /********************************/
+			/* Test the reference parameter */
+	      /********************************/
+
+			if (b_ReferenceAction == APCI1710_ENABLE ||
+				b_ReferenceAction == APCI1710_DISABLE) {
+		 /****************************/
+				/* Test the index parameter */
+		 /****************************/
+
+				if (b_IndexOperation ==
+					APCI1710_HIGH_EDGE_LATCH_COUNTER
+					|| b_IndexOperation ==
+					APCI1710_LOW_EDGE_LATCH_COUNTER
+					|| b_IndexOperation ==
+					APCI1710_HIGH_EDGE_CLEAR_COUNTER
+					|| b_IndexOperation ==
+					APCI1710_LOW_EDGE_CLEAR_COUNTER
+					|| b_IndexOperation ==
+					APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER
+					|| b_IndexOperation ==
+					APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
+				{
+		    /********************************/
+					/* Test the auto mode parameter */
+		    /********************************/
+
+					if (b_AutoMode == APCI1710_ENABLE ||
+						b_AutoMode == APCI1710_DISABLE)
+					{
+		       /***************************/
+						/* Test the interrupt mode */
+		       /***************************/
+
+						if (b_InterruptEnable ==
+							APCI1710_ENABLE
+							|| b_InterruptEnable ==
+							APCI1710_DISABLE) {
+
+			     /************************************/
+							/* Makte the configuration commando */
+			     /************************************/
+
+							if (b_ReferenceAction ==
+								APCI1710_ENABLE)
+							{
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									|
+									APCI1710_ENABLE_INDEX_ACTION;
+							} else {
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									&
+									APCI1710_DISABLE_INDEX_ACTION;
+							}
+
+			     /****************************************/
+							/* Test if low level latch or/and clear */
+			     /****************************************/
+
+							if (b_IndexOperation ==
+								APCI1710_LOW_EDGE_LATCH_COUNTER
+								||
+								b_IndexOperation
+								==
+								APCI1710_LOW_EDGE_CLEAR_COUNTER
+								||
+								b_IndexOperation
+								==
+								APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
+							{
+				/*************************************/
+								/* Set the index level to low (DQ26) */
+				/*************************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									|
+									APCI1710_SET_LOW_INDEX_LEVEL;
+							} else {
+				/**************************************/
+								/* Set the index level to high (DQ26) */
+				/**************************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									&
+									APCI1710_SET_HIGH_INDEX_LEVEL;
+							}
+
+			     /***********************************/
+							/* Test if latch and clear counter */
+			     /***********************************/
+
+							if (b_IndexOperation ==
+								APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER
+								||
+								b_IndexOperation
+								==
+								APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
+							{
+				/***************************************/
+								/* Set the latch and clear flag (DQ27) */
+				/***************************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									|
+									APCI1710_ENABLE_LATCH_AND_CLEAR;
+							}	// if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
+							else {
+				/*****************************************/
+								/* Clear the latch and clear flag (DQ27) */
+				/*****************************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									&
+									APCI1710_DISABLE_LATCH_AND_CLEAR;
+
+				/*************************/
+								/* Test if latch counter */
+				/*************************/
+
+								if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_COUNTER) {
+				   /*********************************/
+									/* Enable the latch from counter */
+				   /*********************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister2
+										=
+										devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister2
+										|
+										APCI1710_INDEX_LATCH_COUNTER;
+								} else {
+				   /*********************************/
+									/* Enable the clear from counter */
+				   /*********************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister2
+										=
+										devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister2
+										&
+										(~APCI1710_INDEX_LATCH_COUNTER);
+								}
+							}	// // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
+
+							if (b_AutoMode ==
+								APCI1710_DISABLE)
+							{
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									|
+									APCI1710_INDEX_AUTO_MODE;
+							} else {
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister2
+									&
+									(~APCI1710_INDEX_AUTO_MODE);
+							}
+
+							if (b_InterruptEnable ==
+								APCI1710_ENABLE)
+							{
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister3
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister3
+									|
+									APCI1710_ENABLE_INDEX_INT;
+							} else {
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister3
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister3
+									&
+									APCI1710_DISABLE_INDEX_INT;
+							}
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_SiemensCounterInfo.
+								s_InitFlag.
+								b_IndexInit = 1;
+
+						} else {
+			  /********************************/
+							/* Interrupt parameter is wrong */
+			  /********************************/
+							DPRINTK("Interrupt parameter is wrong\n");
+							i_ReturnValue = -7;
+						}
+					} else {
+		       /************************************/
+						/* The auto mode parameter is wrong */
+		       /************************************/
+
+						DPRINTK("The auto mode parameter is wrong\n");
+						i_ReturnValue = -6;
+					}
+				} else {
+		    /***********************************************/
+					/* The index operating mode parameter is wrong */
+		    /***********************************************/
+
+					DPRINTK("The index operating mode parameter is wrong\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /*******************************************/
+				/* The reference action parameter is wrong */
+		 /*******************************************/
+
+				DPRINTK("The reference action parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitReference                         |
+|                                                (BYTE_ b_BoardHandle,       |
+|                                                 BYTE_ b_ModulNbr,          |
+|                                                 BYTE_ b_ReferenceLevel)    |
++----------------------------------------------------------------------------+
+| Task              : Initialise the reference corresponding to the selected |
+|                     module (b_ModulNbr).                                   |
+|                                                                            |
+|                               Reference level                              |
+|                               ---------------                              |
+|             +--------------------+-------------------------+               |
+|             | b_ReferenceLevel   |         Operation       |               |
+|             +--------------------+-------------------------+               |
+|             |   APCI1710_LOW     |  Reference occur if "0" |               |
+|             |--------------------|-------------------------|               |
+|             |   APCI1710_HIGH    |  Reference occur if "1" |               |
+|             +--------------------+-------------------------+               |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
+|                     BYTE_ b_ReferenceLevel  : Reference level.             |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number parameter is wrong      |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Reference level parameter is wrong                 |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InitReference(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_ReferenceLevel)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /**************************************/
+			/* Test the reference level parameter */
+	      /**************************************/
+
+			if (b_ReferenceLevel == 0 || b_ReferenceLevel == 1) {
+				if (b_ReferenceLevel == 1) {
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister2 = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister2 |
+						APCI1710_REFERENCE_HIGH;
+				} else {
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister2 = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister2 &
+						APCI1710_REFERENCE_LOW;
+				}
+
+				outl(devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					dw_ModeRegister1_2_3_4,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_InitFlag.b_ReferenceInit = 1;
+			} else {
+		 /**************************************/
+				/* Reference level parameter is wrong */
+		 /**************************************/
+
+				DPRINTK("Reference level parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_	i_APCI1710_InitExternalStrobe                |
+|					(BYTE_ b_BoardHandle,                |
+|					 BYTE_ b_ModulNbr,                   |
+|					 BYTE_ b_ExternalStrobe,             |
+|					 BYTE_ b_ExternalStrobeLevel)        |
++----------------------------------------------------------------------------+
+| Task              : Initialises the external strobe level corresponding to |
+|		      the selected module (b_ModulNbr).                      |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
+|		      BYTE_ b_ExternalStrobe  : External strobe selection    |
+|						0 : External strobe A        |
+|						1 : External strobe B        |
+|		      BYTE_ b_ExternalStrobeLevel : External strobe level    |
+|						APCI1710_LOW :               |
+|						External latch occurs if "0" |
+|						APCI1710_HIGH :              |
+|						External latch occurs if "1" |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number is wrong                |
+|                     -3: Counter not initialised.                           |
+|			  See function "i_APCI1710_InitCounter"              |
+|                     -4: External strobe selection is wrong                 |
+|                     -5: External strobe level parameter is wrong           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InitExternalStrobe(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_ExternalStrobe, BYTE b_ExternalStrobeLevel)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /**************************************/
+			/* Test the external strobe selection */
+	      /**************************************/
+
+			if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) {
+		 /******************/
+				/* Test the level */
+		 /******************/
+
+				if ((b_ExternalStrobeLevel == APCI1710_HIGH) ||
+					((b_ExternalStrobeLevel == APCI1710_LOW
+							&& (devpriv->
+								s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) >=
+							0x3135))) {
+		    /*****************/
+					/* Set the level */
+		    /*****************/
+
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister4 = (devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister4 & (0xFF -
+							(0x10 << b_ExternalStrobe))) | ((b_ExternalStrobeLevel ^ 1) << (4 + b_ExternalStrobe));
+				} else {
+		    /********************************************/
+					/* External strobe level parameter is wrong */
+		    /********************************************/
+
+					DPRINTK("External strobe level parameter is wrong\n");
+					i_ReturnValue = -5;
+				}
+			}	// if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1)
+			else {
+		 /**************************************/
+				/* External strobe selection is wrong */
+		 /**************************************/
+
+				DPRINTK("External strobe selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1)
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+	/*
+	   +----------------------------------------------------------------------------+
+	   | Function Name     : _INT_ i_APCI1710_InitCompareLogic                      |
+	   |                               (BYTE_   b_BoardHandle,                      |
+	   |                                BYTE_   b_ModulNbr,                         |
+	   |                                UINT_  ui_CompareValue)                     |
+	   +----------------------------------------------------------------------------+
+	   | Task              : Set the 32-Bit compare value. At that moment that the  |
+	   |                     incremental counter arrive to the compare value        |
+	   |                     (ui_CompareValue) a interrupt is generated.            |
+	   +----------------------------------------------------------------------------+
+	   | Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+	   |                     BYTE_  b_ModulNbr       : Module number to configure   |
+	   |                                               (0 to 3)                     |
+	   |                     UINT_ ui_CompareValue   : 32-Bit compare value         |
+	   +----------------------------------------------------------------------------+
+	   | Output Parameters : -
+	   +----------------------------------------------------------------------------+
+	   | Return Value      :  0: No error                                           |
+	   |                     -1: The handle parameter of the board is wrong         |
+	   |                     -2: No counter module found                            |
+	   |                     -3: Counter not initialised see function               |
+	   |                         "i_APCI1710_InitCounter"                           |
+	   +----------------------------------------------------------------------------+
+	 */
+
+INT i_APCI1710_InitCompareLogic(struct comedi_device * dev,
+	BYTE b_ModulNbr, UINT ui_CompareValue)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+
+			outl(ui_CompareValue, devpriv->s_BoardInfos.
+				ui_Address + 28 + (64 * b_ModulNbr));
+
+			devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_CompareLogicInit = 1;
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitFrequencyMeasurement              |
+|				(BYTE_		 b_BoardHandle,              |
+|				 BYTE_		 b_ModulNbr,                 |
+|				 BYTE_		 b_PCIInputClock,            |
+|				 BYTE_		 b_TimingUnity,              |
+|				 ULONG_ 	ul_TimingInterval,           |
+|				 PULONG_       pul_RealTimingInterval)       |
++----------------------------------------------------------------------------+
+| Task              : Sets the time for the frequency measurement.           |
+|		      Configures the selected TOR incremental counter of the |
+|		      selected module (b_ModulNbr). The ul_TimingInterval and|
+|		      ul_TimingUnity determine the time base for the         |
+|		      measurement. The pul_RealTimingInterval returns the    |
+|		      real time value. You must call up this function before |
+|		      you call up any other function which gives access to   |
+|		      the frequency measurement.                             |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+|		      BYTE_  b_ModulNbr	      :	Number of the module to be   |
+|						configured (0 to 3)          |
+|		      BYTE_  b_PCIInputClock  :	Selection of the PCI bus     |
+|						clock                        |
+|						- APCI1710_30MHZ :           |
+|						  The PC has a PCI bus clock |
+|						  of 30 MHz                  |
+|						- APCI1710_33MHZ :           |
+|						  The PC has a PCI bus clock |
+|						  of 33 MHz                  |
+|		      BYTE_  b_TimingUnity    : Base time unit (0 to 2)      |
+|						  0 : ns                     |
+|						  1 : æs                     |
+|						  2 : ms                     |
+|		      ULONG_ ul_TimingInterval: Base time value.             |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_ pul_RealTimingInterval : Real base time value. |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number is wrong                |
+|                     -3: Counter not initialised see function               |
+|			  "i_APCI1710_InitCounter"                           |
+|                     -4: The selected PCI input clock is wrong              |
+|                     -5: Timing unity selection is wrong                    |
+|                     -6: Base timing selection is wrong                     |
+|		      -7: 40MHz quartz not on board                          |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_PCIInputClock,
+	BYTE b_TimingUnity,
+	ULONG ul_TimingInterval, PULONG pul_RealTimingInterval)
+{
+	INT i_ReturnValue = 0;
+	ULONG ul_TimerValue = 0;
+	double d_RealTimingInterval;
+	DWORD dw_Status = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /**************************/
+			/* Test the PCI bus clock */
+	      /**************************/
+
+			if ((b_PCIInputClock == APCI1710_30MHZ) ||
+				(b_PCIInputClock == APCI1710_33MHZ) ||
+				(b_PCIInputClock == APCI1710_40MHZ)) {
+		 /************************/
+				/* Test the timing unit */
+		 /************************/
+
+				if (b_TimingUnity <= 2) {
+		    /**********************************/
+					/* Test the base timing selection */
+		    /**********************************/
+
+					if (((b_PCIInputClock == APCI1710_30MHZ)
+							&& (b_TimingUnity == 0)
+							&& (ul_TimingInterval >=
+								266)
+							&& (ul_TimingInterval <=
+								8738133UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_30MHZ)
+							&& (b_TimingUnity == 1)
+							&& (ul_TimingInterval >=
+								1)
+							&& (ul_TimingInterval <=
+								8738UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_30MHZ)
+							&& (b_TimingUnity == 2)
+							&& (ul_TimingInterval >=
+								1)
+							&& (ul_TimingInterval <=
+								8UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_33MHZ)
+							&& (b_TimingUnity == 0)
+							&& (ul_TimingInterval >=
+								242)
+							&& (ul_TimingInterval <=
+								7943757UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_33MHZ)
+							&& (b_TimingUnity == 1)
+							&& (ul_TimingInterval >=
+								1)
+							&& (ul_TimingInterval <=
+								7943UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_33MHZ)
+							&& (b_TimingUnity == 2)
+							&& (ul_TimingInterval >=
+								1)
+							&& (ul_TimingInterval <=
+								7UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_40MHZ)
+							&& (b_TimingUnity == 0)
+							&& (ul_TimingInterval >=
+								200)
+							&& (ul_TimingInterval <=
+								6553500UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_40MHZ)
+							&& (b_TimingUnity == 1)
+							&& (ul_TimingInterval >=
+								1)
+							&& (ul_TimingInterval <=
+								6553UL))
+						|| ((b_PCIInputClock ==
+								APCI1710_40MHZ)
+							&& (b_TimingUnity == 2)
+							&& (ul_TimingInterval >=
+								1)
+							&& (ul_TimingInterval <=
+								6UL))) {
+		       /**********************/
+						/* Test if 40MHz used */
+		       /**********************/
+
+						if (b_PCIInputClock ==
+							APCI1710_40MHZ) {
+			  /******************************/
+							/* Test if firmware >= Rev1.5 */
+			  /******************************/
+
+							if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3135) {
+			     /*********************************/
+								/* Test if 40MHz quartz on board */
+			     /*********************************/
+
+								/*INPDW (ps_APCI1710Variable->
+								   s_Board [b_BoardHandle].
+								   s_BoardInfos.
+								   ui_Address + 36 + (64 * b_ModulNbr), &dw_Status); */
+								dw_Status =
+									inl
+									(devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 36 +
+									(64 * b_ModulNbr));
+
+			     /******************************/
+								/* Test the quartz flag (DQ0) */
+			     /******************************/
+
+								if ((dw_Status & 1) != 1) {
+				/*****************************/
+									/* 40MHz quartz not on board */
+				/*****************************/
+
+									DPRINTK("40MHz quartz not on board\n");
+									i_ReturnValue
+										=
+										-7;
+								}
+							} else {
+			     /*****************************/
+								/* 40MHz quartz not on board */
+			     /*****************************/
+								DPRINTK("40MHz quartz not on board\n");
+								i_ReturnValue =
+									-7;
+							}
+						}	// if (b_PCIInputClock == APCI1710_40MHZ)
+
+		       /***************************/
+						/* Test if not error occur */
+		       /***************************/
+
+						if (i_ReturnValue == 0) {
+			  /****************************/
+							/* Test the INC_CPT version */
+			  /****************************/
+
+							if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131) {
+
+				/**********************/
+								/* Test if 40MHz used */
+				/**********************/
+
+								if (b_PCIInputClock == APCI1710_40MHZ) {
+				   /*********************************/
+									/* Enable the 40MHz quarz (DQ30) */
+				   /*********************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister4
+										=
+										devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister4
+										|
+										APCI1710_ENABLE_40MHZ_FREQUENCY;
+								}	// if (b_PCIInputClock == APCI1710_40MHZ)
+								else {
+				   /**********************************/
+									/* Disable the 40MHz quarz (DQ30) */
+				   /**********************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister4
+										=
+										devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_SiemensCounterInfo.
+										s_ModeRegister.
+										s_ByteModeRegister.
+										b_ModeRegister4
+										&
+										APCI1710_DISABLE_40MHZ_FREQUENCY;
+
+								}	// if (b_PCIInputClock == APCI1710_40MHZ)
+
+			     /********************************/
+								/* Calculate the division fator */
+			     /********************************/
+
+								fpu_begin();
+								switch (b_TimingUnity) {
+				/******/
+									/* ns */
+				/******/
+
+								case 0:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_TimerValue
+										=
+										(ULONG)
+										(ul_TimingInterval
+										*
+										(0.00025 * b_PCIInputClock));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+										ul_TimerValue
+											=
+											ul_TimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									*pul_RealTimingInterval
+										=
+										(ULONG)
+										(ul_TimerValue
+										/
+										(0.00025 * (double)b_PCIInputClock));
+									d_RealTimingInterval
+										=
+										(double)
+										ul_TimerValue
+										/
+										(0.00025
+										*
+										(double)
+										b_PCIInputClock);
+
+									if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
+										*pul_RealTimingInterval
+											=
+											*pul_RealTimingInterval
+											+
+											1;
+									}
+
+									ul_TimingInterval
+										=
+										ul_TimingInterval
+										-
+										1;
+									ul_TimerValue
+										=
+										ul_TimerValue
+										-
+										2;
+
+									break;
+
+				/******/
+									/* æs */
+				/******/
+
+								case 1:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_TimerValue
+										=
+										(ULONG)
+										(ul_TimingInterval
+										*
+										(0.25 * b_PCIInputClock));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+										ul_TimerValue
+											=
+											ul_TimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									*pul_RealTimingInterval
+										=
+										(ULONG)
+										(ul_TimerValue
+										/
+										(0.25 * (double)b_PCIInputClock));
+									d_RealTimingInterval
+										=
+										(double)
+										ul_TimerValue
+										/
+										(
+										(double)
+										0.25
+										*
+										(double)
+										b_PCIInputClock);
+
+									if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
+										*pul_RealTimingInterval
+											=
+											*pul_RealTimingInterval
+											+
+											1;
+									}
+
+									ul_TimingInterval
+										=
+										ul_TimingInterval
+										-
+										1;
+									ul_TimerValue
+										=
+										ul_TimerValue
+										-
+										2;
+
+									break;
+
+				/******/
+									/* ms */
+				/******/
+
+								case 2:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_TimerValue
+										=
+										ul_TimingInterval
+										*
+										(250.0
+										*
+										b_PCIInputClock);
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+										ul_TimerValue
+											=
+											ul_TimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									*pul_RealTimingInterval
+										=
+										(ULONG)
+										(ul_TimerValue
+										/
+										(250.0 * (double)b_PCIInputClock));
+									d_RealTimingInterval
+										=
+										(double)
+										ul_TimerValue
+										/
+										(250.0
+										*
+										(double)
+										b_PCIInputClock);
+
+									if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
+										*pul_RealTimingInterval
+											=
+											*pul_RealTimingInterval
+											+
+											1;
+									}
+
+									ul_TimingInterval
+										=
+										ul_TimingInterval
+										-
+										1;
+									ul_TimerValue
+										=
+										ul_TimerValue
+										-
+										2;
+
+									break;
+								}
+
+								fpu_end();
+			     /*************************/
+								/* Write the timer value */
+			     /*************************/
+
+								outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 32 + (64 * b_ModulNbr));
+
+			     /*******************************/
+								/* Set the initialisation flag */
+			     /*******************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_InitFlag.
+									b_FrequencyMeasurementInit
+									= 1;
+							} else {
+			     /***************************/
+								/* Counter not initialised */
+			     /***************************/
+
+								DPRINTK("Counter not initialised\n");
+								i_ReturnValue =
+									-3;
+							}
+						}	// if (i_ReturnValue == 0)
+					} else {
+		       /**********************************/
+						/* Base timing selection is wrong */
+		       /**********************************/
+
+						DPRINTK("Base timing selection is wrong\n");
+						i_ReturnValue = -6;
+					}
+				} else {
+		    /***********************************/
+					/* Timing unity selection is wrong */
+		    /***********************************/
+
+					DPRINTK("Timing unity selection is wrong\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /*****************************************/
+				/* The selected PCI input clock is wrong */
+		 /*****************************************/
+
+				DPRINTK("The selected PCI input clock is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*########################################################################### */
+
+							//INSN BITS
+/*########################################################################### */
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT	i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev,struct comedi_subdevice *s,
+struct comedi_insn *insn,unsigned int *data)                   |
++----------------------------------------------------------------------------+
+| Task              : Set & Clear Functions for INC_CPT                                          |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnBitsINCCPT(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_BitsType;
+	INT i_ReturnValue = 0;
+	ui_BitsType = CR_CHAN(insn->chanspec);
+	devpriv->tsk_Current = current;	// Save the current process task structure
+
+	switch (ui_BitsType) {
+	case APCI1710_INCCPT_CLEARCOUNTERVALUE:
+		i_ReturnValue = i_APCI1710_ClearCounterValue(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_CLEARALLCOUNTERVALUE:
+		i_ReturnValue = i_APCI1710_ClearAllCounterValue(dev);
+		break;
+
+	case APCI1710_INCCPT_SETINPUTFILTER:
+		i_ReturnValue = i_APCI1710_SetInputFilter(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) data[0], (BYTE) data[1]);
+		break;
+
+	case APCI1710_INCCPT_LATCHCOUNTER:
+		i_ReturnValue = i_APCI1710_LatchCounter(dev,
+			(BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]);
+		break;
+
+	case APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE:
+		i_ReturnValue = i_APCI1710_SetIndexAndReferenceSource(dev,
+			(BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]);
+		break;
+
+	case APCI1710_INCCPT_SETDIGITALCHLON:
+		i_ReturnValue = i_APCI1710_SetDigitalChlOn(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_SETDIGITALCHLOFF:
+		i_ReturnValue = i_APCI1710_SetDigitalChlOff(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	default:
+		printk("Bits Config Parameter Wrong\n");
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ClearCounterValue                     |
+|                               (BYTE_      b_BoardHandle,                   |
+|                                BYTE_       b_ModulNbr)                     |
++----------------------------------------------------------------------------+
+| Task              : Clear the counter value from selected module           |
+|                     (b_ModulNbr).                                          |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Module number to configure       |
+|                                           (0 to 3)                         |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number parameter is wrong      |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ClearCounterValue(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*********************/
+			/* Clear the counter */
+	      /*********************/
+
+			outl(1, devpriv->s_BoardInfos.
+				ui_Address + 16 + (64 * b_ModulNbr));
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ClearAllCounterValue                  |
+|                               (BYTE_      b_BoardHandle)                   |
++----------------------------------------------------------------------------+
+| Task              : Clear all counter value.                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ClearAllCounterValue(struct comedi_device * dev)
+{
+	BYTE b_ModulCpt = 0;
+	INT i_ReturnValue = 0;
+
+	/********************************/
+	/* Test if counter module found */
+	/********************************/
+
+	if ((devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[0] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER
+		|| (devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[1] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER
+		|| (devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[2] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER
+		|| (devpriv->s_BoardInfos.
+			dw_MolduleConfiguration[3] & 0xFFFF0000UL) ==
+		APCI1710_INCREMENTAL_COUNTER) {
+		for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) {
+	      /*******************************/
+			/* Test if incremental counter */
+	      /*******************************/
+
+			if ((devpriv->s_BoardInfos.
+					dw_MolduleConfiguration[b_ModulCpt] &
+					0xFFFF0000UL) ==
+				APCI1710_INCREMENTAL_COUNTER) {
+		 /*********************/
+				/* Clear the counter */
+		 /*********************/
+
+				outl(1, devpriv->s_BoardInfos.
+					ui_Address + 16 + (64 * b_ModulCpt));
+			}
+		}
+	} else {
+	   /***************************/
+		/* No counter module found */
+	   /***************************/
+
+		DPRINTK("No counter module found\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_SetInputFilter                        |
+|					(BYTE_ b_BoardHandle,                |
+|					 BYTE_ b_Module,                     |
+|					 BYTE_ b_PCIInputClock,              |
+|					 BYTE_ b_Filter)     		     |
++----------------------------------------------------------------------------+
+| Task              : Disable or enable the software filter from selected    |
+|		      module (b_ModulNbr). b_Filter determine the filter time|
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+|		      BYTE_  b_ModulNbr	      :	Number of the module to be   |
+|						configured (0 to 3)          |
+|		      BYTE_  b_PCIInputClock  :	Selection of the PCI bus     |
+|						clock                        |
+|						- APCI1710_30MHZ :           |
+|						  The PC has a PCI bus clock |
+|						  of 30 MHz                  |
+|						- APCI1710_33MHZ :           |
+|						  The PC has a PCI bus clock |
+|						  of 33 MHz                  |
+|						- APCI1710_40MHZ :           |
+|						  The APCI1710 has a 40MHz    |
+|						  quartz		     |
+|		      BYTE_  b_Filter	      : Filter selection             |
+|                                                                            |
+|				30 MHz                                       |
+|				------                                       |
+|					0:  Software filter not used         |
+|					1:  Filter from 266ns  (3.750000MHz) |
+|					2:  Filter from 400ns  (2.500000MHz) |
+|					3:  Filter from 533ns  (1.876170MHz) |
+|					4:  Filter from 666ns  (1.501501MHz) |
+|					5:  Filter from 800ns  (1.250000MHz) |
+|					6:  Filter from 933ns  (1.071800MHz) |
+|					7:  Filter from 1066ns (0.938080MHz) |
+|					8:  Filter from 1200ns (0.833333MHz) |
+|					9:  Filter from 1333ns (0.750000MHz) |
+|					10: Filter from 1466ns (0.682100MHz) |
+|					11: Filter from 1600ns (0.625000MHz) |
+|					12: Filter from 1733ns (0.577777MHz) |
+|					13: Filter from 1866ns (0.535900MHz) |
+|					14: Filter from 2000ns (0.500000MHz) |
+|					15: Filter from 2133ns (0.468800MHz) |
+|									     |
+|				33 MHz                                       |
+|				------                                       |
+|					0:  Software filter not used         |
+|					1:  Filter from 242ns  (4.125000MHz) |
+|					2:  Filter from 363ns  (2.754820MHz) |
+|					3:  Filter from 484ns  (2.066115MHz) |
+|					4:  Filter from 605ns  (1.652892MHz) |
+|					5:  Filter from 726ns  (1.357741MHz) |
+|					6:  Filter from 847ns  (1.180637MHz) |
+|					7:  Filter from 968ns  (1.033055MHz) |
+|					8:  Filter from 1089ns (0.918273MHz) |
+|					9:  Filter from 1210ns (0.826446MHz) |
+|					10: Filter from 1331ns (0.751314MHz) |
+|					11: Filter from 1452ns (0.688705MHz) |
+|					12: Filter from 1573ns (0.635727MHz) |
+|					13: Filter from 1694ns (0.590318MHz) |
+|					14: Filter from 1815ns (0.550964MHz) |
+|					15: Filter from 1936ns (0.516528MHz) |
+|									     |
+|				40 MHz                                       |
+|				------                                       |
+|					0:  Software filter not used         |
+|					1:  Filter from 200ns  (5.000000MHz) |
+|					2:  Filter from 300ns  (3.333333MHz) |
+|					3:  Filter from 400ns  (2.500000MHz) |
+|					4:  Filter from 500ns  (2.000000MHz) |
+|					5:  Filter from 600ns  (1.666666MHz) |
+|					6:  Filter from 700ns  (1.428500MHz) |
+|					7:  Filter from 800ns  (1.250000MHz) |
+|					8:  Filter from 900ns  (1.111111MHz) |
+|					9:  Filter from 1000ns (1.000000MHz) |
+|					10: Filter from 1100ns (0.909090MHz) |
+|					11: Filter from 1200ns (0.833333MHz) |
+|					12: Filter from 1300ns (0.769200MHz) |
+|					13: Filter from 1400ns (0.714200MHz) |
+|					14: Filter from 1500ns (0.666666MHz) |
+|					15: Filter from 1600ns (0.625000MHz) |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number is wrong                |
+|                     -3: The module is not a counter module                 |
+|					  -4: The selected PCI input clock is wrong              |
+|					  -5: The selected filter value is wrong                 |
+|					  -6: 40MHz quartz not on board                          |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_SetInputFilter(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_PCIInputClock, BYTE b_Filter)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if incremental counter */
+	   /*******************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
+	      /******************************/
+			/* Test if firmware >= Rev1.5 */
+	      /******************************/
+
+			if ((devpriv->s_BoardInfos.
+					dw_MolduleConfiguration[b_ModulNbr] &
+					0xFFFF) >= 0x3135) {
+		 /**************************/
+				/* Test the PCI bus clock */
+		 /**************************/
+
+				if ((b_PCIInputClock == APCI1710_30MHZ) ||
+					(b_PCIInputClock == APCI1710_33MHZ) ||
+					(b_PCIInputClock == APCI1710_40MHZ)) {
+		    /*************************/
+					/* Test the filter value */
+		    /*************************/
+
+					if (b_Filter < 16) {
+		       /**********************/
+						/* Test if 40MHz used */
+		       /**********************/
+
+						if (b_PCIInputClock ==
+							APCI1710_40MHZ) {
+			  /*********************************/
+							/* Test if 40MHz quartz on board */
+			  /*********************************/
+
+							dw_Status =
+								inl(devpriv->
+								s_BoardInfos.
+								ui_Address +
+								36 +
+								(64 * b_ModulNbr));
+
+			  /******************************/
+							/* Test the quartz flag (DQ0) */
+			  /******************************/
+
+							if ((dw_Status & 1) !=
+								1) {
+			     /*****************************/
+								/* 40MHz quartz not on board */
+			     /*****************************/
+
+								DPRINTK("40MHz quartz not on board\n");
+								i_ReturnValue =
+									-6;
+							}
+						}	// if (b_PCIInputClock == APCI1710_40MHZ)
+
+		       /***************************/
+						/* Test if error not occur */
+		       /***************************/
+
+						if (i_ReturnValue == 0) {
+			  /**********************/
+							/* Test if 40MHz used */
+			  /**********************/
+
+							if (b_PCIInputClock ==
+								APCI1710_40MHZ)
+							{
+			     /*********************************/
+								/* Enable the 40MHz quarz (DQ31) */
+			     /*********************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									|
+									APCI1710_ENABLE_40MHZ_FILTER;
+
+							}	// if (b_PCIInputClock == APCI1710_40MHZ)
+							else {
+			     /**********************************/
+								/* Disable the 40MHz quarz (DQ31) */
+			     /**********************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_SiemensCounterInfo.
+									s_ModeRegister.
+									s_ByteModeRegister.
+									b_ModeRegister4
+									&
+									APCI1710_DISABLE_40MHZ_FILTER;
+
+							}	// if (b_PCIInputClock == APCI1710_40MHZ)
+
+			  /************************/
+							/* Set the filter value */
+			  /************************/
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_SiemensCounterInfo.
+								s_ModeRegister.
+								s_ByteModeRegister.
+								b_ModeRegister3
+								=
+								(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_SiemensCounterInfo.
+								s_ModeRegister.
+								s_ByteModeRegister.
+								b_ModeRegister3
+								& 0x1F) |
+								((b_Filter &
+									0x7) <<
+								5);
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_SiemensCounterInfo.
+								s_ModeRegister.
+								s_ByteModeRegister.
+								b_ModeRegister4
+								=
+								(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_SiemensCounterInfo.
+								s_ModeRegister.
+								s_ByteModeRegister.
+								b_ModeRegister4
+								& 0xFE) |
+								((b_Filter &
+									0x8) >>
+								3);
+
+			  /***************************/
+							/* Write the configuration */
+			  /***************************/
+
+							outl(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_SiemensCounterInfo.
+								s_ModeRegister.
+								dw_ModeRegister1_2_3_4,
+								devpriv->
+								s_BoardInfos.
+								ui_Address +
+								20 +
+								(64 * b_ModulNbr));
+						}	// if (i_ReturnValue == 0)
+					}	// if (b_Filter < 16)
+					else {
+		       /**************************************/
+						/* The selected filter value is wrong */
+		       /**************************************/
+
+						DPRINTK("The selected filter value is wrong\n");
+						i_ReturnValue = -5;
+					}	// if (b_Filter < 16)
+				}	// if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ))
+				else {
+		    /*****************************************/
+					/* The selected PCI input clock is wrong */
+		    /*****************************************/
+
+					DPRINTK("The selected PCI input clock is wrong\n");
+					i_ReturnValue = 4;
+				}	// if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ))
+			} else {
+		 /**************************************/
+				/* The module is not a counter module */
+		 /**************************************/
+
+				DPRINTK("The module is not a counter module\n");
+				i_ReturnValue = -3;
+			}
+		} else {
+	      /**************************************/
+			/* The module is not a counter module */
+	      /**************************************/
+
+			DPRINTK("The module is not a counter module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_LatchCounter (BYTE_ b_BoardHandle,    |
+|                                                    BYTE_ b_ModulNbr,       |
+|                                                    BYTE_ b_LatchReg)       |
++----------------------------------------------------------------------------+
+| Task              : Latch the courant value from selected module           |
+|                     (b_ModulNbr) in to the selected latch register         |
+|                     (b_LatchReg).                                          |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Module number to configure       |
+|                                           (0 to 3)                         |
+|                     BYTE_ b_LatchReg    : Selected latch register          |
+|                               0 : for the first latch register             |
+|                               1 : for the second latch register            |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: The selected latch register parameter is wrong     |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_LatchCounter(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_LatchReg)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*************************************/
+			/* Test the latch register parameter */
+	      /*************************************/
+
+			if (b_LatchReg < 2) {
+		 /*********************/
+				/* Tatch the counter */
+		 /*********************/
+
+				outl(1 << (b_LatchReg * 4),
+					devpriv->s_BoardInfos.ui_Address +
+					(64 * b_ModulNbr));
+			} else {
+		 /**************************************************/
+				/* The selected latch register parameter is wrong */
+		 /**************************************************/
+
+				DPRINTK("The selected latch register parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_	i_APCI1710_SetIndexAndReferenceSource        |
+|					(BYTE_ b_BoardHandle,                |
+|					 BYTE_ b_ModulNbr,                   |
+|					 BYTE_ b_SourceSelection)            |
++----------------------------------------------------------------------------+
+| Task              : Determine the hardware source for the index and the    |
+|		      reference logic. Per default the index logic is        |
+|		      connected to the difference input C and the reference  |
+|		      logic is connected to the 24V input E                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
+|		      BYTE_ b_SourceSelection : APCI1710_SOURCE_0 :          |
+|						The index logic is connected |
+|						to the difference input C and|
+|						the reference logic is       |
+|						connected to the 24V input E.|
+|						This is the default          |
+|						configuration.               |
+|						APCI1710_SOURCE_1 :          |
+|						The reference logic is       |
+|						connected to the difference  |
+|						input C and the index logic  |
+|						is connected to the 24V      |
+|						input E                      |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|		      -2: The selected module number is wrong                |
+|		      -3: The module is not a counter module.                |
+|		      -4: The source selection is wrong                      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_SourceSelection)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if incremental counter */
+	   /*******************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
+	      /******************************/
+			/* Test if firmware >= Rev1.5 */
+	      /******************************/
+
+			if ((devpriv->s_BoardInfos.
+					dw_MolduleConfiguration[b_ModulNbr] &
+					0xFFFF) >= 0x3135) {
+		 /*****************************/
+				/* Test the source selection */
+		 /*****************************/
+
+				if (b_SourceSelection == APCI1710_SOURCE_0 ||
+					b_SourceSelection == APCI1710_SOURCE_1)
+				{
+		    /******************************************/
+					/* Test if invert the index and reference */
+		    /******************************************/
+
+					if (b_SourceSelection ==
+						APCI1710_SOURCE_1) {
+		       /********************************************/
+						/* Invert index and reference source (DQ25) */
+		       /********************************************/
+
+						devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SiemensCounterInfo.
+							s_ModeRegister.
+							s_ByteModeRegister.
+							b_ModeRegister4 =
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SiemensCounterInfo.
+							s_ModeRegister.
+							s_ByteModeRegister.
+							b_ModeRegister4 |
+							APCI1710_INVERT_INDEX_RFERENCE;
+					} else {
+		       /****************************************/
+						/* Set the default configuration (DQ25) */
+		       /****************************************/
+
+						devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SiemensCounterInfo.
+							s_ModeRegister.
+							s_ByteModeRegister.
+							b_ModeRegister4 =
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SiemensCounterInfo.
+							s_ModeRegister.
+							s_ByteModeRegister.
+							b_ModeRegister4 &
+							APCI1710_DEFAULT_INDEX_RFERENCE;
+					}
+				}	// if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1)
+				else {
+		    /*********************************/
+					/* The source selection is wrong */
+		    /*********************************/
+
+					DPRINTK("The source selection is wrong\n");
+					i_ReturnValue = -4;
+				}	// if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1)
+			} else {
+		 /**************************************/
+				/* The module is not a counter module */
+		 /**************************************/
+
+				DPRINTK("The module is not a counter module\n");
+				i_ReturnValue = -3;
+			}
+		} else {
+	      /**************************************/
+			/* The module is not a counter module */
+	      /**************************************/
+
+			DPRINTK("The module is not a counter module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***************************************/
+		/* The selected module number is wrong */
+	   /***************************************/
+
+		DPRINTK("The selected module number is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_	i_APCI1710_SetDigitalChlOn                   |
+|				   (BYTE_  b_BoardHandle,                    |
+|				    BYTE_  b_ModulNbr)                       |
++----------------------------------------------------------------------------+
+| Task              : Sets the digital output H Setting an output means      |
+|		      setting an ouput high.                                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+|		      BYTE_  b_ModulNbr	      :	Number of the module to be   |
+|						configured (0 to 3)          |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number is wrong                |
+|                     -3: Counter not initialised see function               |
+|			  "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_SetDigitalChlOn(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+			devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.
+				b_ModeRegister3 = devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.b_ModeRegister3 | 0x10;
+
+	      /*********************/
+			/* Set the output On */
+	      /*********************/
+
+			outl(devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
+				ui_Address + 20 + (64 * b_ModulNbr));
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_	i_APCI1710_SetDigitalChlOff                  |
+|				   (BYTE_  b_BoardHandle,                    |
+|				    BYTE_  b_ModulNbr)                       |
++----------------------------------------------------------------------------+
+| Task              : Resets the digital output H. Resetting an output means |
+|		      setting an ouput low.                                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+|		      BYTE_  b_ModulNbr	      :	Number of the module to be   |
+|						configured (0 to 3)          |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: The selected module number is wrong                |
+|                     -3: Counter not initialised see function               |
+|			  "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_SetDigitalChlOff(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+			devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.
+				b_ModeRegister3 = devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.b_ModeRegister3 & 0xEF;
+
+	      /**********************/
+			/* Set the output Off */
+	      /**********************/
+
+			outl(devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
+				ui_Address + 20 + (64 * b_ModulNbr));
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*########################################################################### */
+
+							// INSN WRITE
+/*########################################################################### */
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT	i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev,struct comedi_subdevice *s,
+struct comedi_insn *insn,unsigned int *data)                   |
++----------------------------------------------------------------------------+
+| Task              : Enable Disable functions for INC_CPT                                       |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1710_InsnWriteINCCPT(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_WriteType;
+	INT i_ReturnValue = 0;
+
+	ui_WriteType = CR_CHAN(insn->chanspec);
+	devpriv->tsk_Current = current;	// Save the current process task structure
+
+	switch (ui_WriteType) {
+	case APCI1710_INCCPT_ENABLELATCHINTERRUPT:
+		i_ReturnValue = i_APCI1710_EnableLatchInterrupt(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_DISABLELATCHINTERRUPT:
+		i_ReturnValue = i_APCI1710_DisableLatchInterrupt(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_WRITE16BITCOUNTERVALUE:
+		i_ReturnValue = i_APCI1710_Write16BitCounterValue(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) data[0], (UINT) data[1]);
+		break;
+
+	case APCI1710_INCCPT_WRITE32BITCOUNTERVALUE:
+		i_ReturnValue = i_APCI1710_Write32BitCounterValue(dev,
+			(BYTE) CR_AREF(insn->chanspec), (ULONG) data[0]);
+
+		break;
+
+	case APCI1710_INCCPT_ENABLEINDEX:
+		i_APCI1710_EnableIndex(dev, (BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_DISABLEINDEX:
+		i_ReturnValue = i_APCI1710_DisableIndex(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_ENABLECOMPARELOGIC:
+		i_ReturnValue = i_APCI1710_EnableCompareLogic(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_DISABLECOMPARELOGIC:
+		i_ReturnValue = i_APCI1710_DisableCompareLogic(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	case APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT:
+		i_ReturnValue = i_APCI1710_EnableFrequencyMeasurement(dev,
+			(BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]);
+		break;
+
+	case APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT:
+		i_ReturnValue = i_APCI1710_DisableFrequencyMeasurement(dev,
+			(BYTE) CR_AREF(insn->chanspec));
+		break;
+
+	default:
+		printk("Write Config Parameter Wrong\n");
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_EnableLatchInterrupt                  |
+|                               (BYTE_ b_BoardHandle,                        |
+|                                BYTE_ b_ModulNbr)                           |
++----------------------------------------------------------------------------+
+| Task              : Enable the latch interrupt from selected module        |
+|                     (b_ModulNbr). Each software or hardware latch occur a  |
+|                     interrupt.                                             |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Module number to configure       |
+|                                           (0 to 3)                         |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Interrupt routine not installed see function       |
+|                         "i_APCI1710_SetBoardIntRoutine"                    |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_EnableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+
+		 /********************/
+			/* Enable interrupt */
+		 /********************/
+
+			devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.
+				b_ModeRegister2 = devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.
+				b_ModeRegister2 | APCI1710_ENABLE_LATCH_INT;
+
+		 /***************************/
+			/* Write the configuration */
+		 /***************************/
+
+			outl(devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
+				ui_Address + 20 + (64 * b_ModulNbr));
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_DisableLatchInterrupt                 |
+|                               (BYTE_ b_BoardHandle,                        |
+|                                BYTE_ b_ModulNbr)                           |
++----------------------------------------------------------------------------+
+| Task              : Disable the latch interrupt from selected module       |
+|                     (b_ModulNbr).                                          |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Module number to configure       |
+|                                           (0 to 3)                         |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Interrupt routine not installed see function       |
+|                         "i_APCI1710_SetBoardIntRoutine"                    |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_DisableLatchInterrupt(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+
+		 /***************************/
+			/* Write the configuration */
+		 /***************************/
+
+			outl(devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				dw_ModeRegister1_2_3_4 &
+				((APCI1710_DISABLE_LATCH_INT << 8) | 0xFF),
+				devpriv->s_BoardInfos.ui_Address + 20 +
+				(64 * b_ModulNbr));
+
+			mdelay(1000);
+
+		 /*********************/
+			/* Disable interrupt */
+		 /*********************/
+
+			devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.
+				b_ModeRegister2 = devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_ModeRegister.
+				s_ByteModeRegister.
+				b_ModeRegister2 & APCI1710_DISABLE_LATCH_INT;
+
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_Write16BitCounterValue                |
+|                                               (BYTE_  b_BoardHandle        |
+|                                                BYTE_  b_ModulNbr,          |
+|                                                BYTE_  b_SelectedCounter,   |
+|                                                UINT_ ui_WriteValue)        |
++----------------------------------------------------------------------------+
+| Task              : Write a 16-Bit value (ui_WriteValue) in to the selected|
+|                     16-Bit counter (b_SelectedCounter) from selected module|
+|                     (b_ModulNbr).                                          |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                              (0 to 3)                      |
+|                     BYTE_ b_SelectedCounter : Selected 16-Bit counter      |
+|                                               (0 or 1)                     |
+|                     UINT_ ui_WriteValue     : 16-Bit write value           |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: The selected 16-Bit counter parameter is wrong     |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_Write16BitCounterValue(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_SelectedCounter, UINT ui_WriteValue)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /******************************/
+			/* Test the counter selection */
+	      /******************************/
+
+			if (b_SelectedCounter < 2) {
+		 /*******************/
+				/* Write the value */
+		 /*******************/
+
+				outl((ULONG) ((ULONG) (ui_WriteValue) << (16 *
+							b_SelectedCounter)),
+					devpriv->s_BoardInfos.ui_Address + 8 +
+					(b_SelectedCounter * 4) +
+					(64 * b_ModulNbr));
+			} else {
+		 /**************************************************/
+				/* The selected 16-Bit counter parameter is wrong */
+		 /**************************************************/
+
+				DPRINTK("The selected 16-Bit counter parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_Write32BitCounterValue                |
+|                                               (BYTE_   b_BoardHandle       |
+|                                                BYTE_   b_ModulNbr,         |
+|                                                ULONG_ ul_WriteValue)       |
++----------------------------------------------------------------------------+
+| Task              : Write a 32-Bit value (ui_WriteValue) in to the selected|
+|                     module (b_ModulNbr).                                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                              (0 to 3)                      |
+|                     ULONG_ ul_WriteValue    : 32-Bit write value           |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_Write32BitCounterValue(struct comedi_device * dev,
+	BYTE b_ModulNbr, ULONG ul_WriteValue)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*******************/
+			/* Write the value */
+	      /*******************/
+
+			outl(ul_WriteValue, devpriv->s_BoardInfos.
+				ui_Address + 4 + (64 * b_ModulNbr));
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_EnableIndex (BYTE_  b_BoardHandle,    |
+|                                                   BYTE_  b_ModulNbr)       |
++----------------------------------------------------------------------------+
+| Task              : Enable the INDEX actions                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Index not initialised see function                 |
+|                         "i_APCI1710_InitIndex"                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_EnableIndex(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+	ULONG ul_InterruptLatchReg;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*****************************/
+			/* Test if index initialised */
+	      /*****************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister2 = devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister2 | APCI1710_ENABLE_INDEX;
+
+				ul_InterruptLatchReg =
+					inl(devpriv->s_BoardInfos.ui_Address +
+					24 + (64 * b_ModulNbr));
+
+				outl(devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					dw_ModeRegister1_2_3_4,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+			} else {
+		 /*************************************************************/
+				/* Index not initialised see function "i_APCI1710_InitIndex" */
+		 /*************************************************************/
+
+				DPRINTK("Index not initialised \n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_DisableIndex (BYTE_  b_BoardHandle,   |
+|                                                    BYTE_  b_ModulNbr)      |
++----------------------------------------------------------------------------+
+| Task              : Disable the INDEX actions                              |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Index not initialised see function                 |
+|                         "i_APCI1710_InitIndex"                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_DisableIndex(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*****************************/
+			/* Test if index initialised */
+	      /*****************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister2 = devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister2 &
+					APCI1710_DISABLE_INDEX;
+
+				outl(devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					dw_ModeRegister1_2_3_4,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+			} else {
+		 /*************************************************************/
+				/* Index not initialised see function "i_APCI1710_InitIndex" */
+		 /*************************************************************/
+
+				DPRINTK("Index not initialised  \n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_EnableCompareLogic                    |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr)                         |
++----------------------------------------------------------------------------+
+| Task              : Enable the 32-Bit compare logic. At that moment that   |
+|                     the incremental counter arrive to the compare value a  |
+|                     interrupt is generated.                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+|                     BYTE_  b_ModulNbr       : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Compare logic not initialised.                     |
+|                         See function "i_APCI1710_InitCompareLogic"         |
+|                     -5: Interrupt function not initialised.                |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_EnableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*************************************/
+			/* Test if compare logic initialised */
+	      /*************************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_CompareLogicInit == 1) {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister3 = devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister3 |
+					APCI1710_ENABLE_COMPARE_INT;
+
+		    /***************************/
+				/* Write the configuration */
+		    /***************************/
+
+				outl(devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					dw_ModeRegister1_2_3_4,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+			} else {
+		 /*********************************/
+				/* Compare logic not initialised */
+		 /*********************************/
+
+				DPRINTK("Compare logic not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_DisableCompareLogic                   |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr)                         |
++----------------------------------------------------------------------------+
+| Task              : Disable the 32-Bit compare logic.
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+|                     BYTE_  b_ModulNbr       : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Compare logic not initialised.                     |
+|                         See function "i_APCI1710_InitCompareLogic"         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_DisableCompareLogic(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*************************************/
+			/* Test if compare logic initialised */
+	      /*************************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_CompareLogicInit == 1) {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister3 = devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister3 &
+					APCI1710_DISABLE_COMPARE_INT;
+
+		 /***************************/
+				/* Write the configuration */
+		 /***************************/
+
+				outl(devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					dw_ModeRegister1_2_3_4,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+			} else {
+		 /*********************************/
+				/* Compare logic not initialised */
+		 /*********************************/
+
+				DPRINTK("Compare logic not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+	/*
+	   +----------------------------------------------------------------------------+
+	   | Function Name     : _INT_ i_APCI1710_EnableFrequencyMeasurement            |
+	   |                            (BYTE_   b_BoardHandle,                      |
+	   |                             BYTE_   b_ModulNbr,                         |
+	   |                             BYTE_   b_InterruptEnable)                  |
+	   +----------------------------------------------------------------------------+
+	   | Task              : Enables the frequency measurement function             |
+	   +----------------------------------------------------------------------------+
+	   | Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+	   |                  BYTE_  b_ModulNbr       : Number of the module to be   |
+	   |                                            configured (0 to 3)          |
+	   |                  BYTE_  b_InterruptEnable: Enable or disable the        |
+	   |                                            interrupt.                   |
+	   |                                            APCI1710_ENABLE:             |
+	   |                                            Enable the interrupt         |
+	   |                                            APCI1710_DISABLE:            |
+	   |                                            Disable the interrupt        |
+	   +----------------------------------------------------------------------------+
+	   | Output Parameters : -                                                      |
+	   +----------------------------------------------------------------------------+
+	   | Return Value      :  0: No error                                           |
+	   |                     -1: The handle parameter of the board is wrong         |
+	   |                     -2: The selected module number is wrong                |
+	   |                     -3: Counter not initialised see function               |
+	   |                      "i_APCI1710_InitCounter"                           |
+	   |                     -4: Frequency measurement logic not initialised.       |
+	   |                      See function "i_APCI1710_InitFrequencyMeasurement" |
+	   |                     -5: Interrupt parameter is wrong                       |
+	   |                     -6: Interrupt function not initialised.                |
+	   +----------------------------------------------------------------------------+
+	 */
+
+INT i_APCI1710_EnableFrequencyMeasurement(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_InterruptEnable)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /********************************************/
+			/* Test if frequency mesurement initialised */
+	      /********************************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_FrequencyMeasurementInit == 1) {
+		 /***************************/
+				/* Test the interrupt mode */
+		 /***************************/
+
+				if ((b_InterruptEnable == APCI1710_DISABLE) ||
+					(b_InterruptEnable == APCI1710_ENABLE))
+				{
+
+		       /************************************/
+					/* Enable the frequency measurement */
+		       /************************************/
+
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister3 = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister3 |
+						APCI1710_ENABLE_FREQUENCY;
+
+		       /*********************************************/
+					/* Disable or enable the frequency interrupt */
+		       /*********************************************/
+
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister3 = (devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister3 &
+						APCI1710_DISABLE_FREQUENCY_INT)
+						| (b_InterruptEnable << 3);
+
+		       /***************************/
+					/* Write the configuration */
+		       /***************************/
+
+					outl(devpriv->s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						dw_ModeRegister1_2_3_4,
+						devpriv->s_BoardInfos.
+						ui_Address + 20 +
+						(64 * b_ModulNbr));
+
+					devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SiemensCounterInfo.
+						s_InitFlag.
+						b_FrequencyMeasurementEnable =
+						1;
+				} else {
+		    /********************************/
+					/* Interrupt parameter is wrong */
+		    /********************************/
+
+					DPRINTK("Interrupt parameter is wrong\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /***********************************************/
+				/* Frequency measurement logic not initialised */
+		 /***********************************************/
+
+				DPRINTK("Frequency measurement logic not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+	/*
+	   +----------------------------------------------------------------------------+
+	   | Function Name     : _INT_ i_APCI1710_DisableFrequencyMeasurement           |
+	   |                            (BYTE_   b_BoardHandle,                      |
+	   |                             BYTE_   b_ModulNbr)                         |
+	   +----------------------------------------------------------------------------+
+	   | Task              : Disables the frequency measurement function             |
+	   +----------------------------------------------------------------------------+
+	   | Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+	   |                  BYTE_  b_ModulNbr       : Number of the module to be   |
+	   |                                            configured (0 to 3)          |
+	   +----------------------------------------------------------------------------+
+	   | Output Parameters : -                                                      |
+	   +----------------------------------------------------------------------------+
+	   | Return Value      :  0: No error                                           |
+	   |                     -1: The handle parameter of the board is wrong         |
+	   |                     -2: The selected module number is wrong                |
+	   |                     -3: Counter not initialised see function               |
+	   |                      "i_APCI1710_InitCounter"                           |
+	   |                     -4: Frequency measurement logic not initialised.       |
+	   |                      See function "i_APCI1710_InitFrequencyMeasurement" |
+	   +----------------------------------------------------------------------------+
+	 */
+
+INT i_APCI1710_DisableFrequencyMeasurement(struct comedi_device * dev, BYTE b_ModulNbr)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /********************************************/
+			/* Test if frequency mesurement initialised */
+	      /********************************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_FrequencyMeasurementInit == 1) {
+		 /*************************************/
+				/* Disable the frequency measurement */
+		 /*************************************/
+
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister3 = devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister3 &
+					APCI1710_DISABLE_FREQUENCY
+					// Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared
+					& APCI1710_DISABLE_FREQUENCY_INT;
+				// End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared
+
+		 /***************************/
+				/* Write the configuration */
+		 /***************************/
+
+				outl(devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					dw_ModeRegister1_2_3_4,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+
+		 /*************************************/
+				/* Disable the frequency measurement */
+		 /*************************************/
+
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_InitFlag.
+					b_FrequencyMeasurementEnable = 0;
+			} else {
+		 /***********************************************/
+				/* Frequency measurement logic not initialised */
+		 /***********************************************/
+
+				DPRINTK("Frequency measurement logic not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*########################################################################### */
+
+							// INSN READ
+
+/*########################################################################### */
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT	i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev,struct comedi_subdevice *s,
+struct comedi_insn *insn,unsigned int *data)                   |
++----------------------------------------------------------------------------+
+| Task              : Read and Get functions for INC_CPT                                       |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1710_InsnReadINCCPT(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_ReadType;
+	INT i_ReturnValue = 0;
+
+	ui_ReadType = CR_CHAN(insn->chanspec);
+
+	devpriv->tsk_Current = current;	// Save the current process task structure
+	switch (ui_ReadType) {
+	case APCI1710_INCCPT_READLATCHREGISTERSTATUS:
+		i_ReturnValue = i_APCI1710_ReadLatchRegisterStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) CR_RANGE(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_READLATCHREGISTERVALUE:
+		i_ReturnValue = i_APCI1710_ReadLatchRegisterValue(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) CR_RANGE(insn->chanspec), (PULONG) & data[0]);
+		printk("Latch Register Value %d\n", data[0]);
+		break;
+
+	case APCI1710_INCCPT_READ16BITCOUNTERVALUE:
+		i_ReturnValue = i_APCI1710_Read16BitCounterValue(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) CR_RANGE(insn->chanspec), (PUINT) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_READ32BITCOUNTERVALUE:
+		i_ReturnValue = i_APCI1710_Read32BitCounterValue(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PULONG) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_GETINDEXSTATUS:
+		i_ReturnValue = i_APCI1710_GetIndexStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_GETREFERENCESTATUS:
+		i_ReturnValue = i_APCI1710_GetReferenceStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_GETUASSTATUS:
+		i_ReturnValue = i_APCI1710_GetUASStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_GETCBSTATUS:
+		i_ReturnValue = i_APCI1710_GetCBStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_GET16BITCBSTATUS:
+		i_ReturnValue = i_APCI1710_Get16BitCBStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(PBYTE) & data[0], (PBYTE) & data[1]);
+		break;
+
+	case APCI1710_INCCPT_GETUDSTATUS:
+		i_ReturnValue = i_APCI1710_GetUDStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+
+		break;
+
+	case APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS:
+		i_ReturnValue = i_APCI1710_GetInterruptUDLatchedStatus(dev,
+			(BYTE) CR_AREF(insn->chanspec), (PBYTE) & data[0]);
+		break;
+
+	case APCI1710_INCCPT_READFREQUENCYMEASUREMENT:
+		i_ReturnValue = i_APCI1710_ReadFrequencyMeasurement(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(PBYTE) & data[0],
+			(PBYTE) & data[1], (PULONG) & data[2]);
+		break;
+
+	case APCI1710_INCCPT_READINTERRUPT:
+		data[0] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].b_OldModuleMask;
+		data[1] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].ul_OldInterruptMask;
+		data[2] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
+
+		/**************************/
+		/* Increment the read FIFO */
+		/***************************/
+
+		devpriv->
+			s_InterruptParameters.
+			ui_Read = (devpriv->s_InterruptParameters.
+			ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
+
+		break;
+
+	default:
+		printk("ReadType Parameter wrong\n");
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadLatchRegisterStatus               |
+|                                                   (BYTE_   b_BoardHandle,  |
+|                                                    BYTE_   b_ModulNbr,     |
+|                                                    BYTE_   b_LatchReg,     |
+|                                                    PBYTE_ pb_LatchStatus)  |
++----------------------------------------------------------------------------+
+| Task              : Read the latch register status from selected module    |
+|                     (b_ModulNbr) and selected latch register (b_LatchReg). |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Module number to configure       |
+|                                           (0 to 3)                         |
+|                     BYTE_ b_LatchReg    : Selected latch register          |
+|                               0 : for the first latch register             |
+|                               1 : for the second latch register            |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_LatchStatus :   Latch register status.       |
+|                                               0 : No latch occur           |
+|                                               1 : A software latch occur   |
+|                                               2 : A hardware latch occur   |
+|                                               3 : A software and hardware  |
+|                                                   latch occur              |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: The selected latch register parameter is wrong     |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_LatchReg, PBYTE pb_LatchStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_LatchReg;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*************************************/
+			/* Test the latch register parameter */
+	      /*************************************/
+
+			if (b_LatchReg < 2) {
+				dw_LatchReg = inl(devpriv->s_BoardInfos.
+					ui_Address + (64 * b_ModulNbr));
+
+				*pb_LatchStatus =
+					(BYTE) ((dw_LatchReg >> (b_LatchReg *
+							4)) & 0x3);
+			} else {
+		 /**************************************************/
+				/* The selected latch register parameter is wrong */
+		 /**************************************************/
+
+				DPRINTK("The selected latch register parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadLatchRegisterValue                |
+|                                                   (BYTE_     b_BoardHandle,|
+|                                                    BYTE_     b_ModulNbr,   |
+|                                                    BYTE_     b_LatchReg,   |
+|                                                    PULONG_ pul_LatchValue) |
++----------------------------------------------------------------------------+
+| Task              : Read the latch register value from selected module     |
+|                     (b_ModulNbr) and selected latch register (b_LatchReg). |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Module number to configure       |
+|                                           (0 to 3)                         |
+|                     BYTE_ b_LatchReg    : Selected latch register          |
+|                               0 : for the first latch register             |
+|                               1 : for the second latch register            |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_ pul_LatchValue : Latch register value          |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: The selected latch register parameter is wrong     |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_ReadLatchRegisterValue(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_LatchReg, PULONG pul_LatchValue)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*************************************/
+			/* Test the latch register parameter */
+	      /*************************************/
+
+			if (b_LatchReg < 2) {
+				*pul_LatchValue = inl(devpriv->s_BoardInfos.
+					ui_Address + ((b_LatchReg + 1) * 4) +
+					(64 * b_ModulNbr));
+
+			} else {
+		 /**************************************************/
+				/* The selected latch register parameter is wrong */
+		 /**************************************************/
+
+				DPRINTK("The selected latch register parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_Read16BitCounterValue                 |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_SelectedCounter,        |
+|                                        PUINT_   pui_CounterValue)          |
++----------------------------------------------------------------------------+
+| Task              : Latch the selected 16-Bit counter (b_SelectedCounter)  |
+|                     from selected module (b_ModulNbr) in to the first      |
+|                     latch register and return the latched value.           |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                              (0 to 3)                      |
+|                     BYTE_ b_SelectedCounter : Selected 16-Bit counter      |
+|                                               (0 or 1)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PUINT_ pui_CounterValue : 16-Bit counter value         |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: The selected 16-Bit counter parameter is wrong     |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_Read16BitCounterValue(struct comedi_device * dev,
+	BYTE b_ModulNbr, BYTE b_SelectedCounter, PUINT pui_CounterValue)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_LathchValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /******************************/
+			/* Test the counter selection */
+	      /******************************/
+
+			if (b_SelectedCounter < 2) {
+		 /*********************/
+				/* Latch the counter */
+		 /*********************/
+
+				outl(1, devpriv->s_BoardInfos.
+					ui_Address + (64 * b_ModulNbr));
+
+		 /************************/
+				/* Read the latch value */
+		 /************************/
+
+				dw_LathchValue = inl(devpriv->s_BoardInfos.
+					ui_Address + 4 + (64 * b_ModulNbr));
+
+				*pui_CounterValue =
+					(UINT) ((dw_LathchValue >> (16 *
+							b_SelectedCounter)) &
+					0xFFFFU);
+			} else {
+		 /**************************************************/
+				/* The selected 16-Bit counter parameter is wrong */
+		 /**************************************************/
+
+				DPRINTK("The selected 16-Bit counter parameter is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_Read32BitCounterValue                 |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        PULONG_ pul_CounterValue)           |
++----------------------------------------------------------------------------+
+| Task              : Latch the 32-Bit counter from selected module          |
+|                     (b_ModulNbr) in to the first latch register and return |
+|                     the latched value.                                     |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                              (0 to 3)                      |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pul_CounterValue : 32-Bit counter value       |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_Read32BitCounterValue(struct comedi_device * dev,
+	BYTE b_ModulNbr, PULONG pul_CounterValue)
+{
+	INT i_ReturnValue = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*********************/
+			/* Tatch the counter */
+	      /*********************/
+
+			outl(1, devpriv->s_BoardInfos.
+				ui_Address + (64 * b_ModulNbr));
+
+	      /************************/
+			/* Read the latch value */
+	      /************************/
+
+			*pul_CounterValue = inl(devpriv->s_BoardInfos.
+				ui_Address + 4 + (64 * b_ModulNbr));
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetIndexStatus (BYTE_   b_BoardHandle,|
+|                                                      BYTE_   b_ModulNbr,   |
+|                                                      PBYTE_ pb_IndexStatus)|
++----------------------------------------------------------------------------+
+| Task              : Return the index status                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_IndexStatus   : 0 : No INDEX occur           |
+|                                               1 : A INDEX occur            |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Index not initialised see function                 |
+|                         "i_APCI1710_InitIndex"                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetIndexStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_IndexStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*****************************/
+			/* Test if index initialised */
+	      /*****************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
+				dw_StatusReg = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (64 * b_ModulNbr));
+
+				*pb_IndexStatus = (BYTE) (dw_StatusReg & 1);
+			} else {
+		 /*************************************************************/
+				/* Index not initialised see function "i_APCI1710_InitIndex" */
+		 /*************************************************************/
+
+				DPRINTK("Index not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetReferenceStatus                    |
+|                                                (BYTE_   b_BoardHandle,     |
+|                                                 BYTE_   b_ModulNbr,        |
+|                                                 PBYTE_ pb_ReferenceStatus) |
++----------------------------------------------------------------------------+
+| Task              : Return the reference status                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_ReferenceStatus   : 0 : No REFERENCE occur   |
+|                                                   1 : A REFERENCE occur    |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Reference not initialised see function             |
+|                         "i_APCI1710_InitReference"                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetReferenceStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_ReferenceStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*********************************/
+			/* Test if reference initialised */
+	      /*********************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_ReferenceInit) {
+				dw_StatusReg = inl(devpriv->s_BoardInfos.
+					ui_Address + 24 + (64 * b_ModulNbr));
+
+				*pb_ReferenceStatus =
+					(BYTE) (~dw_StatusReg & 1);
+			} else {
+		 /*********************************************************************/
+				/* Reference not initialised see function "i_APCI1710_InitReference" */
+		 /*********************************************************************/
+
+				DPRINTK("Reference not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetUASStatus                          |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                PBYTE_ pb_UASStatus)                        |
++----------------------------------------------------------------------------+
+| Task              : Return the error signal (UAS) status                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_UASStatus      : 0 : UAS is low "0"          |
+|                                                1 : UAS is high "1"         |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetUASStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_UASStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+			dw_StatusReg = inl(devpriv->s_BoardInfos.
+				ui_Address + 24 + (64 * b_ModulNbr));
+
+			*pb_UASStatus = (BYTE) ((dw_StatusReg >> 1) & 1);
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetCBStatus                           |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                PBYTE_ pb_CBStatus)                         |
++----------------------------------------------------------------------------+
+| Task              : Return the counter overflow status                     |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_CBStatus      : 0 : Counter no overflow      |
+|                                               1 : Counter overflow         |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetCBStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_CBStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+			dw_StatusReg = inl(devpriv->s_BoardInfos.
+				ui_Address + 16 + (64 * b_ModulNbr));
+
+			*pb_CBStatus = (BYTE) (dw_StatusReg & 1);
+
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_Get16BitCBStatus                      |
+|					(BYTE_     b_BoardHandle,            |
+|					 BYTE_     b_ModulNbr,               |
+|					 PBYTE_ pb_CBStatusCounter0,         |
+|					 PBYTE_ pb_CBStatusCounter1)         |
++----------------------------------------------------------------------------+
+| Task              : Returns the counter overflow (counter initialised to   |
+|		      2*16-bit) status from selected incremental counter     |
+|		      module                                                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_CBStatusCounter0 : 0 : No overflow occur for |
+|						       the first 16-bit      |
+|						       counter               |
+|						   1 : Overflow occur for the|
+|						       first 16-bit counter  |
+|		      PBYTE_ pb_CBStatusCounter1 : 0 : No overflow occur for |
+|						       the second 16-bit     |
+|						       counter               |
+|						   1 : Overflow occur for the|
+|						       second 16-bit counter |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Counter not initialised to 2*16-bit mode.          |
+|			  See function "i_APCI1710_InitCounter"              |
+|                     -5: Firmware revision error                            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_Get16BitCBStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_CBStatusCounter0, PBYTE pb_CBStatusCounter1)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /*************************/
+			/* Test if 2*16-Bit mode */
+	      /*************************/
+
+			if ((devpriv->s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister1 & 0x10) == 0x10) {
+		 /*****************************/
+				/* Test the Firmware version */
+		 /*****************************/
+
+				if ((devpriv->s_BoardInfos.
+						dw_MolduleConfiguration
+						[b_ModulNbr] & 0xFFFF) >=
+					0x3136) {
+					dw_StatusReg =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 16 +
+						(64 * b_ModulNbr));
+
+					*pb_CBStatusCounter1 =
+						(BYTE) ((dw_StatusReg >> 0) &
+						1);
+					*pb_CBStatusCounter0 =
+						(BYTE) ((dw_StatusReg >> 1) &
+						1);
+				}	// if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136)
+				else {
+		    /****************************/
+					/* Firmware revision error  */
+		    /****************************/
+
+					i_ReturnValue = -5;
+				}	// if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136)
+			}	// if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10)
+			else {
+		 /********************************************/
+				/* Counter not initialised to 2*16-bit mode */
+				/* "i_APCI1710_InitCounter"                 */
+		 /********************************************/
+
+				DPRINTK("Counter not initialised\n");
+				i_ReturnValue = -4;
+			}	// if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10)
+		}		// if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1)
+		else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}		// if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1)
+	}			// if (b_ModulNbr < 4)
+	else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}			// if (b_ModulNbr < 4)
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetUDStatus                           |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                PBYTE_ pb_UDStatus)                         |
++----------------------------------------------------------------------------+
+| Task              : Return the counter progress status                     |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_UDStatus      : 0 : Counter progress in the  |
+|                                                   selected mode down       |
+|                                               1 : Counter progress in the  |
+|                                                   selected mode up         |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetUDStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_UDStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+			dw_StatusReg = inl(devpriv->s_BoardInfos.
+				ui_Address + 24 + (64 * b_ModulNbr));
+
+			*pb_UDStatus = (BYTE) ((dw_StatusReg >> 2) & 1);
+
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetInterruptUDLatchedStatus           |
+|                               (BYTE_   b_BoardHandle,                      |
+|                                BYTE_   b_ModulNbr,                         |
+|                                PBYTE_ pb_UDStatus)                         |
++----------------------------------------------------------------------------+
+| Task              : Return the counter progress latched status after a     |
+|                     index interrupt occur.                                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Module number to configure   |
+|                                               (0 to 3)                     |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_UDStatus      : 0 : Counter progress in the  |
+|                                                   selected mode down       |
+|                                               1 : Counter progress in the  |
+|                                                   selected mode up         |
+|                                               2 : No index interrupt occur |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: No counter module found                            |
+|                     -3: Counter not initialised see function               |
+|                         "i_APCI1710_InitCounter"                           |
+|                     -4: Interrupt function not initialised.                |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device * dev,
+	BYTE b_ModulNbr, PBYTE pb_UDStatus)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+		 /*********************************/
+			/* Test if index interrupt occur */
+		 /*********************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_IndexInterruptOccur == 1) {
+				devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_InitFlag.b_IndexInterruptOccur = 0;
+
+				dw_StatusReg = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (64 * b_ModulNbr));
+
+				*pb_UDStatus = (BYTE) ((dw_StatusReg >> 1) & 1);
+			} else {
+		    /****************************/
+				/* No index interrupt occur */
+		    /****************************/
+
+				*pb_UDStatus = 2;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+	/*
+	   +----------------------------------------------------------------------------+
+	   | Function Name     : _INT_ i_APCI1710_ReadFrequencyMeasurement              |
+	   |                            (BYTE_            b_BoardHandle,             |
+	   |                             BYTE_            b_ModulNbr,                |
+	   |                             PBYTE_          pb_Status,                  |
+	   |                             PULONG_        pul_ReadValue)               |
+	   +----------------------------------------------------------------------------+
+	   | Task              : Returns the status (pb_Status) and the number of       |
+	   |                  increments in the set time.                            |
+	   |                  See function " i_APCI1710_InitFrequencyMeasurement "   |
+	   +----------------------------------------------------------------------------+
+	   | Input Parameters  : BYTE_  b_BoardHandle    : Handle of board APCI-1710    |
+	   |                  BYTE_  b_ModulNbr       : Number of the module to be   |
+	   |                                            configured (0 to 3)          |
+	   +----------------------------------------------------------------------------+
+	   | Output Parameters : PBYTE_ pb_Status     : Returns the frequency        |
+	   |                                            measurement status           |
+	   |                                            0 : Counting cycle not       |
+	   |                                                started.                 |
+	   |                                            1 : Counting cycle started.  |
+	   |                                            2 : Counting cycle stopped.  |
+	   |                                                The measurement cycle is |
+	   |                                                completed.               |
+	   |                  PBYTE_ pb_UDStatus      : 0 : Counter progress in the  |
+	   |                                                   selected mode down       |
+	   |                                               1 : Counter progress in the  |
+	   |                                                   selected mode up         |
+	   |                  PULONG_ pul_ReadValue   : Return the number of         |
+	   |                                            increments in the defined    |
+	   |                                            time base.                   |
+	   +----------------------------------------------------------------------------+
+	   | Return Value      :  0: No error                                           |
+	   |                     -1: The handle parameter of the board is wrong         |
+	   |                     -2: The selected module number is wrong                |
+	   |                     -3: Counter not initialised see function               |
+	   |                      "i_APCI1710_InitCounter"                           |
+	   |                     -4: Frequency measurement logic not initialised.       |
+	   |                      See function "i_APCI1710_InitFrequencyMeasurement" |
+	   +----------------------------------------------------------------------------+
+	 */
+
+INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	PBYTE pb_Status, PBYTE pb_UDStatus, PULONG pul_ReadValue)
+{
+	INT i_ReturnValue = 0;
+	UINT ui_16BitValue;
+	DWORD dw_StatusReg;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /*******************************/
+		/* Test if counter initialised */
+	   /*******************************/
+
+		if (devpriv->
+			s_ModuleInfo[b_ModulNbr].
+			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
+	      /********************************************/
+			/* Test if frequency mesurement initialised */
+	      /********************************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_SiemensCounterInfo.
+				s_InitFlag.b_FrequencyMeasurementInit == 1) {
+		 /******************/
+				/* Test if enable */
+		 /******************/
+
+				if (devpriv->
+					s_ModuleInfo[b_ModulNbr].
+					s_SiemensCounterInfo.
+					s_InitFlag.
+					b_FrequencyMeasurementEnable == 1) {
+		    /*******************/
+					/* Read the status */
+		    /*******************/
+
+					dw_StatusReg =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 32 +
+						(64 * b_ModulNbr));
+
+		    /**************************/
+					/* Test if frequency stop */
+		    /**************************/
+
+					if (dw_StatusReg & 1) {
+						*pb_Status = 2;
+						*pb_UDStatus =
+							(BYTE) ((dw_StatusReg >>
+								1) & 3);
+
+		       /******************/
+						/* Read the value */
+		       /******************/
+
+						*pul_ReadValue =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 28 +
+							(64 * b_ModulNbr));
+
+						if (*pb_UDStatus == 0) {
+			  /*************************/
+							/* Test the counter mode */
+			  /*************************/
+
+							if ((devpriv->s_ModuleInfo[b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & APCI1710_16BIT_COUNTER) == APCI1710_16BIT_COUNTER) {
+			     /****************************************/
+								/* Test if 16-bit counter 1 pulse occur */
+			     /****************************************/
+
+								if ((*pul_ReadValue & 0xFFFFU) != 0) {
+									ui_16BitValue
+										=
+										(UINT)
+										*
+										pul_ReadValue
+										&
+										0xFFFFU;
+									*pul_ReadValue
+										=
+										(*pul_ReadValue
+										&
+										0xFFFF0000UL)
+										|
+										(0xFFFFU
+										-
+										ui_16BitValue);
+								}
+
+			     /****************************************/
+								/* Test if 16-bit counter 2 pulse occur */
+			     /****************************************/
+
+								if ((*pul_ReadValue & 0xFFFF0000UL) != 0) {
+									ui_16BitValue
+										=
+										(UINT)
+										(
+										(*pul_ReadValue
+											>>
+											16)
+										&
+										0xFFFFU);
+									*pul_ReadValue
+										=
+										(*pul_ReadValue
+										&
+										0xFFFFUL)
+										|
+										(
+										(0xFFFFU - ui_16BitValue) << 16);
+								}
+							} else {
+								if (*pul_ReadValue != 0) {
+									*pul_ReadValue
+										=
+										0xFFFFFFFFUL
+										-
+										*pul_ReadValue;
+								}
+							}
+						} else {
+							if (*pb_UDStatus == 1) {
+			     /****************************************/
+								/* Test if 16-bit counter 2 pulse occur */
+			     /****************************************/
+
+								if ((*pul_ReadValue & 0xFFFF0000UL) != 0) {
+									ui_16BitValue
+										=
+										(UINT)
+										(
+										(*pul_ReadValue
+											>>
+											16)
+										&
+										0xFFFFU);
+									*pul_ReadValue
+										=
+										(*pul_ReadValue
+										&
+										0xFFFFUL)
+										|
+										(
+										(0xFFFFU - ui_16BitValue) << 16);
+								}
+							} else {
+								if (*pb_UDStatus
+									== 2) {
+				/****************************************/
+									/* Test if 16-bit counter 1 pulse occur */
+				/****************************************/
+
+									if ((*pul_ReadValue & 0xFFFFU) != 0) {
+										ui_16BitValue
+											=
+											(UINT)
+											*
+											pul_ReadValue
+											&
+											0xFFFFU;
+										*pul_ReadValue
+											=
+											(*pul_ReadValue
+											&
+											0xFFFF0000UL)
+											|
+											(0xFFFFU
+											-
+											ui_16BitValue);
+									}
+								}
+							}
+						}
+					} else {
+						*pb_Status = 1;
+						*pb_UDStatus = 0;
+					}
+				} else {
+					*pb_Status = 0;
+					*pb_UDStatus = 0;
+				}
+			} else {
+		 /***********************************************/
+				/* Frequency measurement logic not initialised */
+		 /***********************************************/
+
+				DPRINTK("Frequency measurement logic not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /****************************************/
+			/* Counter not initialised see function */
+			/* "i_APCI1710_InitCounter"             */
+	      /****************************************/
+
+			DPRINTK("Counter not initialised\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*************************************************/
+		/* The selected module number parameter is wrong */
+	   /*************************************************/
+
+		DPRINTK("The selected module number parameter is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}

+ 271 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h

@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_16BIT_COUNTER			0x10
+#define APCI1710_32BIT_COUNTER			0x0
+#define APCI1710_QUADRUPLE_MODE			0x0
+#define APCI1710_DOUBLE_MODE			0x3
+#define APCI1710_SIMPLE_MODE			0xF
+#define APCI1710_DIRECT_MODE			0x80
+#define APCI1710_HYSTERESIS_ON			0x60
+#define APCI1710_HYSTERESIS_OFF			0x0
+#define APCI1710_INCREMENT			0x60
+#define APCI1710_DECREMENT			0x0
+#define APCI1710_LATCH_COUNTER			0x1
+#define APCI1710_CLEAR_COUNTER			0x0
+#define APCI1710_LOW				0x0
+#define APCI1710_HIGH				0x1
+
+/*********************/
+/* Version 0600-0229 */
+/*********************/
+#define APCI1710_HIGH_EDGE_CLEAR_COUNTER		0x0
+#define APCI1710_HIGH_EDGE_LATCH_COUNTER		0x1
+#define APCI1710_LOW_EDGE_CLEAR_COUNTER			0x2
+#define APCI1710_LOW_EDGE_LATCH_COUNTER			0x3
+#define APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER	0x4
+#define APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER	0x5
+#define APCI1710_SOURCE_0				0x0
+#define APCI1710_SOURCE_1				0x1
+
+#define APCI1710_30MHZ				30
+#define APCI1710_33MHZ				33
+#define APCI1710_40MHZ				40
+
+#define APCI1710_ENABLE_LATCH_INT    		0x80
+#define APCI1710_DISABLE_LATCH_INT   		(~APCI1710_ENABLE_LATCH_INT)
+
+#define APCI1710_INDEX_LATCH_COUNTER		0x10
+#define APCI1710_INDEX_AUTO_MODE		0x8
+#define APCI1710_ENABLE_INDEX			0x4
+#define APCI1710_DISABLE_INDEX			(~APCI1710_ENABLE_INDEX)
+#define APCI1710_ENABLE_LATCH_AND_CLEAR		0x8
+#define APCI1710_DISABLE_LATCH_AND_CLEAR	(~APCI1710_ENABLE_LATCH_AND_CLEAR)
+#define APCI1710_SET_LOW_INDEX_LEVEL		0x4
+#define APCI1710_SET_HIGH_INDEX_LEVEL		(~APCI1710_SET_LOW_INDEX_LEVEL)
+#define APCI1710_INVERT_INDEX_RFERENCE		0x2
+#define APCI1710_DEFAULT_INDEX_RFERENCE         (~APCI1710_INVERT_INDEX_RFERENCE)
+
+#define APCI1710_ENABLE_INDEX_INT		0x1
+#define APCI1710_DISABLE_INDEX_INT		(~APCI1710_ENABLE_INDEX_INT)
+
+#define APCI1710_ENABLE_FREQUENCY		0x4
+#define APCI1710_DISABLE_FREQUENCY		(~APCI1710_ENABLE_FREQUENCY)
+
+#define APCI1710_ENABLE_FREQUENCY_INT		0x8
+#define APCI1710_DISABLE_FREQUENCY_INT		(~APCI1710_ENABLE_FREQUENCY_INT)
+
+#define APCI1710_ENABLE_40MHZ_FREQUENCY		0x40
+#define APCI1710_DISABLE_40MHZ_FREQUENCY	(~APCI1710_ENABLE_40MHZ_FREQUENCY)
+
+#define APCI1710_ENABLE_40MHZ_FILTER		0x80
+#define APCI1710_DISABLE_40MHZ_FILTER		(~APCI1710_ENABLE_40MHZ_FILTER)
+
+#define APCI1710_ENABLE_COMPARE_INT		0x2
+#define APCI1710_DISABLE_COMPARE_INT		(~APCI1710_ENABLE_COMPARE_INT)
+
+#define APCI1710_ENABLE_INDEX_ACTION		0x20
+#define APCI1710_DISABLE_INDEX_ACTION		(~APCI1710_ENABLE_INDEX_ACTION)
+#define APCI1710_REFERENCE_HIGH			0x40
+#define APCI1710_REFERENCE_LOW			(~APCI1710_REFERENCE_HIGH)
+
+#define APCI1710_TOR_GATE_LOW			0x40
+#define APCI1710_TOR_GATE_HIGH			(~APCI1710_TOR_GATE_LOW)
+
+/* INSN CONFIG */
+#define	APCI1710_INCCPT_INITCOUNTER				100
+#define APCI1710_INCCPT_COUNTERAUTOTEST				101
+#define APCI1710_INCCPT_INITINDEX				102
+#define APCI1710_INCCPT_INITREFERENCE				103
+#define APCI1710_INCCPT_INITEXTERNALSTROBE			104
+#define APCI1710_INCCPT_INITCOMPARELOGIC			105
+#define APCI1710_INCCPT_INITFREQUENCYMEASUREMENT		106
+
+/* INSN READ */
+#define APCI1710_INCCPT_READLATCHREGISTERSTATUS			200
+#define APCI1710_INCCPT_READLATCHREGISTERVALUE			201
+#define APCI1710_INCCPT_READ16BITCOUNTERVALUE			202
+#define APCI1710_INCCPT_READ32BITCOUNTERVALUE			203
+#define APCI1710_INCCPT_GETINDEXSTATUS				204
+#define APCI1710_INCCPT_GETREFERENCESTATUS			205
+#define APCI1710_INCCPT_GETUASSTATUS				206
+#define APCI1710_INCCPT_GETCBSTATUS				207
+#define APCI1710_INCCPT_GET16BITCBSTATUS			208
+#define APCI1710_INCCPT_GETUDSTATUS				209
+#define APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS		210
+#define APCI1710_INCCPT_READFREQUENCYMEASUREMENT		211
+#define APCI1710_INCCPT_READINTERRUPT				212
+
+/* INSN BITS */
+#define APCI1710_INCCPT_CLEARCOUNTERVALUE			300
+#define APCI1710_INCCPT_CLEARALLCOUNTERVALUE			301
+#define APCI1710_INCCPT_SETINPUTFILTER				302
+#define APCI1710_INCCPT_LATCHCOUNTER				303
+#define APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE		304
+#define APCI1710_INCCPT_SETDIGITALCHLON				305
+#define APCI1710_INCCPT_SETDIGITALCHLOFF			306
+
+/* INSN WRITE */
+#define APCI1710_INCCPT_ENABLELATCHINTERRUPT			400
+#define APCI1710_INCCPT_DISABLELATCHINTERRUPT			401
+#define APCI1710_INCCPT_WRITE16BITCOUNTERVALUE			402
+#define APCI1710_INCCPT_WRITE32BITCOUNTERVALUE			403
+#define APCI1710_INCCPT_ENABLEINDEX				404
+#define APCI1710_INCCPT_DISABLEINDEX				405
+#define APCI1710_INCCPT_ENABLECOMPARELOGIC			406
+#define APCI1710_INCCPT_DISABLECOMPARELOGIC			407
+#define APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT		408
+#define APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT		409
+
+/************ Main Functions *************/
+INT i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int * data);
+
+INT i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, struct comedi_subdevice * s,
+			      struct comedi_insn *insn, unsigned int * data);
+
+INT i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, struct comedi_subdevice * s,
+			       struct comedi_insn *insn, unsigned int * data);
+
+INT i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, struct comedi_subdevice * s,
+			      struct comedi_insn *insn, unsigned int * data);
+
+/*********** Supplementary Functions********/
+
+/* INSN CONFIG */
+INT i_APCI1710_InitCounter(struct comedi_device *dev,
+			   BYTE b_ModulNbr,
+			   BYTE b_CounterRange,
+			   BYTE b_FirstCounterModus,
+			   BYTE b_FirstCounterOption,
+			   BYTE b_SecondCounterModus,
+			   BYTE b_SecondCounterOption);
+
+INT i_APCI1710_CounterAutoTest(struct comedi_device *dev, PBYTE pb_TestStatus);
+
+INT i_APCI1710_InitIndex(struct comedi_device *dev,
+			 BYTE b_ModulNbr,
+			 BYTE b_ReferenceAction,
+			 BYTE b_IndexOperation, BYTE b_AutoMode,
+			 BYTE b_InterruptEnable);
+
+INT i_APCI1710_InitReference(struct comedi_device *dev,
+			     BYTE b_ModulNbr, BYTE b_ReferenceLevel);
+
+INT i_APCI1710_InitExternalStrobe(struct comedi_device *dev,
+				  BYTE b_ModulNbr, BYTE b_ExternalStrobe,
+				  BYTE b_ExternalStrobeLevel);
+
+INT i_APCI1710_InitCompareLogic(struct comedi_device *dev,
+				BYTE b_ModulNbr, UINT ui_CompareValue);
+
+INT i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev,
+					BYTE b_ModulNbr,
+					BYTE b_PCIInputClock,
+					BYTE b_TimingUnity,
+					ULONG ul_TimingInterval,
+					PULONG pul_RealTimingInterval);
+
+/* INSN BITS */
+INT i_APCI1710_ClearCounterValue(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_ClearAllCounterValue(struct comedi_device *dev);
+
+INT i_APCI1710_SetInputFilter(struct comedi_device *dev,
+			      BYTE b_ModulNbr, BYTE b_PCIInputClock,
+			      BYTE b_Filter);
+
+INT i_APCI1710_LatchCounter(struct comedi_device *dev,
+			    BYTE b_ModulNbr, BYTE b_LatchReg);
+
+INT i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev,
+					  BYTE b_ModulNbr,
+					  BYTE b_SourceSelection);
+
+INT i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, BYTE b_ModulNbr);
+
+/* INSN WRITE */
+INT i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_Write16BitCounterValue(struct comedi_device *dev,
+				      BYTE b_ModulNbr, BYTE b_SelectedCounter,
+				      UINT ui_WriteValue);
+
+INT i_APCI1710_Write32BitCounterValue(struct comedi_device *dev,
+				      BYTE b_ModulNbr, ULONG ul_WriteValue);
+
+INT i_APCI1710_EnableIndex(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_DisableIndex(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_EnableCompareLogic(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_DisableCompareLogic(struct comedi_device *dev, BYTE b_ModulNbr);
+
+INT i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev,
+					  BYTE b_ModulNbr,
+					  BYTE b_InterruptEnable);
+
+INT i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev,
+					   BYTE b_ModulNbr);
+
+/* INSN READ */
+INT i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev,
+				       BYTE b_ModulNbr, BYTE b_LatchReg,
+				       PBYTE pb_LatchStatus);
+
+INT i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev,
+				      BYTE b_ModulNbr, BYTE b_LatchReg,
+				      PULONG pul_LatchValue);
+
+INT i_APCI1710_Read16BitCounterValue(struct comedi_device *dev,
+				     BYTE b_ModulNbr, BYTE b_SelectedCounter,
+				     PUINT pui_CounterValue);
+
+INT i_APCI1710_Read32BitCounterValue(struct comedi_device *dev,
+				     BYTE b_ModulNbr, PULONG pul_CounterValue);
+
+INT i_APCI1710_GetIndexStatus(struct comedi_device *dev,
+			      BYTE b_ModulNbr, PBYTE pb_IndexStatus);
+
+INT i_APCI1710_GetReferenceStatus(struct comedi_device *dev,
+				  BYTE b_ModulNbr, PBYTE pb_ReferenceStatus);
+
+INT i_APCI1710_GetUASStatus(struct comedi_device *dev,
+			    BYTE b_ModulNbr, PBYTE pb_UASStatus);
+
+INT i_APCI1710_GetCBStatus(struct comedi_device *dev,
+			   BYTE b_ModulNbr, PBYTE pb_CBStatus);
+
+INT i_APCI1710_Get16BitCBStatus(struct comedi_device *dev,
+				BYTE b_ModulNbr, PBYTE pb_CBStatusCounter0,
+				PBYTE pb_CBStatusCounter1);
+
+INT i_APCI1710_GetUDStatus(struct comedi_device *dev,
+			   BYTE b_ModulNbr, PBYTE pb_UDStatus);
+
+INT i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev,
+					   BYTE b_ModulNbr, PBYTE pb_UDStatus);
+
+INT i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev,
+					BYTE b_ModulNbr,
+					PBYTE pb_Status, PBYTE pb_UDStatus,
+					PULONG pul_ReadValue);

+ 861 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c

@@ -0,0 +1,861 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : Inp_CPT.C       | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 pulse encoder module                        |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |----------|-----------|------------------------------------------------|
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "APCI1710_Inp_cpt.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitPulseEncoder                      |
+|                               (BYTE_          b_BoardHandle,               |
+|                                BYTE_          b_ModulNbr,                  |
+|                                BYTE_          b_PulseEncoderNbr,           |
+|                                BYTE_          b_InputLevelSelection,       |
+|                                BYTE_          b_TriggerOutputAction,       |
+|                                ULONG_        ul_StartValue)                |
++----------------------------------------------------------------------------+
+| Task              : Configure the pulse encoder operating mode selected via|
+|                     b_ModulNbr and b_PulseEncoderNbr. The pulse encoder    |
+|                     after each pulse decrement the counter value from 1.   |
+|                                                                            |
+|                     You must calling this function be for you call any     |
+|                     other function witch access of pulse encoders.         |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 3)       |
+|                     BYTE_ b_PulseEncoderNbr     : Pulse encoder selection  |
+|                                                   (0 to 3)                 |
+|                     BYTE_ b_InputLevelSelection : Input level selection    |
+|                                                   (0 or 1)                 |
+|                                                       0 : Set pulse encoder|
+|                                                           count the the low|
+|                                                           level pulse.     |
+|                                                       1 : Set pulse encoder|
+|                                                           count the the    |
+|                                                           high level pulse.|
+|                     BYTE_ b_TriggerOutputAction : Digital TRIGGER output   |
+|                                                   action                   |
+|                                                       0 : No action        |
+|                                                       1 : Set the trigger  |
+|                                                           output to "1"    |
+|                                                           (high) after the |
+|                                                           passage from 1 to|
+|                                                           0 from pulse     |
+|                                                           encoder.         |
+|                                                       2 : Set the trigger  |
+|                                                           output to "0"    |
+|                                                           (low) after the  |
+|                                                           passage from 1 to|
+|                                                           0 from pulse     |
+|                                                           encoder          |
+|                     ULONG_ ul_StartValue        : Pulse encoder start value|
+|                                                   (1 to 4294967295)
+	b_ModulNbr				=(BYTE) CR_AREF(insn->chanspec);
+	b_PulseEncoderNbr		=(BYTE) data[0];
+	b_InputLevelSelection	=(BYTE) data[1];
+	b_TriggerOutputAction	=(BYTE) data[2];
+	ul_StartValue			=(ULONG) data[3];
+       |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module is not a pulse encoder module            |
+|                    -3: Pulse encoder selection is wrong                    |
+|                    -4: Input level selection is wrong                      |
+|                    -5: Digital TRIGGER output action selection is wrong    |
+|                    -6: Pulse encoder start value is wrong                  |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_IntRegister;
+
+	BYTE b_ModulNbr;
+	BYTE b_PulseEncoderNbr;
+	BYTE b_InputLevelSelection;
+	BYTE b_TriggerOutputAction;
+	ULONG ul_StartValue;
+
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_PulseEncoderNbr = (BYTE) data[0];
+	b_InputLevelSelection = (BYTE) data[1];
+	b_TriggerOutputAction = (BYTE) data[2];
+	ul_StartValue = (ULONG) data[3];
+
+	i_ReturnValue = insn->n;
+
+	/***********************************/
+	/* Test the selected module number */
+	/***********************************/
+
+	if (b_ModulNbr <= 3) {
+	   /*************************/
+		/* Test if pulse encoder */
+	   /*************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				APCI1710_PULSE_ENCODER) ==
+			APCI1710_PULSE_ENCODER) {
+	      /******************************************/
+			/* Test the selected pulse encoder number */
+	      /******************************************/
+
+			if (b_PulseEncoderNbr <= 3) {
+		 /************************/
+				/* Test the input level */
+		 /************************/
+
+				if ((b_InputLevelSelection == 0)
+					|| (b_InputLevelSelection == 1)) {
+		    /*******************************************/
+					/* Test the ouput TRIGGER action selection */
+		    /*******************************************/
+
+					if ((b_TriggerOutputAction <= 2)
+						|| (b_PulseEncoderNbr > 0)) {
+						if (ul_StartValue > 1) {
+
+							dw_IntRegister =
+								inl(devpriv->
+								s_BoardInfos.
+								ui_Address +
+								20 +
+								(64 * b_ModulNbr));
+
+			  /***********************/
+							/* Set the start value */
+			  /***********************/
+
+							outl(ul_StartValue,
+								devpriv->
+								s_BoardInfos.
+								ui_Address +
+								(b_PulseEncoderNbr
+									* 4) +
+								(64 * b_ModulNbr));
+
+			  /***********************/
+							/* Set the input level */
+			  /***********************/
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_PulseEncoderModuleInfo.
+								dw_SetRegister =
+								(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_PulseEncoderModuleInfo.
+								dw_SetRegister &
+								(0xFFFFFFFFUL -
+									(1UL << (8 + b_PulseEncoderNbr)))) | ((1UL & (~b_InputLevelSelection)) << (8 + b_PulseEncoderNbr));
+
+			  /*******************************/
+							/* Test if output trigger used */
+			  /*******************************/
+
+							if ((b_TriggerOutputAction > 0) && (b_PulseEncoderNbr > 1)) {
+			     /****************************/
+								/* Enable the output action */
+			     /****************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									| (1UL
+									<< (4 + b_PulseEncoderNbr));
+
+			     /*********************************/
+								/* Set the output TRIGGER action */
+			     /*********************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									=
+									(devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									&
+									(0xFFFFFFFFUL
+										-
+										(1UL << (12 + b_PulseEncoderNbr)))) | ((1UL & (b_TriggerOutputAction - 1)) << (12 + b_PulseEncoderNbr));
+							} else {
+			     /*****************************/
+								/* Disable the output action */
+			     /*****************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									&
+									(0xFFFFFFFFUL
+									-
+									(1UL << (4 + b_PulseEncoderNbr)));
+							}
+
+			  /*************************/
+							/* Set the configuration */
+			  /*************************/
+
+							outl(devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_PulseEncoderModuleInfo.
+								dw_SetRegister,
+								devpriv->
+								s_BoardInfos.
+								ui_Address +
+								20 +
+								(64 * b_ModulNbr));
+
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_PulseEncoderModuleInfo.
+								s_PulseEncoderInfo
+								[b_PulseEncoderNbr].
+								b_PulseEncoderInit
+								= 1;
+						} else {
+			  /**************************************/
+							/* Pulse encoder start value is wrong */
+			  /**************************************/
+
+							DPRINTK("Pulse encoder start value is wrong\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+		       /****************************************************/
+						/* Digital TRIGGER output action selection is wrong */
+		       /****************************************************/
+
+						DPRINTK("Digital TRIGGER output action selection is wrong\n");
+						i_ReturnValue = -5;
+					}
+				} else {
+		    /**********************************/
+					/* Input level selection is wrong */
+		    /**********************************/
+
+					DPRINTK("Input level selection is wrong\n");
+					i_ReturnValue = -4;
+				}
+			} else {
+		 /************************************/
+				/* Pulse encoder selection is wrong */
+		 /************************************/
+
+				DPRINTK("Pulse encoder selection is wrong\n");
+				i_ReturnValue = -3;
+			}
+		} else {
+	      /********************************************/
+			/* The module is not a pulse encoder module */
+	      /********************************************/
+
+			DPRINTK("The module is not a pulse encoder module\n");
+			i_ReturnValue = -2;
+		}
+	} else {
+	   /********************************************/
+		/* The module is not a pulse encoder module */
+	   /********************************************/
+
+		DPRINTK("The module is not a pulse encoder module\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_EnablePulseEncoder                    |
+|                                       (BYTE_  b_BoardHandle,               |
+|                                        BYTE_  b_ModulNbr,                  |
+|                                        BYTE_  b_PulseEncoderNbr,           |
+|                                        BYTE_  b_CycleSelection,            |
+|                                        BYTE_  b_InterruptHandling)         |
++----------------------------------------------------------------------------+
+| Task              : Enableor disable  the selected pulse encoder (b_PulseEncoderNbr)  |
+|                     from selected module (b_ModulNbr). Each input pulse    |
+|                     decrement the pulse encoder counter value from 1.      |
+|                     If you enabled the interrupt (b_InterruptHandling), a  |
+|                     interrupt is generated when the pulse encoder has run  |
+|                     down.                                                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_   b_BoardHandle       : Handle of board APCI-1710|
+|                     BYTE_   b_ModulNbr          : Module number to         |
+|                                                   configure (0 to 3)       |
+|                     BYTE_   b_PulseEncoderNbr   : Pulse encoder selection  |
+|                                                   (0 to 3)                 |
+|                     BYTE_   b_CycleSelection    : APCI1710_CONTINUOUS:     |
+|                                                       Each time the        |
+|                                                       counting value is set|
+|                                                       on "0", the pulse    |
+|                                                       encoder load the     |
+|                                                       start value after    |
+|                                                       the next pulse.      |
+|                                                   APCI1710_SINGLE:         |
+|                                                       If the counter is set|
+|                                                       on "0", the pulse    |
+|                                                       encoder is stopped.  |
+|                     BYTE_   b_InterruptHandling : Interrupts can be        |
+|                                                   generated, when the pulse|
+|                                                   encoder has run down.    |
+|                                                   With this parameter the  |
+|                                                   user decides if          |
+|                                                   interrupts are used or   |
+|                                                   not.                     |
+|                                                     APCI1710_ENABLE:       |
+|                                                     Interrupts are enabled |
+|                                                     APCI1710_DISABLE:      |
+|                                                     Interrupts are disabled
+
+  	b_ModulNbr			=(BYTE) CR_AREF(insn->chanspec);
+	b_Action			=(BYTE) data[0];
+	b_PulseEncoderNbr	=(BYTE) data[1];
+	b_CycleSelection	=(BYTE) data[2];
+	b_InterruptHandling	=(BYTE) data[3];|
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection is wrong                          |
+|                     -3: Pulse encoder selection is wrong                   |
+|                     -4: Pulse encoder not initialised.                     |
+|                         See function "i_APCI1710_InitPulseEncoder"         |
+|                     -5: Cycle selection mode is wrong                      |
+|                     -6: Interrupt handling mode is wrong                   |
+|                     -7: Interrupt routine not installed.                   |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	BYTE b_ModulNbr;
+	BYTE b_PulseEncoderNbr;
+	BYTE b_CycleSelection;
+	BYTE b_InterruptHandling;
+	BYTE b_Action;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_Action = (BYTE) data[0];
+	b_PulseEncoderNbr = (BYTE) data[1];
+	b_CycleSelection = (BYTE) data[2];
+	b_InterruptHandling = (BYTE) data[3];
+
+	/***********************************/
+	/* Test the selected module number */
+	/***********************************/
+
+	if (b_ModulNbr <= 3) {
+	   /******************************************/
+		/* Test the selected pulse encoder number */
+	   /******************************************/
+
+		if (b_PulseEncoderNbr <= 3) {
+	      /*************************************/
+			/* Test if pulse encoder initialised */
+	      /*************************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_PulseEncoderModuleInfo.
+				s_PulseEncoderInfo[b_PulseEncoderNbr].
+				b_PulseEncoderInit == 1) {
+				switch (b_Action) {
+
+				case APCI1710_ENABLE:
+		 /****************************/
+					/* Test the cycle selection */
+		 /****************************/
+
+					if (b_CycleSelection ==
+						APCI1710_CONTINUOUS
+						|| b_CycleSelection ==
+						APCI1710_SINGLE) {
+		    /*******************************/
+						/* Test the interrupt handling */
+		    /*******************************/
+
+						if (b_InterruptHandling ==
+							APCI1710_ENABLE
+							|| b_InterruptHandling
+							== APCI1710_DISABLE) {
+		       /******************************/
+							/* Test if interrupt not used */
+		       /******************************/
+
+							if (b_InterruptHandling
+								==
+								APCI1710_DISABLE)
+							{
+			  /*************************/
+								/* Disable the interrupt */
+			  /*************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									&
+									(0xFFFFFFFFUL
+									-
+									(1UL << b_PulseEncoderNbr));
+							} else {
+
+			     /************************/
+								/* Enable the interrupt */
+			     /************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister
+									| (1UL
+									<<
+									b_PulseEncoderNbr);
+								devpriv->tsk_Current = current;	// Save the current process task structure
+
+							}
+
+							if (i_ReturnValue >= 0) {
+			  /***********************************/
+								/* Enable or disable the interrupt */
+			  /***********************************/
+
+								outl(devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_SetRegister,
+									devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 20 +
+									(64 * b_ModulNbr));
+
+			  /****************************/
+								/* Enable the pulse encoder */
+			  /****************************/
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_ControlRegister
+									=
+									devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_ControlRegister
+									| (1UL
+									<<
+									b_PulseEncoderNbr);
+
+			  /**********************/
+								/* Set the cycle mode */
+			  /**********************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_ControlRegister
+									=
+									(devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_ControlRegister
+									&
+									(0xFFFFFFFFUL
+										-
+										(1 << (b_PulseEncoderNbr + 4)))) | ((b_CycleSelection & 1UL) << (4 + b_PulseEncoderNbr));
+
+			  /****************************/
+								/* Enable the pulse encoder */
+			  /****************************/
+
+								outl(devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PulseEncoderModuleInfo.
+									dw_ControlRegister,
+									devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 16 +
+									(64 * b_ModulNbr));
+							}
+						} else {
+		       /************************************/
+							/* Interrupt handling mode is wrong */
+		       /************************************/
+
+							DPRINTK("Interrupt handling mode is wrong\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+		    /*********************************/
+						/* Cycle selection mode is wrong */
+		    /*********************************/
+
+						DPRINTK("Cycle selection mode is wrong\n");
+						i_ReturnValue = -5;
+					}
+					break;
+
+				case APCI1710_DISABLE:
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_ControlRegister =
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_ControlRegister &
+						(0xFFFFFFFFUL -
+						(1UL << b_PulseEncoderNbr));
+
+		 /*****************************/
+					/* Disable the pulse encoder */
+		 /*****************************/
+
+					outl(devpriv->s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_ControlRegister,
+						devpriv->s_BoardInfos.
+						ui_Address + 16 +
+						(64 * b_ModulNbr));
+
+					break;
+				}	// switch End
+
+			} else {
+		 /*********************************/
+				/* Pulse encoder not initialised */
+		 /*********************************/
+
+				DPRINTK("Pulse encoder not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /************************************/
+			/* Pulse encoder selection is wrong */
+	      /************************************/
+
+			DPRINTK("Pulse encoder selection is wrong\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*****************************/
+		/* Module selection is wrong */
+	   /*****************************/
+
+		DPRINTK("Module selection is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadPulseEncoderStatus                |
+|                                       (BYTE_  b_BoardHandle,               |
+|                                        BYTE_  b_ModulNbr,                  |
+|                                        BYTE_  b_PulseEncoderNbr,           |
+|                                        PBYTE_ pb_Status)                   |
++----------------------------------------------------------------------------+
+| Task    APCI1710_PULSEENCODER_READ          : Reads the pulse encoder status
+											and valuefrom selected pulse     |
+|                     encoder (b_PulseEncoderNbr) from selected module       |
+|                     (b_ModulNbr).                                          |
++----------------------------------------------------------------------------+
+	BYTE   b_Type; data[0]
+   APCI1710_PULSEENCODER_WRITE
+ Writes a 32-bit value (ul_WriteValue) into the selected|
+|                     pulse encoder (b_PulseEncoderNbr) from selected module |
+|                     (b_ModulNbr). This operation set the new start pulse   |
+|                     encoder value.
+ APCI1710_PULSEENCODER_READ
+| Input Parameters  : BYTE_   b_BoardHandle       : Handle of board APCI-1710|
+|            CRAREF()         BYTE_   b_ModulNbr          : Module number to         |
+|                                                   configure (0 to 3)       |
+|              data[1]       BYTE_   b_PulseEncoderNbr   : Pulse encoder selection  |
+|                                                   (0 to 3)
+   APCI1710_PULSEENCODER_WRITE
+				data[2]		ULONG_ ul_WriteValue        : 32-bit value to be       |
+|                                                   written             |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_ pb_Status            : Pulse encoder status.    |
+|                                                       0 : No overflow occur|
+|                                                       1 : Overflow occur
+						PULONG_ pul_ReadValue       : Pulse encoder value      |  |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection is wrong                          |
+|                     -3: Pulse encoder selection is wrong                   |
+|                     -4: Pulse encoder not initialised.                     |
+|                         See function "i_APCI1710_InitPulseEncoder"         |
++----------------------------------------------------------------------------+
+*/
+
+/*_INT_   i_APCI1710_ReadPulseEncoderStatus       (BYTE_   b_BoardHandle,
+						 BYTE_   b_ModulNbr,
+						 BYTE_   b_PulseEncoderNbr,
+
+   						 PBYTE_ pb_Status)
+						 */
+INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusRegister;
+	BYTE b_ModulNbr;
+	BYTE b_PulseEncoderNbr;
+	PBYTE pb_Status;
+	BYTE b_Type;
+	PULONG pul_ReadValue;
+	ULONG ul_WriteValue;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_Type = (BYTE) data[0];
+	b_PulseEncoderNbr = (BYTE) data[1];
+	pb_Status = (PBYTE) & data[0];
+	pul_ReadValue = (PULONG) & data[1];
+
+	/***********************************/
+	/* Test the selected module number */
+	/***********************************/
+
+	if (b_ModulNbr <= 3) {
+	   /******************************************/
+		/* Test the selected pulse encoder number */
+	   /******************************************/
+
+		if (b_PulseEncoderNbr <= 3) {
+	      /*************************************/
+			/* Test if pulse encoder initialised */
+	      /*************************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_PulseEncoderModuleInfo.
+				s_PulseEncoderInfo[b_PulseEncoderNbr].
+				b_PulseEncoderInit == 1) {
+
+				switch (b_Type) {
+				case APCI1710_PULSEENCODER_READ:
+		 /****************************/
+					/* Read the status register */
+		 /****************************/
+
+					dw_StatusRegister =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 16 +
+						(64 * b_ModulNbr));
+
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_StatusRegister = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_StatusRegister |
+						dw_StatusRegister;
+
+					*pb_Status =
+						(BYTE) (devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_StatusRegister >> (1 +
+							b_PulseEncoderNbr)) & 1;
+
+					devpriv->s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_StatusRegister =
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_PulseEncoderModuleInfo.
+						dw_StatusRegister &
+						(0xFFFFFFFFUL - (1 << (1 +
+								b_PulseEncoderNbr)));
+
+		 /******************/
+					/* Read the value */
+		 /******************/
+
+					*pul_ReadValue =
+						inl(devpriv->s_BoardInfos.
+						ui_Address +
+						(4 * b_PulseEncoderNbr) +
+						(64 * b_ModulNbr));
+					break;
+
+				case APCI1710_PULSEENCODER_WRITE:
+					ul_WriteValue = (ULONG) data[2];
+			/*******************/
+					/* Write the value */
+			/*******************/
+
+					outl(ul_WriteValue,
+						devpriv->s_BoardInfos.
+						ui_Address +
+						(4 * b_PulseEncoderNbr) +
+						(64 * b_ModulNbr));
+
+				}	//end of switch
+			} else {
+		 /*********************************/
+				/* Pulse encoder not initialised */
+		 /*********************************/
+
+				DPRINTK("Pulse encoder not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /************************************/
+			/* Pulse encoder selection is wrong */
+	      /************************************/
+
+			DPRINTK("Pulse encoder selection is wrong\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*****************************/
+		/* Module selection is wrong */
+	   /*****************************/
+
+		DPRINTK("Module selection is wrong\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+INT i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+
+	data[0] = devpriv->s_InterruptParameters.
+		s_FIFOInterruptParameters[devpriv->
+		s_InterruptParameters.ui_Read].b_OldModuleMask;
+	data[1] = devpriv->s_InterruptParameters.
+		s_FIFOInterruptParameters[devpriv->
+		s_InterruptParameters.ui_Read].ul_OldInterruptMask;
+	data[2] = devpriv->s_InterruptParameters.
+		s_FIFOInterruptParameters[devpriv->
+		s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
+
+	/***************************/
+	/* Increment the read FIFO */
+	/***************************/
+
+	devpriv->s_InterruptParameters.
+		ui_Read = (devpriv->
+		s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
+
+	return insn->n;
+
+}

+ 47 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h

@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_SINGLE			0
+#define APCI1710_CONTINUOUS		1
+
+#define APCI1710_PULSEENCODER_READ	0
+#define APCI1710_PULSEENCODER_WRITE	1
+
+INT i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev,
+						  struct comedi_subdevice *s,
+						  struct comedi_insn *insn,
+						  unsigned int *data);
+
+/*
+ * READ PULSE ENCODER FUNCTIONS
+ */
+INT i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+
+/*
+ * WRITE PULSE ENCODER FUNCTIONS
+ */
+INT i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);

+ 3588 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c

@@ -0,0 +1,3588 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : PWM.C           | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 Wulse wide modulation module                |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +-----------------------------------------------------------------------+
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "APCI1710_Pwm.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT i_APCI1710_InsnConfigPWM(struct comedi_device *dev,
+struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                        |
++----------------------------------------------------------------------------+
+| Task              : Pwm Init and Get Pwm Initialisation                    |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigPWM(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_ConfigType;
+	INT i_ReturnValue = 0;
+	b_ConfigType = CR_CHAN(insn->chanspec);
+
+	switch (b_ConfigType) {
+	case APCI1710_PWM_INIT:
+		i_ReturnValue = i_APCI1710_InitPWM(dev, (BYTE) CR_AREF(insn->chanspec),	//  b_ModulNbr
+			(BYTE) data[0],	//b_PWM
+			(BYTE) data[1],	// b_ClockSelection
+			(BYTE) data[2],	// b_TimingUnit
+			(ULONG) data[3],	//ul_LowTiming
+			(ULONG) data[4],	//ul_HighTiming
+			(PULONG) & data[0],	//pul_RealLowTiming
+			(PULONG) & data[1]	//pul_RealHighTiming
+			);
+		break;
+
+	case APCI1710_PWM_GETINITDATA:
+		i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (BYTE) CR_AREF(insn->chanspec),	// b_ModulNbr
+			(BYTE) data[0],	//b_PWM
+			(PBYTE) & data[0],	//pb_TimingUnit
+			(PULONG) & data[1],	//pul_LowTiming
+			(PULONG) & data[2],	//pul_HighTiming
+			(PBYTE) & data[3],	// pb_StartLevel
+			(PBYTE) & data[4],	// pb_StopMode
+			(PBYTE) & data[5],	// pb_StopLevel
+			(PBYTE) & data[6],	// pb_ExternGate
+			(PBYTE) & data[7],	// pb_InterruptEnable
+			(PBYTE) & data[8]	// pb_Enable
+			);
+		break;
+
+	default:
+		printk(" Config Parameter Wrong\n");
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitPWM                               |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_PWM,                    |
+|                                        BYTE_     b_ClockSelection,         |
+|                                        BYTE_     b_TimingUnit,             |
+|                                        ULONG_   ul_LowTiming,              |
+|                                        ULONG_   ul_HighTiming,             |
+|                                        PULONG_ pul_RealLowTiming,          |
+|                                        PULONG_ pul_RealHighTiming)         |
++----------------------------------------------------------------------------+
+| Task              : Configure the selected PWM (b_PWM) from selected module|
+|                     (b_ModulNbr). The ul_LowTiming, ul_HighTiming and      |
+|                     ul_TimingUnit determine the low/high timing base for   |
+|                     the period. pul_RealLowTiming, pul_RealHighTiming      |
+|                     return the real timing value.                          |
+|                     You must calling this function be for you call any     |
+|                     other function witch access of the PWM.                |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_     b_BoardHandle    : Handle of board APCI-1710 |
+|                     BYTE_     b_ModulNbr       : Module number to configure|
+|                                                  (0 to 3)                  |
+|                     BYTE_     b_PWM            : Selected PWM (0 or 1).    |
+|                     BYTE_     b_ClockSelection : Selection from PCI bus    |
+|                                                  clock                     |
+|                                                   - APCI1710_30MHZ :       |
+|                                                     The PC have a 30 MHz   |
+|                                                     PCI bus clock          |
+|                                                   - APCI1710_33MHZ :       |
+|                                                     The PC have a 33 MHz   |
+|                                                     PCI bus clock          |
+|                                                   - APCI1710_40MHZ         |
+|                                                     The APCI-1710 have a   |
+|                                                     integrated 40Mhz       |
+|                                                     quartz.                |
+|                     BYTE_     b_TimingUnit     : Base timing Unit (0 to 4) |
+|                                                       0 : ns               |
+|                                                       1 : æs               |
+|                                                       2 : ms               |
+|                                                       3 : s                |
+|                                                       4 : mn               |
+|                     ULONG_    ul_LowTiming     : Low base timing value.    |
+|                     ULONG_    ul_HighTiming    : High base timing value.   |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pul_RealLowTiming  : Real low base timing     |
+|                                                   value.                   |
+|                     PULONG_  pul_RealHighTiming : Real high base timing    |
+|                                                   value.                   |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: The module is not a PWM module                      |
+|                    -4: PWM selection is wrong                              |
+|                    -5: The selected input clock is wrong                   |
+|                    -6: Timing Unit selection is wrong                      |
+|                    -7: Low base timing selection is wrong                  |
+|                    -8: High base timing selection is wrong                 |
+|                    -9: You can not used the 40MHz clock selection with     |
+|                        this board                                          |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InitPWM(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_PWM,
+	BYTE b_ClockSelection,
+	BYTE b_TimingUnit,
+	ULONG ul_LowTiming,
+	ULONG ul_HighTiming,
+	PULONG pul_RealLowTiming, PULONG pul_RealHighTiming)
+{
+	INT i_ReturnValue = 0;
+	ULONG ul_LowTimerValue = 0;
+	ULONG ul_HighTimerValue = 0;
+	DWORD dw_Command;
+	double d_RealLowTiming = 0;
+	double d_RealHighTiming = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***************/
+		/* Test if PWM */
+	   /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+	      /**************************/
+			/* Test the PWM selection */
+	      /**************************/
+
+			if (b_PWM <= 1) {
+		 /******************/
+				/* Test the clock */
+		 /******************/
+
+				if ((b_ClockSelection == APCI1710_30MHZ) ||
+					(b_ClockSelection == APCI1710_33MHZ) ||
+					(b_ClockSelection == APCI1710_40MHZ)) {
+		    /************************/
+					/* Test the timing unit */
+		    /************************/
+
+					if (b_TimingUnit <= 4) {
+		       /*********************************/
+						/* Test the low timing selection */
+		       /*********************************/
+
+						if (((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 0)
+								&& (ul_LowTiming
+									>= 266)
+								&& (ul_LowTiming
+									<=
+									0xFFFFFFFFUL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 1)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									571230650UL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 2)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									571230UL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 3)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									571UL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 4)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<= 9UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 0)
+								&& (ul_LowTiming
+									>= 242)
+								&& (ul_LowTiming
+									<=
+									0xFFFFFFFFUL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 1)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									519691043UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 2)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									519691UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 3)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									520UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 4)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<= 8UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 0)
+								&& (ul_LowTiming
+									>= 200)
+								&& (ul_LowTiming
+									<=
+									0xFFFFFFFFUL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 1)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									429496729UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 2)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									429496UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 3)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									429UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 4)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									7UL))) {
+			  /**********************************/
+							/* Test the High timing selection */
+			  /**********************************/
+
+							if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) {
+			     /**************************/
+								/* Test the board version */
+			     /**************************/
+
+								if (((b_ClockSelection == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_ClockSelection != APCI1710_40MHZ)) {
+
+				/************************************/
+									/* Calculate the low division fator */
+				/************************************/
+
+									fpu_begin
+										();
+
+									switch (b_TimingUnit) {
+				   /******/
+										/* ns */
+				   /******/
+
+									case 0:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(ul_LowTiming
+											*
+											(0.00025 * b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+											ul_LowTimerValue
+												=
+												ul_LowTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealLowTiming
+											=
+											(ULONG)
+											(ul_LowTimerValue
+											/
+											(0.00025 * (double)b_ClockSelection));
+										d_RealLowTiming
+											=
+											(double)
+											ul_LowTimerValue
+											/
+											(0.00025
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
+											*pul_RealLowTiming
+												=
+												*pul_RealLowTiming
+												+
+												1;
+										}
+
+										ul_LowTiming
+											=
+											ul_LowTiming
+											-
+											1;
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_LowTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_LowTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /******/
+										/* æs */
+				   /******/
+
+									case 1:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(ul_LowTiming
+											*
+											(0.25 * b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+											ul_LowTimerValue
+												=
+												ul_LowTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealLowTiming
+											=
+											(ULONG)
+											(ul_LowTimerValue
+											/
+											(0.25 * (double)b_ClockSelection));
+										d_RealLowTiming
+											=
+											(double)
+											ul_LowTimerValue
+											/
+											(
+											(double)
+											0.25
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
+											*pul_RealLowTiming
+												=
+												*pul_RealLowTiming
+												+
+												1;
+										}
+
+										ul_LowTiming
+											=
+											ul_LowTiming
+											-
+											1;
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_LowTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_LowTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /******/
+										/* ms */
+				   /******/
+
+									case 2:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_LowTimerValue
+											=
+											ul_LowTiming
+											*
+											(250.0
+											*
+											b_ClockSelection);
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+											ul_LowTimerValue
+												=
+												ul_LowTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealLowTiming
+											=
+											(ULONG)
+											(ul_LowTimerValue
+											/
+											(250.0 * (double)b_ClockSelection));
+										d_RealLowTiming
+											=
+											(double)
+											ul_LowTimerValue
+											/
+											(250.0
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
+											*pul_RealLowTiming
+												=
+												*pul_RealLowTiming
+												+
+												1;
+										}
+
+										ul_LowTiming
+											=
+											ul_LowTiming
+											-
+											1;
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_LowTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_LowTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /*****/
+										/* s */
+				   /*****/
+
+									case 3:
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(ul_LowTiming
+											*
+											(250000.0
+												*
+												b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+											ul_LowTimerValue
+												=
+												ul_LowTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealLowTiming
+											=
+											(ULONG)
+											(ul_LowTimerValue
+											/
+											(250000.0
+												*
+												(double)
+												b_ClockSelection));
+										d_RealLowTiming
+											=
+											(double)
+											ul_LowTimerValue
+											/
+											(250000.0
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
+											*pul_RealLowTiming
+												=
+												*pul_RealLowTiming
+												+
+												1;
+										}
+
+										ul_LowTiming
+											=
+											ul_LowTiming
+											-
+											1;
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_LowTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_LowTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /******/
+										/* mn */
+				   /******/
+
+									case 4:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(
+											(ul_LowTiming
+												*
+												60)
+											*
+											(250000.0
+												*
+												b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+											ul_LowTimerValue
+												=
+												ul_LowTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealLowTiming
+											=
+											(ULONG)
+											(ul_LowTimerValue
+											/
+											(250000.0
+												*
+												(double)
+												b_ClockSelection))
+											/
+											60;
+										d_RealLowTiming
+											=
+											(
+											(double)
+											ul_LowTimerValue
+											/
+											(250000.0
+												*
+												(double)
+												b_ClockSelection))
+											/
+											60.0;
+
+										if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealLowTiming + 0.5)) {
+											*pul_RealLowTiming
+												=
+												*pul_RealLowTiming
+												+
+												1;
+										}
+
+										ul_LowTiming
+											=
+											ul_LowTiming
+											-
+											1;
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_LowTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_LowTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+									}
+
+				/*************************************/
+									/* Calculate the high division fator */
+				/*************************************/
+
+									switch (b_TimingUnit) {
+				   /******/
+										/* ns */
+				   /******/
+
+									case 0:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(ul_HighTiming
+											*
+											(0.00025 * b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+											ul_HighTimerValue
+												=
+												ul_HighTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealHighTiming
+											=
+											(ULONG)
+											(ul_HighTimerValue
+											/
+											(0.00025 * (double)b_ClockSelection));
+										d_RealHighTiming
+											=
+											(double)
+											ul_HighTimerValue
+											/
+											(0.00025
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
+											*pul_RealHighTiming
+												=
+												*pul_RealHighTiming
+												+
+												1;
+										}
+
+										ul_HighTiming
+											=
+											ul_HighTiming
+											-
+											1;
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_HighTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_HighTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /******/
+										/* æs */
+				   /******/
+
+									case 1:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(ul_HighTiming
+											*
+											(0.25 * b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+											ul_HighTimerValue
+												=
+												ul_HighTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealHighTiming
+											=
+											(ULONG)
+											(ul_HighTimerValue
+											/
+											(0.25 * (double)b_ClockSelection));
+										d_RealHighTiming
+											=
+											(double)
+											ul_HighTimerValue
+											/
+											(
+											(double)
+											0.25
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
+											*pul_RealHighTiming
+												=
+												*pul_RealHighTiming
+												+
+												1;
+										}
+
+										ul_HighTiming
+											=
+											ul_HighTiming
+											-
+											1;
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_HighTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_HighTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /******/
+										/* ms */
+				   /******/
+
+									case 2:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_HighTimerValue
+											=
+											ul_HighTiming
+											*
+											(250.0
+											*
+											b_ClockSelection);
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+											ul_HighTimerValue
+												=
+												ul_HighTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealHighTiming
+											=
+											(ULONG)
+											(ul_HighTimerValue
+											/
+											(250.0 * (double)b_ClockSelection));
+										d_RealHighTiming
+											=
+											(double)
+											ul_HighTimerValue
+											/
+											(250.0
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
+											*pul_RealHighTiming
+												=
+												*pul_RealHighTiming
+												+
+												1;
+										}
+
+										ul_HighTiming
+											=
+											ul_HighTiming
+											-
+											1;
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_HighTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_HighTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /*****/
+										/* s */
+				   /*****/
+
+									case 3:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(ul_HighTiming
+											*
+											(250000.0
+												*
+												b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+											ul_HighTimerValue
+												=
+												ul_HighTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealHighTiming
+											=
+											(ULONG)
+											(ul_HighTimerValue
+											/
+											(250000.0
+												*
+												(double)
+												b_ClockSelection));
+										d_RealHighTiming
+											=
+											(double)
+											ul_HighTimerValue
+											/
+											(250000.0
+											*
+											(double)
+											b_ClockSelection);
+
+										if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
+											*pul_RealHighTiming
+												=
+												*pul_RealHighTiming
+												+
+												1;
+										}
+
+										ul_HighTiming
+											=
+											ul_HighTiming
+											-
+											1;
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_HighTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_HighTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+
+				   /******/
+										/* mn */
+				   /******/
+
+									case 4:
+
+					   /******************/
+										/* Timer 0 factor */
+					   /******************/
+
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(
+											(ul_HighTiming
+												*
+												60)
+											*
+											(250000.0
+												*
+												b_ClockSelection));
+
+					   /*******************/
+										/* Round the value */
+					   /*******************/
+
+										if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+											ul_HighTimerValue
+												=
+												ul_HighTimerValue
+												+
+												1;
+										}
+
+					   /*****************************/
+										/* Calculate the real timing */
+					   /*****************************/
+
+										*pul_RealHighTiming
+											=
+											(ULONG)
+											(ul_HighTimerValue
+											/
+											(250000.0
+												*
+												(double)
+												b_ClockSelection))
+											/
+											60;
+										d_RealHighTiming
+											=
+											(
+											(double)
+											ul_HighTimerValue
+											/
+											(250000.0
+												*
+												(double)
+												b_ClockSelection))
+											/
+											60.0;
+
+										if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealHighTiming + 0.5)) {
+											*pul_RealHighTiming
+												=
+												*pul_RealHighTiming
+												+
+												1;
+										}
+
+										ul_HighTiming
+											=
+											ul_HighTiming
+											-
+											1;
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											-
+											2;
+
+										if (b_ClockSelection != APCI1710_40MHZ) {
+											ul_HighTimerValue
+												=
+												(ULONG)
+												(
+												(double)
+												(ul_HighTimerValue)
+												*
+												1.007752288);
+										}
+
+										break;
+									}
+
+									fpu_end();
+				/****************************/
+									/* Save the clock selection */
+				/****************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										b_ClockSelection
+										=
+										b_ClockSelection;
+
+				/************************/
+									/* Save the timing unit */
+				/************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										s_PWMInfo
+										[b_PWM].
+										b_TimingUnit
+										=
+										b_TimingUnit;
+
+				/****************************/
+									/* Save the low base timing */
+				/****************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										s_PWMInfo
+										[b_PWM].
+										d_LowTiming
+										=
+										d_RealLowTiming;
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										s_PWMInfo
+										[b_PWM].
+										ul_RealLowTiming
+										=
+										*pul_RealLowTiming;
+
+				/****************************/
+									/* Save the high base timing */
+				/****************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										s_PWMInfo
+										[b_PWM].
+										d_HighTiming
+										=
+										d_RealHighTiming;
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										s_PWMInfo
+										[b_PWM].
+										ul_RealHighTiming
+										=
+										*pul_RealHighTiming;
+
+				/************************/
+									/* Write the low timing */
+				/************************/
+
+									outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr));
+
+				/*************************/
+									/* Write the high timing */
+				/*************************/
+
+									outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr));
+
+				/***************************/
+									/* Set the clock selection */
+				/***************************/
+
+									dw_Command
+										=
+										inl
+										(devpriv->
+										s_BoardInfos.
+										ui_Address
+										+
+										8
+										+
+										(20 * b_PWM) + (64 * b_ModulNbr));
+
+									dw_Command
+										=
+										dw_Command
+										&
+										0x7F;
+
+									if (b_ClockSelection == APCI1710_40MHZ) {
+										dw_Command
+											=
+											dw_Command
+											|
+											0x80;
+									}
+
+				/***************************/
+									/* Set the clock selection */
+				/***************************/
+
+									outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr));
+
+				/*************/
+									/* PWM init. */
+				/*************/
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_PWMModuleInfo.
+										s_PWMInfo
+										[b_PWM].
+										b_PWMInit
+										=
+										1;
+								} else {
+				/***************************************************/
+									/* You can not used the 40MHz clock selection with */
+									/* this board                                      */
+				/***************************************************/
+									DPRINTK("You can not used the 40MHz clock selection with this board\n");
+									i_ReturnValue
+										=
+										-9;
+								}
+							} else {
+			     /***************************************/
+								/* High base timing selection is wrong */
+			     /***************************************/
+								DPRINTK("High base timing selection is wrong\n");
+								i_ReturnValue =
+									-8;
+							}
+						} else {
+			  /**************************************/
+							/* Low base timing selection is wrong */
+			  /**************************************/
+							DPRINTK("Low base timing selection is wrong\n");
+							i_ReturnValue = -7;
+						}
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+					else {
+		       /**********************************/
+						/* Timing unit selection is wrong */
+		       /**********************************/
+						DPRINTK("Timing unit selection is wrong\n");
+						i_ReturnValue = -6;
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+				}	// if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ))
+				else {
+		    /*******************************/
+					/* The selected clock is wrong */
+		    /*******************************/
+					DPRINTK("The selected clock is wrong\n");
+					i_ReturnValue = -5;
+				}	// if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ))
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+			else {
+		 /******************************/
+				/* Tor PWM selection is wrong */
+		 /******************************/
+				DPRINTK("Tor PWM selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+		} else {
+	      /**********************************/
+			/* The module is not a PWM module */
+	      /**********************************/
+			DPRINTK("The module is not a PWM module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetPWMInitialisation                  |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_PWM,                    |
+|                                        PBYTE_   pb_TimingUnit,             |
+|                                        PULONG_ pul_LowTiming,              |
+|                                        PULONG_ pul_HighTiming,             |
+|                                        PBYTE_   pb_StartLevel,             |
+|                                        PBYTE_   pb_StopMode,               |
+|                                        PBYTE_   pb_StopLevel,              |
+|                                        PBYTE_   pb_ExternGate,             |
+|                                        PBYTE_   pb_InterruptEnable,        |
+|                                        PBYTE_   pb_Enable)                 |
++----------------------------------------------------------------------------+
+| Task              : Return the PWM (b_PWM) initialisation from selected    |
+|                     module (b_ModulNbr). You must calling the              |
+|                     "i_APCI1710_InitPWM" function be for you call this     |
+|                     function.                                              |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle : Handle of board APCI-1710        |
+|                     BYTE_ b_ModulNbr    : Selected module number (0 to 3)  |
+|                     BYTE_ b_PWM         : Selected PWM (0 or 1)            |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_  pb_TimingUnit      : Base timing Unit (0 to 4) |
+|                                                       0 : ns               |
+|                                                       1 : æs               |
+|                                                       2 : ms               |
+|                                                       3 : s                |
+|                                                       4 : mn               |
+|                     PULONG_ pul_LowTiming      : Low base timing value.    |
+|                     PULONG_ pul_HighTiming     : High base timing value.   |
+|                     PBYTE_  pb_StartLevel      : Start period level        |
+|                                                  selection                 |
+|                                                       0 : The period start |
+|                                                           with a low level |
+|                                                       1 : The period start |
+|                                                           with a high level|
+|                     PBYTE_  pb_StopMode        : Stop mode selection       |
+|                                                  0 : The PWM is stopped    |
+|                                                      directly after the    |
+|                                                     "i_APCI1710_DisablePWM"|
+|                                                      function and break the|
+|                                                      last period           |
+|                                                  1 : After the             |
+|                                                     "i_APCI1710_DisablePWM"|
+|                                                      function the PWM is   |
+|                                                      stopped at the end    |
+|                                                      from last period cycle|
+|                     PBYTE_  pb_StopLevel        : Stop PWM level selection |
+|                                                    0 : The output signal   |
+|                                                        keep the level after|
+|                                                        the                 |
+|                                                     "i_APCI1710_DisablePWM"|
+|                                                        function            |
+|                                                    1 : The output signal is|
+|                                                        set to low after the|
+|                                                     "i_APCI1710_DisablePWM"|
+|                                                        function            |
+|                                                    2 : The output signal is|
+|                                                        set to high after   |
+|                                                        the                 |
+|                                                     "i_APCI1710_DisablePWM"|
+|                                                        function            |
+|                     PBYTE_  pb_ExternGate      : Extern gate action        |
+|                                                  selection                 |
+|                                                   0 : Extern gate signal   |
+|                                                       not used.            |
+|                                                   1 : Extern gate signal   |
+|                                                       used.                |
+|                     PBYTE_  pb_InterruptEnable : Enable or disable the PWM |
+|                                                  interrupt.                |
+|                                                  - APCI1710_ENABLE :       |
+|                                                    Enable the PWM interrupt|
+|                                                    A interrupt occur after |
+|                                                    each period             |
+|                                                  - APCI1710_DISABLE :      |
+|                                                    Disable the PWM         |
+|                                                    interrupt               |
+|                     PBYTE_  pb_Enable          : Indicate if the PWM is    |
+|                                                  enabled or no             |
+|                                                       0 : PWM not enabled  |
+|                                                       1 : PWM enabled      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a PWM module                     |
+|                     -4: PWM selection is wrong                             |
+|                     -5: PWM not initialised see function                   |
+|                         "i_APCI1710_InitPWM"                               |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_GetPWMInitialisation(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_PWM,
+	PBYTE pb_TimingUnit,
+	PULONG pul_LowTiming,
+	PULONG pul_HighTiming,
+	PBYTE pb_StartLevel,
+	PBYTE pb_StopMode,
+	PBYTE pb_StopLevel,
+	PBYTE pb_ExternGate, PBYTE pb_InterruptEnable, PBYTE pb_Enable)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+	DWORD dw_Command;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***************/
+		/* Test if PWM */
+	   /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+	      /**************************/
+			/* Test the PWM selection */
+	      /**************************/
+
+			if (b_PWM <= 1) {
+		 /***************************/
+				/* Test if PWM initialised */
+		 /***************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (20 * b_PWM) +
+					(64 * b_ModulNbr));
+
+				if (dw_Status & 0x10) {
+		    /***********************/
+					/* Read the low timing */
+		    /***********************/
+
+					*pul_LowTiming =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 0 + (20 * b_PWM) +
+						(64 * b_ModulNbr));
+
+		    /************************/
+					/* Read the high timing */
+		    /************************/
+
+					*pul_HighTiming =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 4 + (20 * b_PWM) +
+						(64 * b_ModulNbr));
+
+		    /********************/
+					/* Read the command */
+		    /********************/
+
+					dw_Command = inl(devpriv->s_BoardInfos.
+						ui_Address + 8 + (20 * b_PWM) +
+						(64 * b_ModulNbr));
+
+					*pb_StartLevel =
+						(BYTE) ((dw_Command >> 5) & 1);
+					*pb_StopMode =
+						(BYTE) ((dw_Command >> 0) & 1);
+					*pb_StopLevel =
+						(BYTE) ((dw_Command >> 1) & 1);
+					*pb_ExternGate =
+						(BYTE) ((dw_Command >> 4) & 1);
+					*pb_InterruptEnable =
+						(BYTE) ((dw_Command >> 3) & 1);
+
+					if (*pb_StopLevel) {
+						*pb_StopLevel =
+							*pb_StopLevel +
+							(BYTE) ((dw_Command >>
+								2) & 1);
+					}
+
+		    /********************/
+					/* Read the command */
+		    /********************/
+
+					dw_Command = inl(devpriv->s_BoardInfos.
+						ui_Address + 8 + (20 * b_PWM) +
+						(64 * b_ModulNbr));
+
+					*pb_Enable =
+						(BYTE) ((dw_Command >> 0) & 1);
+
+					*pb_TimingUnit = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_PWMModuleInfo.
+						s_PWMInfo[b_PWM].b_TimingUnit;
+				}	// if (dw_Status & 0x10)
+				else {
+		    /***********************/
+					/* PWM not initialised */
+		    /***********************/
+					DPRINTK("PWM not initialised\n");
+					i_ReturnValue = -5;
+				}	// if (dw_Status & 0x10)
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+			else {
+		 /******************************/
+				/* Tor PWM selection is wrong */
+		 /******************************/
+				DPRINTK("Tor PWM selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+		} else {
+	      /**********************************/
+			/* The module is not a PWM module */
+	      /**********************************/
+			DPRINTK("The module is not a PWM module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     :INT i_APCI1710_InsnWritePWM(struct comedi_device *dev,
+struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                        |
++----------------------------------------------------------------------------+
+| Task              : Pwm Enable Disable and Set New Timing                  |
++----------------------------------------------------------------------------+
+| Input Parameters  :
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnWritePWM(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_WriteType;
+	INT i_ReturnValue = 0;
+	b_WriteType = CR_CHAN(insn->chanspec);
+
+	switch (b_WriteType) {
+	case APCI1710_PWM_ENABLE:
+		i_ReturnValue = i_APCI1710_EnablePWM(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) data[0],
+			(BYTE) data[1],
+			(BYTE) data[2],
+			(BYTE) data[3], (BYTE) data[4], (BYTE) data[5]);
+		break;
+
+	case APCI1710_PWM_DISABLE:
+		i_ReturnValue = i_APCI1710_DisablePWM(dev,
+			(BYTE) CR_AREF(insn->chanspec), (BYTE) data[0]);
+		break;
+
+	case APCI1710_PWM_NEWTIMING:
+		i_ReturnValue = i_APCI1710_SetNewPWMTiming(dev,
+			(BYTE) CR_AREF(insn->chanspec),
+			(BYTE) data[0],
+			(BYTE) data[1], (ULONG) data[2], (ULONG) data[3]);
+		break;
+
+	default:
+		printk("Write Config Parameter Wrong\n");
+	}
+
+	if (i_ReturnValue >= 0)
+		i_ReturnValue = insn->n;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_EnablePWM                         |
+|                                       (BYTE_  b_BoardHandle,               |
+|                                        BYTE_  b_ModulNbr,                  |
+|                                        BYTE_  b_PWM,                       |
+|                                        BYTE_  b_StartLevel,                |
+|                                        BYTE_  b_StopMode,                  |
+|                                        BYTE_  b_StopLevel,                 |
+|                                        BYTE_  b_ExternGate,                |
+|                                        BYTE_  b_InterruptEnable)           |
++----------------------------------------------------------------------------+
+| Task              : Enable the selected PWM (b_PWM) from selected module   |
+|                     (b_ModulNbr). You must calling the "i_APCI1710_InitPWM"|
+|                     function be for you call this function.                |
+|                     If you enable the PWM interrupt, the PWM generate a    |
+|                     interrupt after each period.                           |
+|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
+|                     Interrupt mask description chapter.                    |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle     : Handle of board APCI-1710    |
+|                     BYTE_ b_ModulNbr        : Selected module number       |
+|                                               (0 to 3)                     |
+|                     BYTE_ b_PWM             : Selected PWM (0 or 1)        |
+|                     BYTE_ b_StartLevel      : Start period level selection |
+|                                                0 : The period start with a |
+|                                                    low level               |
+|                                                1 : The period start with a |
+|                                                    high level              |
+|                     BYTE_ b_StopMode        : Stop mode selection          |
+|                                                0 : The PWM is stopped      |
+|                                                    directly after the      |
+|                                                    "i_APCI1710_DisablePWM" |
+|                                                    function and break the  |
+|                                                    last period             |
+|                                                1 : After the               |
+|                                                    "i_APCI1710_DisablePWM" |
+|                                                     function the PWM is    |
+|                                                     stopped at the end from|
+|                                                     last period cycle.     |
+|                     BYTE_ b_StopLevel       : Stop PWM level selection     |
+|                                                0 : The output signal keep  |
+|                                                    the level after the     |
+|                                                    "i_APCI1710_DisablePWM" |
+|                                                    function                |
+|                                                1 : The output signal is set|
+|                                                    to low after the        |
+|                                                    "i_APCI1710_DisablePWM" |
+|                                                    function                |
+|                                                2 : The output signal is set|
+|                                                    to high after the       |
+|                                                    "i_APCI1710_DisablePWM" |
+|                                                    function                |
+|                     BYTE_ b_ExternGate      : Extern gate action selection |
+|                                                0 : Extern gate signal not  |
+|                                                    used.                   |
+|                                                1 : Extern gate signal used.|
+|                     BYTE_ b_InterruptEnable : Enable or disable the PWM    |
+|                                               interrupt.                   |
+|                                               - APCI1710_ENABLE :          |
+|                                                 Enable the PWM interrupt   |
+|                                                 A interrupt occur after    |
+|                                                 each period                |
+|                                               - APCI1710_DISABLE :         |
+|                                                 Disable the PWM interrupt  |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0:  No error                                           |
+|                    -1:  The handle parameter of the board is wrong         |
+|                    -2:  Module selection wrong                             |
+|                    -3:  The module is not a PWM module                     |
+|                    -4:  PWM selection is wrong                             |
+|                    -5:  PWM not initialised see function                   |
+|                         "i_APCI1710_InitPWM"                               |
+|                    -6:  PWM start level selection is wrong                 |
+|                    -7:  PWM stop mode selection is wrong                   |
+|                    -8:  PWM stop level selection is wrong                  |
+|                    -9:  Extern gate signal selection is wrong              |
+|                    -10: Interrupt parameter is wrong                       |
+|                    -11: Interrupt function not initialised.                |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_EnablePWM(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_PWM,
+	BYTE b_StartLevel,
+	BYTE b_StopMode,
+	BYTE b_StopLevel, BYTE b_ExternGate, BYTE b_InterruptEnable)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+	DWORD dw_Command;
+
+	devpriv->tsk_Current = current;	// Save the current process task structure
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***************/
+		/* Test if PWM */
+	   /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+	      /**************************/
+			/* Test the PWM selection */
+	      /**************************/
+
+			if (b_PWM <= 1) {
+		 /***************************/
+				/* Test if PWM initialised */
+		 /***************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (20 * b_PWM) +
+					(64 * b_ModulNbr));
+
+				if (dw_Status & 0x10) {
+		    /**********************************/
+					/* Test the start level selection */
+		    /**********************************/
+
+					if (b_StartLevel <= 1) {
+		       /**********************/
+						/* Test the stop mode */
+		       /**********************/
+
+						if (b_StopMode <= 1) {
+			  /***********************/
+							/* Test the stop level */
+			  /***********************/
+
+							if (b_StopLevel <= 2) {
+			     /*****************************/
+								/* Test the extern gate mode */
+			     /*****************************/
+
+								if (b_ExternGate
+									<= 1) {
+				/*****************************/
+									/* Test the interrupt action */
+				/*****************************/
+
+									if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) {
+				   /******************************************/
+										/* Test if interrupt function initialised */
+				   /******************************************/
+
+				      /********************/
+										/* Read the command */
+				      /********************/
+
+										dw_Command
+											=
+											inl
+											(devpriv->
+											s_BoardInfos.
+											ui_Address
+											+
+											8
+											+
+											(20 * b_PWM) + (64 * b_ModulNbr));
+
+										dw_Command
+											=
+											dw_Command
+											&
+											0x80;
+
+				      /********************/
+										/* Make the command */
+				      /********************/
+
+										dw_Command
+											=
+											dw_Command
+											|
+											b_StopMode
+											|
+											(b_InterruptEnable
+											<<
+											3)
+											|
+											(b_ExternGate
+											<<
+											4)
+											|
+											(b_StartLevel
+											<<
+											5);
+
+										if (b_StopLevel & 3) {
+											dw_Command
+												=
+												dw_Command
+												|
+												2;
+
+											if (b_StopLevel & 2) {
+												dw_Command
+													=
+													dw_Command
+													|
+													4;
+											}
+										}
+
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_PWMModuleInfo.
+											s_PWMInfo
+											[b_PWM].
+											b_InterruptEnable
+											=
+											b_InterruptEnable;
+
+				      /*******************/
+										/* Set the command */
+				      /*******************/
+
+										outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr));
+
+				      /******************/
+										/* Enable the PWM */
+				      /******************/
+										outl(1, devpriv->s_BoardInfos.ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr));
+									}	// if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE)
+									else {
+				   /********************************/
+										/* Interrupt parameter is wrong */
+				   /********************************/
+										DPRINTK("Interrupt parameter is wrong\n");
+										i_ReturnValue
+											=
+											-10;
+									}	// if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE)
+								}	// if (b_ExternGate >= 0 && b_ExternGate <= 1)
+								else {
+				/*****************************************/
+									/* Extern gate signal selection is wrong */
+				/*****************************************/
+									DPRINTK("Extern gate signal selection is wrong\n");
+									i_ReturnValue
+										=
+										-9;
+								}	// if (b_ExternGate >= 0 && b_ExternGate <= 1)
+							}	// if (b_StopLevel >= 0 && b_StopLevel <= 2)
+							else {
+			     /*************************************/
+								/* PWM stop level selection is wrong */
+			     /*************************************/
+								DPRINTK("PWM stop level selection is wrong\n");
+								i_ReturnValue =
+									-8;
+							}	// if (b_StopLevel >= 0 && b_StopLevel <= 2)
+						}	// if (b_StopMode >= 0 && b_StopMode <= 1)
+						else {
+			  /************************************/
+							/* PWM stop mode selection is wrong */
+			  /************************************/
+							DPRINTK("PWM stop mode selection is wrong\n");
+							i_ReturnValue = -7;
+						}	// if (b_StopMode >= 0 && b_StopMode <= 1)
+					}	// if (b_StartLevel >= 0 && b_StartLevel <= 1)
+					else {
+		       /**************************************/
+						/* PWM start level selection is wrong */
+		       /**************************************/
+						DPRINTK("PWM start level selection is wrong\n");
+						i_ReturnValue = -6;
+					}	// if (b_StartLevel >= 0 && b_StartLevel <= 1)
+				}	// if (dw_Status & 0x10)
+				else {
+		    /***********************/
+					/* PWM not initialised */
+		    /***********************/
+					DPRINTK("PWM not initialised\n");
+					i_ReturnValue = -5;
+				}	// if (dw_Status & 0x10)
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+			else {
+		 /******************************/
+				/* Tor PWM selection is wrong */
+		 /******************************/
+				DPRINTK("Tor PWM selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+		} else {
+	      /**********************************/
+			/* The module is not a PWM module */
+	      /**********************************/
+			DPRINTK("The module is not a PWM module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_DisablePWM (BYTE_  b_BoardHandle,     |
+|                                                  BYTE_  b_ModulNbr,        |
+|                                                  BYTE_  b_PWM)             |
++----------------------------------------------------------------------------+
+| Task              : Disable the selected PWM (b_PWM) from selected module  |
+|                     (b_ModulNbr). The output signal level depend of the    |
+|                     initialisation by the "i_APCI1710_EnablePWM".          |
+|                     See the b_StartLevel, b_StopMode and b_StopLevel       |
+|                     parameters from this function.                         |
++----------------------------------------------------------------------------+
+| Input Parameters  :BYTE_ b_BoardHandle : Handle of board APCI-1710         |
+|                    BYTE_ b_ModulNbr    : Selected module number (0 to 3)   |
+|                    BYTE_ b_PWM         : Selected PWM (0 or 1)             |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a PWM module                     |
+|                     -4: PWM selection is wrong                             |
+|                     -5: PWM not initialised see function                   |
+|                         "i_APCI1710_InitPWM"                               |
+|                     -6: PWM not enabled see function                       |
+|                         "i_APCI1710_EnablePWM"                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_DisablePWM(struct comedi_device * dev, BYTE b_ModulNbr, BYTE b_PWM)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***************/
+		/* Test if PWM */
+	   /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+	      /**************************/
+			/* Test the PWM selection */
+	      /**************************/
+
+			if (b_PWM <= 1) {
+		 /***************************/
+				/* Test if PWM initialised */
+		 /***************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (20 * b_PWM) +
+					(64 * b_ModulNbr));
+
+				if (dw_Status & 0x10) {
+		    /***********************/
+					/* Test if PWM enabled */
+		    /***********************/
+
+					if (dw_Status & 0x1) {
+		       /*******************/
+						/* Disable the PWM */
+		       /*******************/
+						outl(0, devpriv->s_BoardInfos.
+							ui_Address + 12 +
+							(20 * b_PWM) +
+							(64 * b_ModulNbr));
+					}	// if (dw_Status & 0x1)
+					else {
+		       /*******************/
+						/* PWM not enabled */
+		       /*******************/
+						DPRINTK("PWM not enabled\n");
+						i_ReturnValue = -6;
+					}	// if (dw_Status & 0x1)
+				}	// if (dw_Status & 0x10)
+				else {
+		    /***********************/
+					/* PWM not initialised */
+		    /***********************/
+					DPRINTK(" PWM not initialised\n");
+					i_ReturnValue = -5;
+				}	// if (dw_Status & 0x10)
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+			else {
+		 /******************************/
+				/* Tor PWM selection is wrong */
+		 /******************************/
+				DPRINTK("Tor PWM selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+		} else {
+	      /**********************************/
+			/* The module is not a PWM module */
+	      /**********************************/
+			DPRINTK("The module is not a PWM module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_SetNewPWMTiming                       |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_PWM,                    |
+|                                        BYTE_     b_ClockSelection,         |
+|                                        BYTE_     b_TimingUnit,             |
+|                                        ULONG_   ul_LowTiming,              |
+|                                        ULONG_   ul_HighTiming)             |
++----------------------------------------------------------------------------+
+| Task              : Set a new timing. The ul_LowTiming, ul_HighTiming and  |
+|                     ul_TimingUnit determine the low/high timing base for   |
+|                     the period.                                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_     b_BoardHandle    : Handle of board APCI-1710 |
+|                     BYTE_     b_ModulNbr       : Module number to configure|
+|                                                  (0 to 3)                  |
+|                     BYTE_     b_PWM            : Selected PWM (0 or 1).    |
+|                     BYTE_     b_TimingUnit     : Base timing Unit (0 to 4) |
+|                                                       0 : ns               |
+|                                                       1 : æs               |
+|                                                       2 : ms               |
+|                                                       3 : s                |
+|                                                       4 : mn               |
+|                     ULONG_    ul_LowTiming     : Low base timing value.    |
+|                     ULONG_    ul_HighTiming    : High base timing value.   |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: Module selection wrong                              |
+|                    -3: The module is not a PWM module                      |
+|                    -4: PWM selection is wrong                              |
+|                    -5: PWM not initialised                                 |
+|                    -6: Timing Unit selection is wrong                      |
+|                    -7: Low base timing selection is wrong                  |
+|                    -8: High base timing selection is wrong                 |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_SetNewPWMTiming(struct comedi_device * dev,
+	BYTE b_ModulNbr,
+	BYTE b_PWM, BYTE b_TimingUnit, ULONG ul_LowTiming, ULONG ul_HighTiming)
+{
+	BYTE b_ClockSelection;
+	INT i_ReturnValue = 0;
+	ULONG ul_LowTimerValue = 0;
+	ULONG ul_HighTimerValue = 0;
+	ULONG ul_RealLowTiming = 0;
+	ULONG ul_RealHighTiming = 0;
+	DWORD dw_Status;
+	DWORD dw_Command;
+	double d_RealLowTiming = 0;
+	double d_RealHighTiming = 0;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***************/
+		/* Test if PWM */
+	   /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+	      /**************************/
+			/* Test the PWM selection */
+	      /**************************/
+
+			if (b_PWM <= 1) {
+		 /***************************/
+				/* Test if PWM initialised */
+		 /***************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (20 * b_PWM) +
+					(64 * b_ModulNbr));
+
+				if (dw_Status & 0x10) {
+					b_ClockSelection = devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_PWMModuleInfo.
+						b_ClockSelection;
+
+		    /************************/
+					/* Test the timing unit */
+		    /************************/
+
+					if (b_TimingUnit <= 4) {
+		       /*********************************/
+						/* Test the low timing selection */
+		       /*********************************/
+
+						if (((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 0)
+								&& (ul_LowTiming
+									>= 266)
+								&& (ul_LowTiming
+									<=
+									0xFFFFFFFFUL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 1)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									571230650UL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 2)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									571230UL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 3)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									571UL))
+							|| ((b_ClockSelection ==
+									APCI1710_30MHZ)
+								&& (b_TimingUnit
+									== 4)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<= 9UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 0)
+								&& (ul_LowTiming
+									>= 242)
+								&& (ul_LowTiming
+									<=
+									0xFFFFFFFFUL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 1)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									519691043UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 2)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									519691UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 3)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									520UL))
+							|| ((b_ClockSelection ==
+									APCI1710_33MHZ)
+								&& (b_TimingUnit
+									== 4)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<= 8UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 0)
+								&& (ul_LowTiming
+									>= 200)
+								&& (ul_LowTiming
+									<=
+									0xFFFFFFFFUL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 1)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									429496729UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 2)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									429496UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 3)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									429UL))
+							|| ((b_ClockSelection ==
+									APCI1710_40MHZ)
+								&& (b_TimingUnit
+									== 4)
+								&& (ul_LowTiming
+									>= 1)
+								&& (ul_LowTiming
+									<=
+									7UL))) {
+			  /**********************************/
+							/* Test the High timing selection */
+			  /**********************************/
+
+							if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) {
+			     /************************************/
+								/* Calculate the low division fator */
+			     /************************************/
+
+								fpu_begin();
+								switch (b_TimingUnit) {
+				/******/
+									/* ns */
+				/******/
+
+								case 0:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_LowTimerValue
+										=
+										(ULONG)
+										(ul_LowTiming
+										*
+										(0.00025 * b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealLowTiming
+										=
+										(ULONG)
+										(ul_LowTimerValue
+										/
+										(0.00025 * (double)b_ClockSelection));
+									d_RealLowTiming
+										=
+										(double)
+										ul_LowTimerValue
+										/
+										(0.00025
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
+										ul_RealLowTiming
+											=
+											ul_RealLowTiming
+											+
+											1;
+									}
+
+									ul_LowTiming
+										=
+										ul_LowTiming
+										-
+										1;
+									ul_LowTimerValue
+										=
+										ul_LowTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_LowTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/******/
+									/* æs */
+				/******/
+
+								case 1:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_LowTimerValue
+										=
+										(ULONG)
+										(ul_LowTiming
+										*
+										(0.25 * b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealLowTiming
+										=
+										(ULONG)
+										(ul_LowTimerValue
+										/
+										(0.25 * (double)b_ClockSelection));
+									d_RealLowTiming
+										=
+										(double)
+										ul_LowTimerValue
+										/
+										(
+										(double)
+										0.25
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
+										ul_RealLowTiming
+											=
+											ul_RealLowTiming
+											+
+											1;
+									}
+
+									ul_LowTiming
+										=
+										ul_LowTiming
+										-
+										1;
+									ul_LowTimerValue
+										=
+										ul_LowTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_LowTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/******/
+									/* ms */
+				/******/
+
+								case 2:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_LowTimerValue
+										=
+										ul_LowTiming
+										*
+										(250.0
+										*
+										b_ClockSelection);
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealLowTiming
+										=
+										(ULONG)
+										(ul_LowTimerValue
+										/
+										(250.0 * (double)b_ClockSelection));
+									d_RealLowTiming
+										=
+										(double)
+										ul_LowTimerValue
+										/
+										(250.0
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
+										ul_RealLowTiming
+											=
+											ul_RealLowTiming
+											+
+											1;
+									}
+
+									ul_LowTiming
+										=
+										ul_LowTiming
+										-
+										1;
+									ul_LowTimerValue
+										=
+										ul_LowTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_LowTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/*****/
+									/* s */
+				/*****/
+
+								case 3:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_LowTimerValue
+										=
+										(ULONG)
+										(ul_LowTiming
+										*
+										(250000.0
+											*
+											b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealLowTiming
+										=
+										(ULONG)
+										(ul_LowTimerValue
+										/
+										(250000.0
+											*
+											(double)
+											b_ClockSelection));
+									d_RealLowTiming
+										=
+										(double)
+										ul_LowTimerValue
+										/
+										(250000.0
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
+										ul_RealLowTiming
+											=
+											ul_RealLowTiming
+											+
+											1;
+									}
+
+									ul_LowTiming
+										=
+										ul_LowTiming
+										-
+										1;
+									ul_LowTimerValue
+										=
+										ul_LowTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_LowTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/******/
+									/* mn */
+				/******/
+
+								case 4:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_LowTimerValue
+										=
+										(ULONG)
+										(
+										(ul_LowTiming
+											*
+											60)
+										*
+										(250000.0
+											*
+											b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
+										ul_LowTimerValue
+											=
+											ul_LowTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealLowTiming
+										=
+										(ULONG)
+										(ul_LowTimerValue
+										/
+										(250000.0
+											*
+											(double)
+											b_ClockSelection))
+										/
+										60;
+									d_RealLowTiming
+										=
+										(
+										(double)
+										ul_LowTimerValue
+										/
+										(250000.0
+											*
+											(double)
+											b_ClockSelection))
+										/
+										60.0;
+
+									if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealLowTiming + 0.5)) {
+										ul_RealLowTiming
+											=
+											ul_RealLowTiming
+											+
+											1;
+									}
+
+									ul_LowTiming
+										=
+										ul_LowTiming
+										-
+										1;
+									ul_LowTimerValue
+										=
+										ul_LowTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_LowTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_LowTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+								}
+
+			     /*************************************/
+								/* Calculate the high division fator */
+			     /*************************************/
+
+								switch (b_TimingUnit) {
+				/******/
+									/* ns */
+				/******/
+
+								case 0:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_HighTimerValue
+										=
+										(ULONG)
+										(ul_HighTiming
+										*
+										(0.00025 * b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealHighTiming
+										=
+										(ULONG)
+										(ul_HighTimerValue
+										/
+										(0.00025 * (double)b_ClockSelection));
+									d_RealHighTiming
+										=
+										(double)
+										ul_HighTimerValue
+										/
+										(0.00025
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
+										ul_RealHighTiming
+											=
+											ul_RealHighTiming
+											+
+											1;
+									}
+
+									ul_HighTiming
+										=
+										ul_HighTiming
+										-
+										1;
+									ul_HighTimerValue
+										=
+										ul_HighTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_HighTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/******/
+									/* æs */
+				/******/
+
+								case 1:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_HighTimerValue
+										=
+										(ULONG)
+										(ul_HighTiming
+										*
+										(0.25 * b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealHighTiming
+										=
+										(ULONG)
+										(ul_HighTimerValue
+										/
+										(0.25 * (double)b_ClockSelection));
+									d_RealHighTiming
+										=
+										(double)
+										ul_HighTimerValue
+										/
+										(
+										(double)
+										0.25
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
+										ul_RealHighTiming
+											=
+											ul_RealHighTiming
+											+
+											1;
+									}
+
+									ul_HighTiming
+										=
+										ul_HighTiming
+										-
+										1;
+									ul_HighTimerValue
+										=
+										ul_HighTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_HighTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/******/
+									/* ms */
+				/******/
+
+								case 2:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_HighTimerValue
+										=
+										ul_HighTiming
+										*
+										(250.0
+										*
+										b_ClockSelection);
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealHighTiming
+										=
+										(ULONG)
+										(ul_HighTimerValue
+										/
+										(250.0 * (double)b_ClockSelection));
+									d_RealHighTiming
+										=
+										(double)
+										ul_HighTimerValue
+										/
+										(250.0
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
+										ul_RealHighTiming
+											=
+											ul_RealHighTiming
+											+
+											1;
+									}
+
+									ul_HighTiming
+										=
+										ul_HighTiming
+										-
+										1;
+									ul_HighTimerValue
+										=
+										ul_HighTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_HighTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/*****/
+									/* s */
+				/*****/
+
+								case 3:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_HighTimerValue
+										=
+										(ULONG)
+										(ul_HighTiming
+										*
+										(250000.0
+											*
+											b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealHighTiming
+										=
+										(ULONG)
+										(ul_HighTimerValue
+										/
+										(250000.0
+											*
+											(double)
+											b_ClockSelection));
+									d_RealHighTiming
+										=
+										(double)
+										ul_HighTimerValue
+										/
+										(250000.0
+										*
+										(double)
+										b_ClockSelection);
+
+									if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
+										ul_RealHighTiming
+											=
+											ul_RealHighTiming
+											+
+											1;
+									}
+
+									ul_HighTiming
+										=
+										ul_HighTiming
+										-
+										1;
+									ul_HighTimerValue
+										=
+										ul_HighTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_HighTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+
+				/******/
+									/* mn */
+				/******/
+
+								case 4:
+
+					/******************/
+									/* Timer 0 factor */
+					/******************/
+
+									ul_HighTimerValue
+										=
+										(ULONG)
+										(
+										(ul_HighTiming
+											*
+											60)
+										*
+										(250000.0
+											*
+											b_ClockSelection));
+
+					/*******************/
+									/* Round the value */
+					/*******************/
+
+									if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
+										ul_HighTimerValue
+											=
+											ul_HighTimerValue
+											+
+											1;
+									}
+
+					/*****************************/
+									/* Calculate the real timing */
+					/*****************************/
+
+									ul_RealHighTiming
+										=
+										(ULONG)
+										(ul_HighTimerValue
+										/
+										(250000.0
+											*
+											(double)
+											b_ClockSelection))
+										/
+										60;
+									d_RealHighTiming
+										=
+										(
+										(double)
+										ul_HighTimerValue
+										/
+										(250000.0
+											*
+											(double)
+											b_ClockSelection))
+										/
+										60.0;
+
+									if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealHighTiming + 0.5)) {
+										ul_RealHighTiming
+											=
+											ul_RealHighTiming
+											+
+											1;
+									}
+
+									ul_HighTiming
+										=
+										ul_HighTiming
+										-
+										1;
+									ul_HighTimerValue
+										=
+										ul_HighTimerValue
+										-
+										2;
+
+									if (b_ClockSelection != APCI1710_40MHZ) {
+										ul_HighTimerValue
+											=
+											(ULONG)
+											(
+											(double)
+											(ul_HighTimerValue)
+											*
+											1.007752288);
+									}
+
+									break;
+								}
+
+								fpu_end();
+
+			     /************************/
+								/* Save the timing unit */
+			     /************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PWMModuleInfo.
+									s_PWMInfo
+									[b_PWM].
+									b_TimingUnit
+									=
+									b_TimingUnit;
+
+			     /****************************/
+								/* Save the low base timing */
+			     /****************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PWMModuleInfo.
+									s_PWMInfo
+									[b_PWM].
+									d_LowTiming
+									=
+									d_RealLowTiming;
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PWMModuleInfo.
+									s_PWMInfo
+									[b_PWM].
+									ul_RealLowTiming
+									=
+									ul_RealLowTiming;
+
+			     /****************************/
+								/* Save the high base timing */
+			     /****************************/
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PWMModuleInfo.
+									s_PWMInfo
+									[b_PWM].
+									d_HighTiming
+									=
+									d_RealHighTiming;
+
+								devpriv->
+									s_ModuleInfo
+									[b_ModulNbr].
+									s_PWMModuleInfo.
+									s_PWMInfo
+									[b_PWM].
+									ul_RealHighTiming
+									=
+									ul_RealHighTiming;
+
+			     /************************/
+								/* Write the low timing */
+			     /************************/
+
+								outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr));
+
+			     /*************************/
+								/* Write the high timing */
+			     /*************************/
+
+								outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr));
+
+			     /***************************/
+								/* Set the clock selection */
+			     /***************************/
+
+								dw_Command =
+									inl
+									(devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 8 +
+									(20 * b_PWM) + (64 * b_ModulNbr));
+
+								dw_Command =
+									dw_Command
+									& 0x7F;
+
+								if (b_ClockSelection == APCI1710_40MHZ) {
+									dw_Command
+										=
+										dw_Command
+										|
+										0x80;
+								}
+
+			     /***************************/
+								/* Set the clock selection */
+			     /***************************/
+
+								outl(dw_Command,
+									devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 8 +
+									(20 * b_PWM) + (64 * b_ModulNbr));
+							} else {
+			     /***************************************/
+								/* High base timing selection is wrong */
+			     /***************************************/
+								DPRINTK("High base timing selection is wrong\n");
+								i_ReturnValue =
+									-8;
+							}
+						} else {
+			  /**************************************/
+							/* Low base timing selection is wrong */
+			  /**************************************/
+							DPRINTK("Low base timing selection is wrong\n");
+							i_ReturnValue = -7;
+						}
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+					else {
+		       /**********************************/
+						/* Timing unit selection is wrong */
+		       /**********************************/
+						DPRINTK("Timing unit selection is wrong\n");
+						i_ReturnValue = -6;
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+				}	// if (dw_Status & 0x10)
+				else {
+		    /***********************/
+					/* PWM not initialised */
+		    /***********************/
+					DPRINTK("PWM not initialised\n");
+					i_ReturnValue = -5;
+				}	// if (dw_Status & 0x10)
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+			else {
+		 /******************************/
+				/* Tor PWM selection is wrong */
+		 /******************************/
+				DPRINTK("Tor PWM selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+		} else {
+	      /**********************************/
+			/* The module is not a PWM module */
+	      /**********************************/
+			DPRINTK("The module is not a PWM module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetPWMStatus                          |
+|                               (BYTE_    b_BoardHandle,                     |
+|                                BYTE_    b_ModulNbr,                        |
+|                                BYTE_    b_PWM,                             |
+|                                PBYTE_  pb_PWMOutputStatus,                 |
+|                                PBYTE_  pb_ExternGateStatus)                |
++----------------------------------------------------------------------------+
+| Task              : Return the status from selected PWM (b_PWM) from       |
+|                     selected module (b_ModulNbr).                          |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_  b_BoardHandle : Handle of board APCI-1710       |
+|                     BYTE_  b_PWM         : Selected PWM (0 or 1)           |
+|                     BYTE_  b_ModulNbr    : Selected module number (0 to 3)
+	b_ModulNbr			=(BYTE)  CR_AREF(insn->chanspec);
+	b_PWM				=(BYTE)  data[0];
+
+ |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_  pb_PWMOutputStatus  : Return the PWM output    |
+|                                                   level status.            |
+|                                                    0 : The PWM output level|
+|                                                        is low.             |
+|                                                    1 : The PWM output level|
+|                                                        is high.            |
+|                     PBYTE_  pb_ExternGateStatus : Return the extern gate   |
+|                                                   level status.            |
+|                                                    0 : The extern gate is  |
+|                                                        low.                |
+|                                                    1 : The extern gate is  |
+|                                                        high.
+    pb_PWMOutputStatus	=(PBYTE) data[0];
+	pb_ExternGateStatus =(PBYTE) data[1];             |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a PWM module                     |
+|                     -4: PWM selection is wrong                             |
+|                     -5: PWM not initialised see function                   |
+|                         "i_APCI1710_InitPWM"                               |
+|                     -6: PWM not enabled see function "i_APCI1710_EnablePWM"|
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnReadGetPWMStatus(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+
+	BYTE b_ModulNbr;
+	BYTE b_PWM;
+	PBYTE pb_PWMOutputStatus;
+	PBYTE pb_ExternGateStatus;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_PWM = (BYTE) CR_CHAN(insn->chanspec);
+	pb_PWMOutputStatus = (PBYTE) & data[0];
+	pb_ExternGateStatus = (PBYTE) & data[1];
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***************/
+		/* Test if PWM */
+	   /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+	      /**************************/
+			/* Test the PWM selection */
+	      /**************************/
+
+			if (b_PWM <= 1) {
+		 /***************************/
+				/* Test if PWM initialised */
+		 /***************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 12 + (20 * b_PWM) +
+					(64 * b_ModulNbr));
+
+				if (dw_Status & 0x10) {
+		    /***********************/
+					/* Test if PWM enabled */
+		    /***********************/
+
+					if (dw_Status & 0x1) {
+						*pb_PWMOutputStatus =
+							(BYTE) ((dw_Status >> 7)
+							& 1);
+						*pb_ExternGateStatus =
+							(BYTE) ((dw_Status >> 6)
+							& 1);
+					}	// if (dw_Status & 0x1)
+					else {
+		       /*******************/
+						/* PWM not enabled */
+		       /*******************/
+
+						DPRINTK("PWM not enabled \n");
+						i_ReturnValue = -6;
+					}	// if (dw_Status & 0x1)
+				}	// if (dw_Status & 0x10)
+				else {
+		    /***********************/
+					/* PWM not initialised */
+		    /***********************/
+
+					DPRINTK("PWM not initialised\n");
+					i_ReturnValue = -5;
+				}	// if (dw_Status & 0x10)
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+			else {
+		 /******************************/
+				/* Tor PWM selection is wrong */
+		 /******************************/
+
+				DPRINTK("Tor PWM selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_PWM >= 0 && b_PWM <= 1)
+		} else {
+	      /**********************************/
+			/* The module is not a PWM module */
+	      /**********************************/
+
+			DPRINTK("The module is not a PWM module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+INT i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	data[0] = devpriv->s_InterruptParameters.
+		s_FIFOInterruptParameters[devpriv->
+		s_InterruptParameters.ui_Read].b_OldModuleMask;
+	data[1] = devpriv->s_InterruptParameters.
+		s_FIFOInterruptParameters[devpriv->
+		s_InterruptParameters.ui_Read].ul_OldInterruptMask;
+	data[2] = devpriv->s_InterruptParameters.
+		s_FIFOInterruptParameters[devpriv->
+		s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
+
+			     /**************************/
+	/* Increment the read FIFO */
+			     /***************************/
+
+	devpriv->
+		s_InterruptParameters.
+		ui_Read = (devpriv->
+		s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
+
+	return insn->n;
+
+}

+ 76 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h

@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_30MHZ		30
+#define APCI1710_33MHZ		33
+#define APCI1710_40MHZ		40
+
+#define APCI1710_PWM_INIT		0
+#define APCI1710_PWM_GETINITDATA	1
+
+#define APCI1710_PWM_DISABLE		0
+#define APCI1710_PWM_ENABLE		1
+#define APCI1710_PWM_NEWTIMING		2
+
+INT i_APCI1710_InsnConfigPWM(struct comedi_device *dev, struct comedi_subdevice *s,
+			     struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InitPWM(struct comedi_device *dev,
+		       BYTE b_ModulNbr,
+		       BYTE b_PWM,
+		       BYTE b_ClockSelection,
+		       BYTE b_TimingUnit,
+		       ULONG ul_LowTiming,
+		       ULONG ul_HighTiming,
+		       PULONG pul_RealLowTiming, PULONG pul_RealHighTiming);
+
+INT i_APCI1710_GetPWMInitialisation(struct comedi_device *dev,
+				    BYTE b_ModulNbr,
+				    BYTE b_PWM,
+				    PBYTE pb_TimingUnit,
+				    PULONG pul_LowTiming,
+				    PULONG pul_HighTiming,
+				    PBYTE pb_StartLevel,
+				    PBYTE pb_StopMode,
+				    PBYTE pb_StopLevel,
+				    PBYTE pb_ExternGate,
+				    PBYTE pb_InterruptEnable, PBYTE pb_Enable);
+
+INT i_APCI1710_InsnWritePWM(struct comedi_device *dev, struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_EnablePWM(struct comedi_device *dev,
+			 BYTE b_ModulNbr,
+			 BYTE b_PWM,
+			 BYTE b_StartLevel,
+			 BYTE b_StopMode,
+			 BYTE b_StopLevel, BYTE b_ExternGate,
+			 BYTE b_InterruptEnable);
+
+INT i_APCI1710_SetNewPWMTiming(struct comedi_device *dev,
+			       BYTE b_ModulNbr,
+			       BYTE b_PWM, BYTE b_TimingUnit,
+			       ULONG ul_LowTiming, ULONG ul_HighTiming);
+
+INT i_APCI1710_DisablePWM(struct comedi_device *dev, BYTE b_ModulNbr, BYTE b_PWM);
+
+INT i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev,
+					struct comedi_subdevice *s,
+					struct comedi_insn *insn, unsigned int *data);

+ 848 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c

@@ -0,0 +1,848 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : SSI.C           | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 SSI counter module                          |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 13/05/98 | S. Weber  | SSI digital input / output implementation      |
+  |----------|-----------|------------------------------------------------|
+  | 22/03/00 | C.Guinot  | 0100/0226 -> 0200/0227                         |
+  |          |           | Änderung in InitSSI Funktion                   |
+  |          |           | b_SSIProfile >= 2 anstatt b_SSIProfile > 2     |
+  |          |           |                                                |
+  +-----------------------------------------------------------------------+
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "APCI1710_Ssi.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitSSI                               |
+|                               (BYTE_    b_BoardHandle,                     |
+|                                BYTE_    b_ModulNbr,                        |
+|                                BYTE_    b_SSIProfile,                      |
+|                                BYTE_    b_PositionTurnLength,              |
+|                                BYTE_    b_TurnCptLength,                   |
+|                                BYTE_    b_PCIInputClock,                   |
+|                                ULONG_  ul_SSIOutputClock,                  |
+|                                BYTE_    b_SSICountingMode)                 |
++----------------------------------------------------------------------------+
+| Task              : Configure the SSI operating mode from selected module  |
+|                     (b_ModulNbr). You must calling this function be for you|
+|                     call any other function witch access of SSI.           |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 3)       |
+|                     BYTE_  b_SSIProfile         : Selection from SSI       |
+|                                                   profile length (2 to 32).|
+|                     BYTE_  b_PositionTurnLength : Selection from SSI       |
+|                                                   position data length     |
+|                                                   (1 to 31).               |
+|                     BYTE_  b_TurnCptLength      : Selection from SSI turn  |
+|                                                   counter data length      |
+|                                                   (1 to 31).               |
+|                     BYTE   b_PCIInputClock      : Selection from PCI bus   |
+|                                                   clock                    |
+|                                                 - APCI1710_30MHZ :         |
+|                                                   The PC have a PCI bus    |
+|                                                   clock from 30 MHz        |
+|                                                 - APCI1710_33MHZ :         |
+|                                                   The PC have a PCI bus    |
+|                                                   clock from 33 MHz        |
+|                     ULONG_ ul_SSIOutputClock    : Selection from SSI output|
+|                                                   clock.                   |
+|                                                   From  229 to 5 000 000 Hz|
+|                                                   for 30 MHz selection.    |
+|                                                   From  252 to 5 000 000 Hz|
+|                                                   for 33 MHz selection.    |
+|                     BYTE   b_SSICountingMode    : SSI counting mode        |
+|                                                   selection                |
+|                                                 - APCI1710_BINARY_MODE :   |
+|                                                    Binary counting mode.   |
+|                                                 - APCI1710_GRAY_MODE :     |
+|                                                    Gray counting mode.
+
+	b_ModulNbr			= CR_AREF(insn->chanspec);
+	b_SSIProfile		= (BYTE) data[0];
+	b_PositionTurnLength= (BYTE) data[1];
+	b_TurnCptLength		= (BYTE) data[2];
+	b_PCIInputClock		= (BYTE) data[3];
+	ul_SSIOutputClock	= (ULONG) data[4];
+	b_SSICountingMode	= (BYTE)  data[5];     |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a SSI module                      |
+|                    -4: The selected SSI profile length is wrong            |
+|                    -5: The selected SSI position data length is wrong      |
+|                    -6: The selected SSI turn counter data length is wrong  |
+|                    -7: The selected PCI input clock is wrong               |
+|                    -8: The selected SSI output clock is wrong              |
+|                    -9: The selected SSI counting mode parameter is wrong   |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigInitSSI(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	UINT ui_TimerValue;
+	BYTE b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength,
+		b_PCIInputClock, b_SSICountingMode;
+	ULONG ul_SSIOutputClock;
+
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_SSIProfile = (BYTE) data[0];
+	b_PositionTurnLength = (BYTE) data[1];
+	b_TurnCptLength = (BYTE) data[2];
+	b_PCIInputClock = (BYTE) data[3];
+	ul_SSIOutputClock = (ULONG) data[4];
+	b_SSICountingMode = (BYTE) data[5];
+
+	i_ReturnValue = insn->n;
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if SSI counter */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
+	      /*******************************/
+			/* Test the SSI profile length */
+	      /*******************************/
+
+			// CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2
+			if (b_SSIProfile >= 2 && b_SSIProfile < 33) {
+		 /*************************************/
+				/* Test the SSI position data length */
+		 /*************************************/
+
+				if (b_PositionTurnLength > 0
+					&& b_PositionTurnLength < 32) {
+		    /*****************************************/
+					/* Test the SSI turn counter data length */
+		    /*****************************************/
+
+					if (b_TurnCptLength > 0
+						&& b_TurnCptLength < 32) {
+		       /***************************/
+						/* Test the profile length */
+		       /***************************/
+
+						if ((b_TurnCptLength +
+								b_PositionTurnLength)
+							<= b_SSIProfile) {
+			  /****************************/
+							/* Test the PCI input clock */
+			  /****************************/
+
+							if (b_PCIInputClock ==
+								APCI1710_30MHZ
+								||
+								b_PCIInputClock
+								==
+								APCI1710_33MHZ)
+							{
+			     /*************************/
+								/* Test the output clock */
+			     /*************************/
+
+								if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) {
+									if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) {
+				   /**********************/
+										/* Save configuration */
+				   /**********************/
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_SSICounterInfo.
+											b_SSIProfile
+											=
+											b_SSIProfile;
+
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_SSICounterInfo.
+											b_PositionTurnLength
+											=
+											b_PositionTurnLength;
+
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_SSICounterInfo.
+											b_TurnCptLength
+											=
+											b_TurnCptLength;
+
+				   /*********************************/
+										/* Initialise the profile length */
+				   /*********************************/
+
+										if (b_SSICountingMode == APCI1710_BINARY_MODE) {
+
+											outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
+										} else {
+
+											outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
+										}
+
+				   /******************************/
+										/* Calculate the output clock */
+				   /******************************/
+
+										ui_TimerValue
+											=
+											(UINT)
+											(
+											((ULONG) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock);
+
+				   /************************/
+										/* Initialise the timer */
+				   /************************/
+
+										outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
+
+				   /********************************/
+										/* Initialise the counting mode */
+				   /********************************/
+
+										outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
+
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_SSICounterInfo.
+											b_SSIInit
+											=
+											1;
+									} else {
+				   /*****************************************************/
+										/* The selected SSI counting mode parameter is wrong */
+				   /*****************************************************/
+
+										DPRINTK("The selected SSI counting mode parameter is wrong\n");
+										i_ReturnValue
+											=
+											-9;
+									}
+								} else {
+				/******************************************/
+									/* The selected SSI output clock is wrong */
+				/******************************************/
+
+									DPRINTK("The selected SSI output clock is wrong\n");
+									i_ReturnValue
+										=
+										-8;
+								}
+							} else {
+			     /*****************************************/
+								/* The selected PCI input clock is wrong */
+			     /*****************************************/
+
+								DPRINTK("The selected PCI input clock is wrong\n");
+								i_ReturnValue =
+									-7;
+							}
+						} else {
+			  /********************************************/
+							/* The selected SSI profile length is wrong */
+			  /********************************************/
+
+							DPRINTK("The selected SSI profile length is wrong\n");
+							i_ReturnValue = -4;
+						}
+					} else {
+		       /******************************************************/
+						/* The selected SSI turn counter data length is wrong */
+		       /******************************************************/
+
+						DPRINTK("The selected SSI turn counter data length is wrong\n");
+						i_ReturnValue = -6;
+					}
+				} else {
+		    /**************************************************/
+					/* The selected SSI position data length is wrong */
+		    /**************************************************/
+
+					DPRINTK("The selected SSI position data length is wrong\n");
+					i_ReturnValue = -5;
+				}
+			} else {
+		 /********************************************/
+				/* The selected SSI profile length is wrong */
+		 /********************************************/
+
+				DPRINTK("The selected SSI profile length is wrong\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /**********************************/
+			/* The module is not a SSI module */
+	      /**********************************/
+
+			DPRINTK("The module is not a SSI module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_  i_APCI1710_Read1SSIValue                        |
+|                               (BYTE_     b_BoardHandle,                    |
+|                                BYTE_     b_ModulNbr,                       |
+|                                BYTE_     b_SelectedSSI,                    |
+|                                PULONG_ pul_Position,                       |
+|                                PULONG_ pul_TurnCpt)
+ INT i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s,
+	struct comedi_insn *insn,unsigned int *data)                       |
++----------------------------------------------------------------------------+
+| Task              :
+
+
+						Read the selected SSI counter (b_SelectedSSI) from     |
+|                     selected module (b_ModulNbr).
+						or Read all SSI counter (b_SelectedSSI) from              |
+|                     selected module (b_ModulNbr).                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 3)       |
+|                     BYTE_ b_SelectedSSI         : Selection from SSI       |
+|                                                   counter (0 to 2)
+
+    b_ModulNbr		=   (BYTE) CR_AREF(insn->chanspec);
+	b_SelectedSSI	=	(BYTE) CR_CHAN(insn->chanspec); (in case of single ssi)
+	b_ReadType		=	(BYTE) CR_RANGE(insn->chanspec);
+|
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pul_Position       : SSI position in the turn |
+|                     PULONG_  pul_TurnCpt        : Number of turns
+
+pul_Position	=	(PULONG) &data[0];
+	pul_TurnCpt		=	(PULONG) &data[1];         |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a SSI module                      |
+|                    -4: SSI not initialised see function                    |
+|                        "i_APCI1710_InitSSI"                                |
+|                    -5: The selected SSI is wrong                           |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnReadSSIValue(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	BYTE b_Cpt;
+	BYTE b_Length;
+	BYTE b_Schift;
+	BYTE b_SSICpt;
+	DWORD dw_And;
+	DWORD dw_And1;
+	DWORD dw_And2;
+	DWORD dw_StatusReg;
+	DWORD dw_CounterValue;
+	BYTE b_ModulNbr;
+	BYTE b_SelectedSSI;
+	BYTE b_ReadType;
+	PULONG pul_Position;
+	PULONG pul_TurnCpt;
+	PULONG pul_Position1;
+	PULONG pul_TurnCpt1;
+
+	i_ReturnValue = insn->n;
+	pul_Position1 = (PULONG) & data[0];
+// For Read1
+	pul_TurnCpt1 = (PULONG) & data[1];
+// For Read all
+	pul_Position = (PULONG) & data[0];	//0-2
+	pul_TurnCpt = (PULONG) & data[3];	//3-5
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_SelectedSSI = (BYTE) CR_CHAN(insn->chanspec);
+	b_ReadType = (BYTE) CR_RANGE(insn->chanspec);
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if SSI counter */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
+	      /***************************/
+			/* Test if SSI initialised */
+	      /***************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_SSICounterInfo.b_SSIInit == 1) {
+
+				switch (b_ReadType) {
+
+				case APCI1710_SSI_READ1VALUE:
+		 /****************************************/
+					/* Test the selected SSI counter number */
+		 /****************************************/
+
+					if (b_SelectedSSI < 3) {
+		    /************************/
+						/* Start the conversion */
+		    /************************/
+
+						outl(0, devpriv->s_BoardInfos.
+							ui_Address + 8 +
+							(64 * b_ModulNbr));
+
+						do {
+		       /*******************/
+							/* Read the status */
+		       /*******************/
+
+							dw_StatusReg =
+								inl(devpriv->
+								s_BoardInfos.
+								ui_Address +
+								(64 * b_ModulNbr));
+						}
+						while ((dw_StatusReg & 0x1) !=
+							0);
+
+		    /******************************/
+						/* Read the SSI counter value */
+		    /******************************/
+
+						dw_CounterValue =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 4 +
+							(b_SelectedSSI * 4) +
+							(64 * b_ModulNbr));
+
+						b_Length =
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_SSIProfile / 2;
+
+						if ((b_Length * 2) !=
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_SSIProfile) {
+							b_Length++;
+						}
+
+						b_Schift =
+							b_Length -
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_PositionTurnLength;
+
+						*pul_Position1 =
+							dw_CounterValue >>
+							b_Schift;
+
+						dw_And = 1;
+
+						for (b_Cpt = 0;
+							b_Cpt <
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_PositionTurnLength;
+							b_Cpt++) {
+							dw_And = dw_And * 2;
+						}
+
+						*pul_Position1 =
+							*pul_Position1 &
+							((dw_And) - 1);
+
+						*pul_TurnCpt1 =
+							dw_CounterValue >>
+							b_Length;
+
+						dw_And = 1;
+
+						for (b_Cpt = 0;
+							b_Cpt <
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_TurnCptLength;
+							b_Cpt++) {
+							dw_And = dw_And * 2;
+						}
+
+						*pul_TurnCpt1 =
+							*pul_TurnCpt1 &
+							((dw_And) - 1);
+					} else {
+		    /*****************************/
+						/* The selected SSI is wrong */
+		    /*****************************/
+
+						DPRINTK("The selected SSI is wrong\n");
+						i_ReturnValue = -5;
+					}
+					break;
+
+				case APCI1710_SSI_READALLVALUE:
+					dw_And1 = 1;
+
+					for (b_Cpt = 0;
+						b_Cpt <
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SSICounterInfo.
+						b_PositionTurnLength; b_Cpt++) {
+						dw_And1 = dw_And1 * 2;
+					}
+
+					dw_And2 = 1;
+
+					for (b_Cpt = 0;
+						b_Cpt <
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_SSICounterInfo.
+						b_TurnCptLength; b_Cpt++) {
+						dw_And2 = dw_And2 * 2;
+					}
+
+		 /************************/
+					/* Start the conversion */
+		 /************************/
+
+					outl(0, devpriv->s_BoardInfos.
+						ui_Address + 8 +
+						(64 * b_ModulNbr));
+
+					do {
+		    /*******************/
+						/* Read the status */
+		    /*******************/
+
+						dw_StatusReg =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address +
+							(64 * b_ModulNbr));
+					}
+					while ((dw_StatusReg & 0x1) != 0);
+
+					for (b_SSICpt = 0; b_SSICpt < 3;
+						b_SSICpt++) {
+		    /******************************/
+						/* Read the SSI counter value */
+		    /******************************/
+
+						dw_CounterValue =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 4 +
+							(b_SSICpt * 4) +
+							(64 * b_ModulNbr));
+
+						b_Length =
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_SSIProfile / 2;
+
+						if ((b_Length * 2) !=
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_SSIProfile) {
+							b_Length++;
+						}
+
+						b_Schift =
+							b_Length -
+							devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_SSICounterInfo.
+							b_PositionTurnLength;
+
+						pul_Position[b_SSICpt] =
+							dw_CounterValue >>
+							b_Schift;
+						pul_Position[b_SSICpt] =
+							pul_Position[b_SSICpt] &
+							((dw_And1) - 1);
+
+						pul_TurnCpt[b_SSICpt] =
+							dw_CounterValue >>
+							b_Length;
+						pul_TurnCpt[b_SSICpt] =
+							pul_TurnCpt[b_SSICpt] &
+							((dw_And2) - 1);
+					}
+					break;
+
+				default:
+					printk("Read Type Inputs Wrong\n");
+
+				}	// switch  ending
+
+			} else {
+		 /***********************/
+				/* SSI not initialised */
+		 /***********************/
+
+				DPRINTK("SSI not initialised\n");
+				i_ReturnValue = -4;
+			}
+		} else {
+	      /**********************************/
+			/* The module is not a SSI module */
+	      /**********************************/
+
+			DPRINTK("The module is not a SSI module\n");
+			i_ReturnValue = -3;
+
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_   i_APCI1710_ReadSSI1DigitalInput                |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_InputChannel,           |
+|                                        PBYTE_   pb_ChannelStatus)          |
++----------------------------------------------------------------------------+
+| Task              :
+					(0) Set the digital output from selected SSI moule         |
+|                     (b_ModuleNbr) ON
+                    (1) Set the digital output from selected SSI moule         |
+|                     (b_ModuleNbr) OFF
+					(2)Read the status from selected SSI digital input        |
+|                     (b_InputChannel)
+                    (3)Read the status from all SSI digital inputs from       |
+|                     selected SSI module (b_ModulNbr)                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr    CR_AREF        : Module number to         |
+|                                                   configure (0 to 3)       |
+|                     BYTE_ b_InputChannel CR_CHAN       : Selection from digital   |
+|                        data[0] which IOTYPE                           input ( 0 to 2)          |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_  pb_ChannelStatus    : Digital input channel    |
+|                                 data[0]                  status                   |
+|                                                   0 : Channle is not active|
+|                                                   1 : Channle is active    |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a SSI module                      |
+|                    -4: The selected SSI digital input is wrong             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg;
+	BYTE b_ModulNbr;
+	BYTE b_InputChannel;
+	PBYTE pb_ChannelStatus;
+	PBYTE pb_InputStatus;
+	BYTE b_IOType;
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_IOType = (BYTE) data[0];
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if SSI counter */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
+			switch (b_IOType) {
+			case APCI1710_SSI_SET_CHANNELON:
+					/*****************************/
+				/* Set the digital output ON */
+					/*****************************/
+
+				outl(1, devpriv->s_BoardInfos.ui_Address + 16 +
+					(64 * b_ModulNbr));
+				break;
+
+			case APCI1710_SSI_SET_CHANNELOFF:
+					/******************************/
+				/* Set the digital output OFF */
+					/******************************/
+
+				outl(0, devpriv->s_BoardInfos.ui_Address + 16 +
+					(64 * b_ModulNbr));
+				break;
+
+			case APCI1710_SSI_READ_1CHANNEL:
+				   /******************************************/
+				/* Test the digital imnput channel number */
+				   /******************************************/
+
+				b_InputChannel = (BYTE) CR_CHAN(insn->chanspec);
+				pb_ChannelStatus = (PBYTE) & data[0];
+
+				if (b_InputChannel <= 2) {
+					/**************************/
+					/* Read all digital input */
+					/**************************/
+
+					dw_StatusReg =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + (64 * b_ModulNbr));
+					*pb_ChannelStatus =
+						(BYTE) (((~dw_StatusReg) >> (4 +
+								b_InputChannel))
+						& 1);
+				} else {
+					/********************************/
+					/* Selected digital input error */
+					/********************************/
+
+					DPRINTK("Selected digital input error\n");
+					i_ReturnValue = -4;
+				}
+				break;
+
+			case APCI1710_SSI_READ_ALLCHANNEL:
+					/**************************/
+				/* Read all digital input */
+					/**************************/
+				pb_InputStatus = (PBYTE) & data[0];
+
+				dw_StatusReg =
+					inl(devpriv->s_BoardInfos.ui_Address +
+					(64 * b_ModulNbr));
+				*pb_InputStatus =
+					(BYTE) (((~dw_StatusReg) >> 4) & 7);
+				break;
+
+			default:
+				printk("IO type wrong\n");
+
+			}	//switch end
+		} else {
+	      /**********************************/
+			/* The module is not a SSI module */
+	      /**********************************/
+
+			DPRINTK("The module is not a SSI module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}

+ 43 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h

@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_30MHZ		30
+#define APCI1710_33MHZ		33
+#define APCI1710_40MHZ		40
+
+#define APCI1710_BINARY_MODE	0x1
+#define APCI1710_GRAY_MODE	0x0
+
+#define APCI1710_SSI_READ1VALUE		1
+#define APCI1710_SSI_READALLVALUE	2
+
+#define APCI1710_SSI_SET_CHANNELON	0
+#define APCI1710_SSI_SET_CHANNELOFF	1
+#define APCI1710_SSI_READ_1CHANNEL	2
+#define APCI1710_SSI_READ_ALLCHANNEL	3
+
+/*
+ * SSI INISIALISATION FUNCTION
+ */
+INT i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);

+ 2049 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c

@@ -0,0 +1,2049 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : TOR.C           | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 tor counter module                          |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 27/01/99 | S. Weber  | 40 MHz implementation                          |
+  +-----------------------------------------------------------------------+
+  | 28/04/00 | S. Weber  | Simple,double and quadruple mode implementation|
+  |          |           | Extern clock implementation                    |
+  +-----------------------------------------------------------------------+
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "APCI1710_Tor.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_     i_APCI1710_InitTorCounter                    |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_TorCounter,             |
+|                                        BYTE_     b_PCIInputClock,          |
+|                                        BYTE_     b_TimingUnit,             |
+|                                        ULONG_   ul_TimingInterval,         |
+|                                        PULONG_ pul_RealTimingInterval)     |
++----------------------------------------------------------------------------+
+| Task              : Configure the selected tor counter (b_TorCounter)      |
+|                     from selected module (b_ModulNbr).                     |
+|                     The ul_TimingInterval and ul_TimingUnit determine the  |
+|                     timing base for the measurement.                       |
+|                     The pul_RealTimingInterval return the real timing      |
+|                     value. You must calling this function be for you call  |
+|                     any other function witch access of the tor counter.    |
+|                                                                            |
++----------------------------------------------------------------------------+
+| Input Parameters  :    |
+|
+		CR_AREF	BYTE_   b_ModulNbr       : Module number to configure  |
+|                                                (0 to 3)                    |
+|           data[0] BYTE_   b_TorCounter     : Tor counter selection       |
+|                                                (0 or 1).                   |
+|           data[1] BYTE_   b_PCIInputClock  : Selection from PCI bus clock|
+|                                                - APCI1710_30MHZ :          |
+|                                                  The PC have a PCI bus     |
+|                                                  clock from 30 MHz         |
+|                                                - APCI1710_33MHZ :          |
+|                                                  The PC have a PCI bus     |
+|                                                  clock from 33 MHz         |
+|                                                - APCI1710_40MHZ            |
+|                                                  The APCI-1710 have a      |
+|                                                  integrated 40Mhz          |
+|                                                  quartz.                   |
+|                                                - APCI1710_GATE_INPUT       |
+|                                                  Used the gate input for   |
+|						   the base clock. If you    |
+|						   have selected this option,|
+|						   than it is not possibl to |
+|						   used the gate input for   |
+|						   enabled the acquisition   |
+|           data[2] BYTE_   b_TimingUnit    : Base timing unit (0 to 4)    |
+|                                                 0 : ns                     |
+|                                                 1 : µs                     |
+|                                                 2 : ms                     |
+|                                                 3 : s                      |
+|                                                 4 : mn                     |
+|           data[3]          ULONG_ ul_TimingInterval : Base timing value.          |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pul_RealTimingInterval : Real  base timing    |
+|                     data[0]                                  value.               |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a tor counter module             |
+|                     -4: Tor counter selection is wrong                     |
+|                     -5: The selected PCI input clock is wrong              |
+|                     -6: Timing unit selection is wrong                     |
+|                     -7: Base timing selection is wrong                     |
+|                     -8: You can not used the 40MHz clock selection wich    |
+|                         this board                                         |
+|                     -9: You can not used the 40MHz clock selection wich    |
+|                         this TOR version                                   |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	ULONG ul_TimerValue = 0;
+	DWORD dw_Command;
+	double d_RealTimingInterval = 0;
+	BYTE b_ModulNbr;
+	BYTE b_TorCounter;
+	BYTE b_PCIInputClock;
+	BYTE b_TimingUnit;
+	ULONG ul_TimingInterval;
+	ULONG ul_RealTimingInterval = 0;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+
+	b_TorCounter = (BYTE) data[0];
+	b_PCIInputClock = (BYTE) data[1];
+	b_TimingUnit = (BYTE) data[2];
+	ul_TimingInterval = (ULONG) data[3];
+	printk("INPUT clock %d\n", b_PCIInputClock);
+
+		/**************************/
+	/* Test the module number */
+		/**************************/
+
+	if (b_ModulNbr < 4) {
+		/***********************/
+		/* Test if tor counter */
+		/***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
+	      /**********************************/
+			/* Test the tor counter selection */
+	      /**********************************/
+
+			if (b_TorCounter <= 1) {
+		 /**************************/
+				/* Test the PCI bus clock */
+		 /**************************/
+
+				if ((b_PCIInputClock == APCI1710_30MHZ) ||
+					(b_PCIInputClock == APCI1710_33MHZ) ||
+					(b_PCIInputClock == APCI1710_40MHZ) ||
+					(b_PCIInputClock ==
+						APCI1710_GATE_INPUT)) {
+		    /************************/
+					/* Test the timing unit */
+		    /************************/
+
+					if ((b_TimingUnit <= 4)
+						|| (b_PCIInputClock ==
+							APCI1710_GATE_INPUT)) {
+		       /**********************************/
+						/* Test the base timing selection */
+		       /**********************************/
+
+						if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 133) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230650UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 9UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 121) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691043UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 520UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 8UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 100) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496729UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 7UL)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && (ul_TimingInterval >= 2))) {
+				/**************************/
+							/* Test the board version */
+				/**************************/
+
+							if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) {
+			     /************************/
+								/* Test the TOR version */
+			     /************************/
+
+								if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3132)) || (b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) {
+				/*********************************/
+									/* Test if not extern clock used */
+				/*********************************/
+
+									if (b_PCIInputClock != APCI1710_GATE_INPUT) {
+										fpu_begin
+											();
+				   /****************************************/
+										/* Calculate the timer 0 division fator */
+				   /****************************************/
+
+										switch (b_TimingUnit) {
+				      /******/
+											/* ns */
+				      /******/
+
+										case 0:
+
+					      /******************/
+											/* Timer 0 factor */
+					      /******************/
+
+											ul_TimerValue
+												=
+												(ULONG)
+												(ul_TimingInterval
+												*
+												(0.00025 * b_PCIInputClock));
+
+					      /*******************/
+											/* Round the value */
+					      /*******************/
+
+											if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+												ul_TimerValue
+													=
+													ul_TimerValue
+													+
+													1;
+											}
+
+					      /*****************************/
+											/* Calculate the real timing */
+					      /*****************************/
+
+											ul_RealTimingInterval
+												=
+												(ULONG)
+												(ul_TimerValue
+												/
+												(0.00025 * (double)b_PCIInputClock));
+											d_RealTimingInterval
+												=
+												(double)
+												ul_TimerValue
+												/
+												(0.00025
+												*
+												(double)
+												b_PCIInputClock);
+
+											if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+												ul_RealTimingInterval
+													=
+													ul_RealTimingInterval
+													+
+													1;
+											}
+
+											ul_TimingInterval
+												=
+												ul_TimingInterval
+												-
+												1;
+											ul_TimerValue
+												=
+												ul_TimerValue
+												-
+												2;
+
+											if (b_PCIInputClock != APCI1710_40MHZ) {
+												ul_TimerValue
+													=
+													(ULONG)
+													(
+													(double)
+													(ul_TimerValue)
+													*
+													1.007752288);
+											}
+
+											break;
+
+				      /******/
+											/* æs */
+				      /******/
+
+										case 1:
+
+					      /******************/
+											/* Timer 0 factor */
+					      /******************/
+
+											ul_TimerValue
+												=
+												(ULONG)
+												(ul_TimingInterval
+												*
+												(0.25 * b_PCIInputClock));
+
+					      /*******************/
+											/* Round the value */
+					      /*******************/
+
+											if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+												ul_TimerValue
+													=
+													ul_TimerValue
+													+
+													1;
+											}
+
+					      /*****************************/
+											/* Calculate the real timing */
+					      /*****************************/
+
+											ul_RealTimingInterval
+												=
+												(ULONG)
+												(ul_TimerValue
+												/
+												(0.25 * (double)b_PCIInputClock));
+											d_RealTimingInterval
+												=
+												(double)
+												ul_TimerValue
+												/
+												(
+												(double)
+												0.25
+												*
+												(double)
+												b_PCIInputClock);
+
+											if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+												ul_RealTimingInterval
+													=
+													ul_RealTimingInterval
+													+
+													1;
+											}
+
+											ul_TimingInterval
+												=
+												ul_TimingInterval
+												-
+												1;
+											ul_TimerValue
+												=
+												ul_TimerValue
+												-
+												2;
+
+											if (b_PCIInputClock != APCI1710_40MHZ) {
+												ul_TimerValue
+													=
+													(ULONG)
+													(
+													(double)
+													(ul_TimerValue)
+													*
+													1.007752288);
+											}
+
+											break;
+
+				      /******/
+											/* ms */
+				      /******/
+
+										case 2:
+
+					      /******************/
+											/* Timer 0 factor */
+					      /******************/
+
+											ul_TimerValue
+												=
+												ul_TimingInterval
+												*
+												(250.0
+												*
+												b_PCIInputClock);
+
+					      /*******************/
+											/* Round the value */
+					      /*******************/
+
+											if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+												ul_TimerValue
+													=
+													ul_TimerValue
+													+
+													1;
+											}
+
+					      /*****************************/
+											/* Calculate the real timing */
+					      /*****************************/
+
+											ul_RealTimingInterval
+												=
+												(ULONG)
+												(ul_TimerValue
+												/
+												(250.0 * (double)b_PCIInputClock));
+											d_RealTimingInterval
+												=
+												(double)
+												ul_TimerValue
+												/
+												(250.0
+												*
+												(double)
+												b_PCIInputClock);
+
+											if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+												ul_RealTimingInterval
+													=
+													ul_RealTimingInterval
+													+
+													1;
+											}
+
+											ul_TimingInterval
+												=
+												ul_TimingInterval
+												-
+												1;
+											ul_TimerValue
+												=
+												ul_TimerValue
+												-
+												2;
+
+											if (b_PCIInputClock != APCI1710_40MHZ) {
+												ul_TimerValue
+													=
+													(ULONG)
+													(
+													(double)
+													(ul_TimerValue)
+													*
+													1.007752288);
+											}
+
+											break;
+
+				      /*****/
+											/* s */
+				      /*****/
+
+										case 3:
+
+					      /******************/
+											/* Timer 0 factor */
+					      /******************/
+
+											ul_TimerValue
+												=
+												(ULONG)
+												(ul_TimingInterval
+												*
+												(250000.0
+													*
+													b_PCIInputClock));
+
+					      /*******************/
+											/* Round the value */
+					      /*******************/
+
+											if ((double)((double)ul_TimingInterval * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+												ul_TimerValue
+													=
+													ul_TimerValue
+													+
+													1;
+											}
+
+					      /*****************************/
+											/* Calculate the real timing */
+					      /*****************************/
+
+											ul_RealTimingInterval
+												=
+												(ULONG)
+												(ul_TimerValue
+												/
+												(250000.0
+													*
+													(double)
+													b_PCIInputClock));
+											d_RealTimingInterval
+												=
+												(double)
+												ul_TimerValue
+												/
+												(250000.0
+												*
+												(double)
+												b_PCIInputClock);
+
+											if ((double)((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+												ul_RealTimingInterval
+													=
+													ul_RealTimingInterval
+													+
+													1;
+											}
+
+											ul_TimingInterval
+												=
+												ul_TimingInterval
+												-
+												1;
+											ul_TimerValue
+												=
+												ul_TimerValue
+												-
+												2;
+
+											if (b_PCIInputClock != APCI1710_40MHZ) {
+												ul_TimerValue
+													=
+													(ULONG)
+													(
+													(double)
+													(ul_TimerValue)
+													*
+													1.007752288);
+											}
+
+											break;
+
+				      /******/
+											/* mn */
+				      /******/
+
+										case 4:
+
+					      /******************/
+											/* Timer 0 factor */
+					      /******************/
+
+											ul_TimerValue
+												=
+												(ULONG)
+												(
+												(ul_TimingInterval
+													*
+													60)
+												*
+												(250000.0
+													*
+													b_PCIInputClock));
+
+					      /*******************/
+											/* Round the value */
+					      /*******************/
+
+											if ((double)((double)(ul_TimingInterval * 60.0) * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
+												ul_TimerValue
+													=
+													ul_TimerValue
+													+
+													1;
+											}
+
+					      /*****************************/
+											/* Calculate the real timing */
+					      /*****************************/
+
+											ul_RealTimingInterval
+												=
+												(ULONG)
+												(ul_TimerValue
+												/
+												(250000.0
+													*
+													(double)
+													b_PCIInputClock))
+												/
+												60;
+											d_RealTimingInterval
+												=
+												(
+												(double)
+												ul_TimerValue
+												/
+												(250000.0
+													*
+													(double)
+													b_PCIInputClock))
+												/
+												60.0;
+
+											if ((double)(((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) {
+												ul_RealTimingInterval
+													=
+													ul_RealTimingInterval
+													+
+													1;
+											}
+
+											ul_TimingInterval
+												=
+												ul_TimingInterval
+												-
+												1;
+											ul_TimerValue
+												=
+												ul_TimerValue
+												-
+												2;
+
+											if (b_PCIInputClock != APCI1710_40MHZ) {
+												ul_TimerValue
+													=
+													(ULONG)
+													(
+													(double)
+													(ul_TimerValue)
+													*
+													1.007752288);
+											}
+
+											break;
+										}
+
+										fpu_end();
+									}	// if (b_PCIInputClock != APCI1710_GATE_INPUT)
+									else {
+				   /*************************************************************/
+										/* 2 Clock used for the overflow and the reload from counter */
+				   /*************************************************************/
+
+										ul_TimerValue
+											=
+											ul_TimingInterval
+											-
+											2;
+									}	// if (b_PCIInputClock != APCI1710_GATE_INPUT)
+
+				/****************************/
+									/* Save the PCI input clock */
+				/****************************/
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TorCounterModuleInfo.
+										b_PCIInputClock
+										=
+										b_PCIInputClock;
+
+				/************************/
+									/* Save the timing unit */
+				/************************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TorCounterModuleInfo.
+										s_TorCounterInfo
+										[b_TorCounter].
+										b_TimingUnit
+										=
+										b_TimingUnit;
+
+				/************************/
+									/* Save the base timing */
+				/************************/
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TorCounterModuleInfo.
+										s_TorCounterInfo
+										[b_TorCounter].
+										d_TimingInterval
+										=
+										d_RealTimingInterval;
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TorCounterModuleInfo.
+										s_TorCounterInfo
+										[b_TorCounter].
+										ul_RealTimingInterval
+										=
+										ul_RealTimingInterval;
+
+				/*******************/
+									/* Get the command */
+				/*******************/
+
+									dw_Command
+										=
+										inl
+										(devpriv->
+										s_BoardInfos.
+										ui_Address
+										+
+										4
+										+
+										(16 * b_TorCounter) + (64 * b_ModulNbr));
+
+									dw_Command
+										=
+										(dw_Command
+										>>
+										4)
+										&
+										0xF;
+
+				/******************/
+									/* Test if 40 MHz */
+				/******************/
+
+									if (b_PCIInputClock == APCI1710_40MHZ) {
+				   /****************************/
+										/* Set the 40 MHz selection */
+				   /****************************/
+
+										dw_Command
+											=
+											dw_Command
+											|
+											0x10;
+									}
+
+				/*****************************/
+									/* Test if extern clock used */
+				/*****************************/
+
+									if (b_PCIInputClock == APCI1710_GATE_INPUT) {
+				   /****************************/
+										/* Set the 40 MHz selection */
+				   /****************************/
+
+										dw_Command
+											=
+											dw_Command
+											|
+											0x20;
+									}
+
+				/*************************/
+									/* Write the new command */
+				/*************************/
+
+									outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr));
+
+				/*******************/
+									/* Disable the tor */
+				/*******************/
+
+									outl(0, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr));
+				/*************************/
+									/* Set the timer 1 value */
+				/*************************/
+
+									outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (16 * b_TorCounter) + (64 * b_ModulNbr));
+
+				/*********************/
+									/* Tor counter init. */
+				/*********************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TorCounterModuleInfo.
+										s_TorCounterInfo
+										[b_TorCounter].
+										b_TorCounterInit
+										=
+										1;
+								} else {
+				/***********************************************/
+									/* TOR version error for 40MHz clock selection */
+				/***********************************************/
+
+									DPRINTK("TOR version error for 40MHz clock selection\n");
+									i_ReturnValue
+										=
+										-9;
+								}
+							} else {
+			     /**************************************************************/
+								/* You can not used the 40MHz clock selection wich this board */
+			     /**************************************************************/
+
+								DPRINTK("You can not used the 40MHz clock selection wich this board\n");
+								i_ReturnValue =
+									-8;
+							}
+						} else {
+			  /**********************************/
+							/* Base timing selection is wrong */
+			  /**********************************/
+
+							DPRINTK("Base timing selection is wrong\n");
+							i_ReturnValue = -7;
+						}
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+					else {
+		       /**********************************/
+						/* Timing unit selection is wrong */
+		       /**********************************/
+
+						DPRINTK("Timing unit selection is wrong\n");
+						i_ReturnValue = -6;
+					}	// if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4))
+				}	// if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ))
+				else {
+		    /*****************************************/
+					/* The selected PCI input clock is wrong */
+		    /*****************************************/
+
+					DPRINTK("The selected PCI input clock is wrong\n");
+					i_ReturnValue = -5;
+				}	// if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ))
+			}	// if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7)
+			else {
+		 /**********************************/
+				/* Tor Counter selection is wrong */
+		 /**********************************/
+
+				DPRINTK("Tor Counter selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7)
+		} else {
+	      /******************************************/
+			/* The module is not a tor counter module */
+	      /******************************************/
+
+			DPRINTK("The module is not a tor counter module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+	data[0] = (UINT) ul_RealTimingInterval;
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_EnableTorCounter                      |
+|                                               (BYTE_ b_BoardHandle,        |
+|                                                BYTE_ b_ModulNbr,           |
+|						 BYTE_ b_TorCounter,         |
+|						 BYTE_ b_InputMode,          |
+|						 BYTE_ b_ExternGate,         |
+|                                                BYTE_ b_CycleMode,          |
+|                                                BYTE_ b_InterruptEnable)    |
++----------------------------------------------------------------------------+
+| Task              : Enable the tor counter (b_TorCounter) from selected    |
+|		      module (b_ModulNbr). You must calling the              |
+|                     "i_APCI1710_InitTorCounter" function be for you call   |
+|		      this function.                                         |
+|                     If you enable the tor counter interrupt, the           |
+|                     tor counter generate a interrupt after the timing cycle|
+|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
+|                     Interrupt mask description chapter from this manual.   |
+|                     The b_CycleMode parameter determine if you will        |
+|                     measured a single or more cycle.                       |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr     : Selected module number (0 to 3) |
+|                     BYTE_ b_TorCounter   : Tor counter selection (0 or 1). |
+|		      BYTE_ b_InputMode    : Input signal level selection    |
+|						0 : Tor count each low level |
+|						1 : Tor count each high level|
+|		      BYTE_ b_ExternGate   : Extern gate action selection    |
+|						0 : Extern gate signal not   |
+|						    used                     |
+|						1 : Extern gate signal used. |
+|						    If you selected the      |
+|						    single mode, each high   |
+|						    level signal start the   |
+|						    counter.                 |
+|						    If you selected the      |
+|						    continuous mode, the     |
+|						    first high level signal  |
+|						    start the tor counter    |
+|									     |
+|					      APCI1710_TOR_QUADRUPLE _MODE : |
+|					      In the quadruple mode, the edge|
+|					      analysis circuit generates a   |
+|					      counting pulse from each edge  |
+|					      of 2 signals which are phase   |
+|					      shifted in relation to each    |
+|					      other.                         |
+|					      The gate input is used for the |
+|					      signal B                       |
+|									     |
+|					      APCI1710_TOR_DOUBLE_MODE:      |
+|					      Functions in the same way as   |
+|					      the quadruple mode, except that|
+|					      only two of the four edges are |
+|					      analysed per period.           |
+|					      The gate input is used for the |
+|					      signal B                       |
+|									     |
+|					      APCI1710_TOR_SIMPLE_MODE:      |
+|					      Functions in the same way as   |
+|					      the quadruple mode, except that|
+|					      only one of the four edges is  |
+|					      analysed per period.           |
+|					      The gate input is used for the |
+|					      signal B                       |
+|									     |
+|                     BYTE_ b_CycleMode    : Selected the tor counter        |
+|                                            acquisition mode                |
+|                     BYTE_ b_InterruptEnable : Enable or disable the        |
+|                                               tor counter interrupt.       |
+|                                               APCI1710_ENABLE:             |
+|                                               Enable the tor counter       |
+|                                               interrupt                    |
+|                                               APCI1710_DISABLE:            |
+|                                               Disable the tor counter      |
+|                                               interrupt                    |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a tor counter module             |
+|                     -4: Tor counter selection is wrong                     |
+|                     -5: Tor counter not initialised see function           |
+|                         "i_APCI1710_InitTorCounter"                        |
+|                     -6: Tor input signal selection is wrong                |
+|                     -7: Extern gate signal mode is wrong                   |
+|                     -8: Tor counter acquisition mode cycle is wrong        |
+|                     -9: Interrupt parameter is wrong                       |
+|                     -10:Interrupt function not initialised.                |
+|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
++----------------------------------------------------------------------------+
+*/
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_DisableTorCounter                     |
+|                                               (BYTE_  b_BoardHandle,       |
+|                                                BYTE_  b_ModulNbr,          |
+|						 BYTE_  b_TorCounter)        |
++----------------------------------------------------------------------------+
+| Task              : Disable the tor counter (b_TorCounter) from selected   |
+|		      module (b_ModulNbr). If you disable the tor counter    |
+|		      after a start cycle occur and you restart the tor      |
+|		      counter witch the " i_APCI1710_EnableTorCounter"       |
+|		      function, the status register is cleared               |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr     : Selected module number (0 to 3) |
+|                     BYTE_ b_TorCounter   : Tor counter selection (0 or 1). |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a tor counter module             |
+|                     -4: Tor counter selection is wrong                     |
+|                     -5: Tor counter not initialised see function           |
+|                         "i_APCI1710_InitTorCounter"                        |
+|                     -6: Tor counter not enabled see function               |
+|                         "i_APCI1710_EnableTorCounter"                      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+	DWORD dw_DummyRead;
+	DWORD dw_ConfigReg;
+	BYTE b_ModulNbr, b_Action;
+	BYTE b_TorCounter;
+	BYTE b_InputMode;
+	BYTE b_ExternGate;
+	BYTE b_CycleMode;
+	BYTE b_InterruptEnable;
+
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_Action = (BYTE) data[0];	// enable or disable
+	b_TorCounter = (BYTE) data[1];
+	b_InputMode = (BYTE) data[2];
+	b_ExternGate = (BYTE) data[3];
+	b_CycleMode = (BYTE) data[4];
+	b_InterruptEnable = (BYTE) data[5];
+	i_ReturnValue = insn->n;;
+	devpriv->tsk_Current = current;	// Save the current process task structure
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if tor counter */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
+	      /**********************************/
+			/* Test the tor counter selection */
+	      /**********************************/
+
+			if (b_TorCounter <= 1) {
+				switch (b_Action)	// Enable or Disable
+				{
+				case APCI1710_ENABLE:
+		 /***********************************/
+					/* Test if tor counter initialised */
+		 /***********************************/
+
+					dw_Status =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 8 +
+						(16 * b_TorCounter) +
+						(64 * b_ModulNbr));
+
+					if (dw_Status & 0x10) {
+		    /******************************/
+						/* Test the input signal mode */
+		    /******************************/
+
+						if (b_InputMode == 0 ||
+							b_InputMode == 1 ||
+							b_InputMode ==
+							APCI1710_TOR_SIMPLE_MODE
+							|| b_InputMode ==
+							APCI1710_TOR_DOUBLE_MODE
+							|| b_InputMode ==
+							APCI1710_TOR_QUADRUPLE_MODE)
+						{
+		       /************************************/
+							/* Test the extern gate signal mode */
+		       /************************************/
+
+							if (b_ExternGate == 0
+								|| b_ExternGate
+								== 1
+								|| b_InputMode >
+								1) {
+			  /*********************************/
+								/* Test the cycle mode parameter */
+			  /*********************************/
+
+								if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) {
+			     /***************************/
+									/* Test the interrupt flag */
+			     /***************************/
+
+									if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) {
+
+				   /***************************/
+										/* Save the interrupt mode */
+				   /***************************/
+
+										devpriv->
+											s_ModuleInfo
+											[b_ModulNbr].
+											s_TorCounterModuleInfo.
+											s_TorCounterInfo
+											[b_TorCounter].
+											b_InterruptEnable
+											=
+											b_InterruptEnable;
+
+				   /*******************/
+										/* Get the command */
+				   /*******************/
+
+										dw_ConfigReg
+											=
+											inl
+											(devpriv->
+											s_BoardInfos.
+											ui_Address
+											+
+											4
+											+
+											(16 * b_TorCounter) + (64 * b_ModulNbr));
+
+										dw_ConfigReg
+											=
+											(dw_ConfigReg
+											>>
+											4)
+											&
+											0x30;
+
+				   /********************************/
+										/* Test if not direct mode used */
+				   /********************************/
+
+										if (b_InputMode > 1) {
+				      /*******************************/
+											/* Extern gate can not be used */
+				      /*******************************/
+
+											b_ExternGate
+												=
+												0;
+
+				      /*******************************************/
+											/* Enable the extern gate for the Signal B */
+				      /*******************************************/
+
+											dw_ConfigReg
+												=
+												dw_ConfigReg
+												|
+												0x40;
+
+				      /***********************/
+											/* Test if simple mode */
+				      /***********************/
+
+											if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) {
+					 /**************************/
+												/* Enable the sinple mode */
+					 /**************************/
+
+												dw_ConfigReg
+													=
+													dw_ConfigReg
+													|
+													0x780;
+
+											}	// if (b_InputMode == APCI1710_TOR_SIMPLE_MODE)
+
+				      /***********************/
+											/* Test if double mode */
+				      /***********************/
+
+											if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) {
+					 /**************************/
+												/* Enable the double mode */
+					 /**************************/
+
+												dw_ConfigReg
+													=
+													dw_ConfigReg
+													|
+													0x180;
+
+											}	// if (b_InputMode == APCI1710_TOR_DOUBLE_MODE)
+
+											b_InputMode
+												=
+												0;
+										}	// if (b_InputMode > 1)
+
+				   /*******************/
+										/* Set the command */
+				   /*******************/
+
+										dw_ConfigReg
+											=
+											dw_ConfigReg
+											|
+											b_CycleMode
+											|
+											(b_InterruptEnable
+											*
+											2)
+											|
+											(b_InputMode
+											*
+											4)
+											|
+											(b_ExternGate
+											*
+											8);
+
+				   /*****************************/
+										/* Clear the status register */
+				   /*****************************/
+
+										dw_DummyRead
+											=
+											inl
+											(devpriv->
+											s_BoardInfos.
+											ui_Address
+											+
+											0
+											+
+											(16 * b_TorCounter) + (64 * b_ModulNbr));
+
+				   /***************************************/
+										/* Clear the interrupt status register */
+				   /***************************************/
+
+										dw_DummyRead
+											=
+											inl
+											(devpriv->
+											s_BoardInfos.
+											ui_Address
+											+
+											12
+											+
+											(16 * b_TorCounter) + (64 * b_ModulNbr));
+
+				   /********************/
+										/* Set the commando */
+				   /********************/
+
+										outl(dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr));
+
+				   /****************/
+										/* Set the gate */
+				   /****************/
+
+										outl(1, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr));
+
+									}	// if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE))
+									else {
+				/********************************/
+										/* Interrupt parameter is wrong */
+				/********************************/
+
+										DPRINTK("Interrupt parameter is wrong\n");
+										i_ReturnValue
+											=
+											-9;
+									}	// if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE))
+								}	// if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS))
+								else {
+			     /***********************************************/
+									/* Tor counter acquisition mode cycle is wrong */
+			     /***********************************************/
+
+									DPRINTK("Tor counter acquisition mode cycle is wrong\n");
+									i_ReturnValue
+										=
+										-8;
+								}	// if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS))
+							}	// if (b_ExternGate >= 0 && b_ExternGate <= 1)
+							else {
+			  /***********************************/
+								/* Extern gate input mode is wrong */
+			  /***********************************/
+
+								DPRINTK("Extern gate input mode is wrong\n");
+								i_ReturnValue =
+									-7;
+							}	// if (b_ExternGate >= 0 && b_ExternGate <= 1)
+						}	// if (b_InputMode >= 0 && b_InputMode <= 1)
+						else {
+		       /***************************************/
+							/* Tor input signal selection is wrong */
+		       /***************************************/
+
+							DPRINTK("Tor input signal selection is wrong\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+		    /*******************************/
+						/* Tor counter not initialised */
+		    /*******************************/
+
+						DPRINTK("Tor counter not initialised\n");
+						i_ReturnValue = -5;
+					}
+					break;
+
+				case APCI1710_DISABLE:
+			 /***********************************/
+					/* Test if tor counter initialised */
+		 /***********************************/
+
+					dw_Status = inl(devpriv->s_BoardInfos.
+						ui_Address + 8 +
+						(16 * b_TorCounter) +
+						(64 * b_ModulNbr));
+
+		 /*******************************/
+					/* Test if counter initialised */
+		 /*******************************/
+
+					if (dw_Status & 0x10) {
+		    /***************************/
+						/* Test if counter enabled */
+		    /***************************/
+
+						if (dw_Status & 0x1) {
+		       /****************************/
+							/* Clear the interrupt mode */
+		       /****************************/
+							devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_TorCounterModuleInfo.
+								s_TorCounterInfo
+								[b_TorCounter].
+								b_InterruptEnable
+								=
+								APCI1710_DISABLE;
+
+		       /******************/
+							/* Clear the gate */
+		       /******************/
+
+							outl(0, devpriv->
+								s_BoardInfos.
+								ui_Address + 8 +
+								(16 * b_TorCounter) + (64 * b_ModulNbr));
+						}	// if (dw_Status & 0x1)
+						else {
+		       /***************************/
+							/* Tor counter not enabled */
+		       /***************************/
+
+							DPRINTK("Tor counter not enabled \n");
+							i_ReturnValue = -6;
+						}	// if (dw_Status & 0x1)
+					}	// if (dw_Status & 0x10)
+					else {
+		    /*******************************/
+						/* Tor counter not initialised */
+		    /*******************************/
+
+						DPRINTK("Tor counter not initialised\n");
+						i_ReturnValue = -5;
+					}	// // if (dw_Status & 0x10)
+
+				}	// switch
+			}	// if (b_TorCounter <= 1)
+			else {
+		 /**********************************/
+				/* Tor counter selection is wrong */
+		 /**********************************/
+
+				DPRINTK("Tor counter selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_TorCounter <= 1)
+		} else {
+	      /******************************************/
+			/* The module is not a tor counter module */
+	      /******************************************/
+
+			DPRINTK("The module is not a tor counter module \n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error \n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_GetTorCounterInitialisation           |
+|                                               (BYTE_     b_BoardHandle,    |
+|                                                BYTE_     b_ModulNbr,       |
+|						 BYTE_     b_TorCounter,     |
+|                                        	 PBYTE_   pb_TimingUnit,     |
+|                                        	 PULONG_ pul_TimingInterval, |
+|						 PBYTE_   pb_InputMode,      |
+|						 PBYTE_   pb_ExternGate,     |
+|                                                PBYTE_   pb_CycleMode,      |
+|						 PBYTE_   pb_Enable,         |
+|                                                PBYTE_   pb_InterruptEnable)|
++----------------------------------------------------------------------------+
+| Task              : Enable the tor counter (b_TorCounter) from selected    |
+|		      module (b_ModulNbr). You must calling the              |
+|                     "i_APCI1710_InitTorCounter" function be for you call   |
+|		      this function.                                         |
+|                     If you enable the tor counter interrupt, the           |
+|                     tor counter generate a interrupt after the timing cycle|
+|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
+|                     Interrupt mask description chapter from this manual.   |
+|                     The b_CycleMode parameter determine if you will        |
+|                     measured a single or more cycle.                       |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr     : Selected module number (0 to 3) |
+|                     BYTE_ b_TorCounter   : Tor counter selection (0 or 1)
+
+	b_ModulNbr			=	CR_AREF(insn->chanspec);
+	b_TorCounter		=	CR_CHAN(insn->chanspec);
+. |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_  pb_TimingUnit    : Base timing unit (0 to 4)   |
+|                                                 0 : ns                     |
+|                                                 1 : µs                     |
+|                                                 2 : ms                     |
+|                                                 3 : s                      |
+|                                                 4 : mn                     |
+|                     PULONG_ pul_TimingInterval : Base timing value.        |
+|		      PBYTE_ pb_InputMode        : Input signal level        |
+|						   selection  		     |
+|						0 : Tor count each low level |
+|						1 : Tor count each high level|
+|		      PBYTE_ pb_ExternGate	: Extern gate action         |
+|						  selection                  |
+|						  0 : Extern gate signal not |
+|						      used                   |
+|						  1 : Extern gate signal used|
+|                     PBYTE_ pb_CycleMode       : Tor counter acquisition    |
+|						  mode           	     |
+|		      PBYTE_ pb_Enable		: Indicate if the tor counter|
+|						  is enabled or no           |
+|						  0 : Tor counter disabled   |
+|						  1 : Tor counter enabled    |
+|                     PBYTE_ pb_InterruptEnable : Enable or disable the      |
+|                                                 tor counter interrupt.     |
+|                                                 APCI1710_ENABLE:           |
+|                                                 Enable the tor counter     |
+|                                                 interrupt                  |
+|                                                 APCI1710_DISABLE:          |
+|                                                 Disable the tor counter    |
+|                                                 interrupt
+	pb_TimingUnit		=	(PBYTE) &data[0];
+	pul_TimingInterval	=  (PULONG) &data[1];
+	pb_InputMode		=	(PBYTE) &data[2];
+	pb_ExternGate		=	(PBYTE) &data[3];
+	pb_CycleMode		=	(PBYTE) &data[4];
+	pb_Enable			=	(PBYTE) &data[5];
+	pb_InterruptEnable	=	(PBYTE) &data[6];
+                 |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a tor counter module             |
+|                     -4: Tor counter selection is wrong                     |
+|                     -5: Tor counter not initialised see function           |
+|                         "i_APCI1710_InitTorCounter"                        |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+	BYTE b_ModulNbr;
+	BYTE b_TorCounter;
+	PBYTE pb_TimingUnit;
+	PULONG pul_TimingInterval;
+	PBYTE pb_InputMode;
+	PBYTE pb_ExternGate;
+	PBYTE pb_CycleMode;
+	PBYTE pb_Enable;
+	PBYTE pb_InterruptEnable;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_TorCounter = CR_CHAN(insn->chanspec);
+
+	pb_TimingUnit = (PBYTE) & data[0];
+	pul_TimingInterval = (PULONG) & data[1];
+	pb_InputMode = (PBYTE) & data[2];
+	pb_ExternGate = (PBYTE) & data[3];
+	pb_CycleMode = (PBYTE) & data[4];
+	pb_Enable = (PBYTE) & data[5];
+	pb_InterruptEnable = (PBYTE) & data[6];
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if tor counter */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
+	      /**********************************/
+			/* Test the tor counter selection */
+	      /**********************************/
+
+			if (b_TorCounter <= 1) {
+
+		 /***********************************/
+				/* Test if tor counter initialised */
+		 /***********************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 8 + (16 * b_TorCounter) +
+					(64 * b_ModulNbr));
+
+				if (dw_Status & 0x10) {
+					*pb_Enable = dw_Status & 1;
+
+		    /********************/
+					/* Get the commando */
+		    /********************/
+
+					dw_Status = inl(devpriv->s_BoardInfos.
+						ui_Address + 4 +
+						(16 * b_TorCounter) +
+						(64 * b_ModulNbr));
+
+					*pb_CycleMode =
+						(BYTE) ((dw_Status >> 4) & 1);
+					*pb_InterruptEnable =
+						(BYTE) ((dw_Status >> 5) & 1);
+
+		    /******************************************************/
+					/* Test if extern gate used for clock or for signal B */
+		    /******************************************************/
+
+					if (dw_Status & 0x600) {
+		       /*****************************************/
+						/* Test if extern gate used for signal B */
+		       /*****************************************/
+
+						if (dw_Status & 0x400) {
+			  /***********************/
+							/* Test if simple mode */
+			  /***********************/
+
+							if ((dw_Status & 0x7800)
+								== 0x7800) {
+								*pb_InputMode =
+									APCI1710_TOR_SIMPLE_MODE;
+							}
+
+			  /***********************/
+							/* Test if double mode */
+			  /***********************/
+
+							if ((dw_Status & 0x7800)
+								== 0x1800) {
+								*pb_InputMode =
+									APCI1710_TOR_DOUBLE_MODE;
+							}
+
+			  /**************************/
+							/* Test if quadruple mode */
+			  /**************************/
+
+							if ((dw_Status & 0x7800)
+								== 0x0000) {
+								*pb_InputMode =
+									APCI1710_TOR_QUADRUPLE_MODE;
+							}
+						}	// if (dw_Status & 0x400)
+						else {
+							*pb_InputMode = 1;
+						}	// // if (dw_Status & 0x400)
+
+		       /************************/
+						/* Extern gate not used */
+		       /************************/
+
+						*pb_ExternGate = 0;
+					}	// if (dw_Status & 0x600)
+					else {
+						*pb_InputMode =
+							(BYTE) ((dw_Status >> 6)
+							& 1);
+						*pb_ExternGate =
+							(BYTE) ((dw_Status >> 7)
+							& 1);
+					}	// if (dw_Status & 0x600)
+
+					*pb_TimingUnit =
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_TorCounterModuleInfo.
+						s_TorCounterInfo[b_TorCounter].
+						b_TimingUnit;
+
+					*pul_TimingInterval =
+						devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_TorCounterModuleInfo.
+						s_TorCounterInfo[b_TorCounter].
+						ul_RealTimingInterval;
+				} else {
+		    /*******************************/
+					/* Tor counter not initialised */
+		    /*******************************/
+
+					DPRINTK("Tor counter not initialised\n");
+					i_ReturnValue = -5;
+				}
+
+			}	// if (b_TorCounter <= 1)
+			else {
+		 /**********************************/
+				/* Tor counter selection is wrong */
+		 /**********************************/
+
+				DPRINTK("Tor counter selection is wrong \n");
+				i_ReturnValue = -4;
+			}	// if (b_TorCounter <= 1)
+		} else {
+	      /******************************************/
+			/* The module is not a tor counter module */
+	      /******************************************/
+
+			DPRINTK("The module is not a tor counter module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_ReadTorCounterValue                   |
+|                               (BYTE_     b_BoardHandle,                    |
+|                                BYTE_     b_ModulNbr,                       |
+|				 BYTE_     b_TorCounter,                     |
+|                                UINT_    ui_TimeOut,                        |
+|                                PBYTE_   pb_TorCounterStatus,               |
+|                                PULONG_ pul_TorCounterValue)                |
++----------------------------------------------------------------------------+
+| Task        	case APCI1710_TOR_GETPROGRESSSTATUS: Return the tor counter
+(b_TorCounter) status (pb_TorCounterStatus) from selected tor counter        |
+|		      module (b_ModulNbr).
+
+				 case APCI1710_TOR_GETCOUNTERVALUE :
+  Return the tor counter (b_TorCounter) status           |
+|		      (pb_TorCounterStatus) and the timing value             |
+|		      (pul_TorCounterValue) after a conting cycle stop       |
+|                     from selected tor counter module (b_ModulNbr).         |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle  : Handle of board APCI-1710       |
+|                     BYTE_ b_ModulNbr     : Selected module number (0 to 3) |
+|                     BYTE_ b_TorCounter   : Tor counter selection (0 or 1).
+	b_ModulNbr    = CR_AREF(insn->chanspec);
+	b_ReadType    = (BYTE) data[0];
+	b_TorCounter  =	(BYTE) data[1];
+	ui_TimeOut	  = (UINT) data[2]; |
++----------------------------------------------------------------------------+
+| Output Parameters : PBYTE_  pb_TorCounterStatus : Return the tor counter   |
+|                                                    status.                 |
+|                                               0 : Conting cycle not started|
+|                                                   Software gate not set.   |
+|                                               1 : Conting cycle started.   |
+|                                                   Software gate set.       |
+|                                               2 : Conting cycle stopped.   |
+|                                                   The conting cycle is     |
+|                                                   terminate.               |
+|                                               3 : A overflow occur. You    |
+|                                                   must change the base     |
+|                                                   timing witch the         |
+|                                                   function                 |
+|                                                 "i_APCI1710_InitTorCounter"|
+|						4 : Timeeout occur           |
+|                     PULONG  pul_TorCounterValue  : Tor counter value.
+	pb_TorCounterStatus=(PBYTE) &data[0];
+	pul_TorCounterValue=(PULONG) &data[1];    |
++----------------------------------------------------------------------------+
+| Return Value      :  0: No error                                           |
+|                     -1: The handle parameter of the board is wrong         |
+|                     -2: Module selection wrong                             |
+|                     -3: The module is not a tor counter module             |
+|                     -4: Tor counter selection is wrong                     |
+|                     -5: Tor counter not initialised see function           |
+|                         "i_APCI1710_InitTorCounter"                        |
+|                     -6: Tor counter not enabled see function               |
+|                         "i_APCI1710_EnableTorCounter"                      |
+|                     -7: Timeout parameter is wrong (0 to 65535)            |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_Status;
+	DWORD dw_TimeOut = 0;
+
+	BYTE b_ModulNbr;
+	BYTE b_TorCounter;
+	BYTE b_ReadType;
+	UINT ui_TimeOut;
+	PBYTE pb_TorCounterStatus;
+	PULONG pul_TorCounterValue;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_ReadType = (BYTE) data[0];
+	b_TorCounter = (BYTE) data[1];
+	ui_TimeOut = (UINT) data[2];
+	pb_TorCounterStatus = (PBYTE) & data[0];
+	pul_TorCounterValue = (PULONG) & data[1];
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ReadType == APCI1710_TOR_READINTERRUPT) {
+
+		data[0] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].b_OldModuleMask;
+		data[1] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].ul_OldInterruptMask;
+		data[2] = devpriv->s_InterruptParameters.
+			s_FIFOInterruptParameters[devpriv->
+			s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
+
+			   /**************************/
+		/* Increment the read FIFO */
+			   /***************************/
+
+		devpriv->
+			s_InterruptParameters.
+			ui_Read = (devpriv->
+			s_InterruptParameters.
+			ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
+
+		return insn->n;
+	}
+
+	if (b_ModulNbr < 4) {
+	   /***********************/
+		/* Test if tor counter */
+	   /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
+	      /**********************************/
+			/* Test the tor counter selection */
+	      /**********************************/
+
+			if (b_TorCounter <= 1) {
+		 /***********************************/
+				/* Test if tor counter initialised */
+		 /***********************************/
+
+				dw_Status = inl(devpriv->s_BoardInfos.
+					ui_Address + 8 + (16 * b_TorCounter) +
+					(64 * b_ModulNbr));
+
+		 /*******************************/
+				/* Test if counter initialised */
+		 /*******************************/
+
+				if (dw_Status & 0x10) {
+		    /***************************/
+					/* Test if counter enabled */
+		    /***************************/
+
+					if (dw_Status & 0x1) {
+
+						switch (b_ReadType) {
+
+						case APCI1710_TOR_GETPROGRESSSTATUS:
+		       /*******************/
+							/* Read the status */
+		       /*******************/
+
+							dw_Status =
+								inl(devpriv->
+								s_BoardInfos.
+								ui_Address + 4 +
+								(16 * b_TorCounter) + (64 * b_ModulNbr));
+
+							dw_Status =
+								dw_Status & 0xF;
+
+		       /*****************/
+							/* Test if start */
+		       /*****************/
+
+							if (dw_Status & 1) {
+								if (dw_Status &
+									2) {
+									if (dw_Status & 4) {
+				/************************/
+										/* Tor counter owerflow */
+				/************************/
+
+										*pb_TorCounterStatus
+											=
+											3;
+									} else {
+				/***********************/
+										/* Tor counter started */
+				/***********************/
+
+										*pb_TorCounterStatus
+											=
+											2;
+									}
+								} else {
+			     /***********************/
+									/* Tor counter started */
+			     /***********************/
+
+									*pb_TorCounterStatus
+										=
+										1;
+								}
+							} else {
+			  /***************************/
+								/* Tor counter not started */
+			  /***************************/
+
+								*pb_TorCounterStatus
+									= 0;
+							}
+							break;
+
+						case APCI1710_TOR_GETCOUNTERVALUE:
+
+		       /*****************************/
+							/* Test the timout parameter */
+		       /*****************************/
+
+							if ((ui_TimeOut >= 0)
+								&& (ui_TimeOut
+									<=
+									65535UL))
+							{
+								for (;;) {
+			     /*******************/
+									/* Read the status */
+			     /*******************/
+
+									dw_Status
+										=
+										inl
+										(devpriv->
+										s_BoardInfos.
+										ui_Address
+										+
+										4
+										+
+										(16 * b_TorCounter) + (64 * b_ModulNbr));
+			     /********************/
+									/* Test if overflow */
+			     /********************/
+
+									if ((dw_Status & 4) == 4) {
+				/******************/
+										/* Overflow occur */
+				/******************/
+
+										*pb_TorCounterStatus
+											=
+											3;
+
+				/******************/
+										/* Read the value */
+				/******************/
+
+										*pul_TorCounterValue
+											=
+											inl
+											(devpriv->
+											s_BoardInfos.
+											ui_Address
+											+
+											0
+											+
+											(16 * b_TorCounter) + (64 * b_ModulNbr));
+										break;
+									}	// if ((dw_Status & 4) == 4)
+									else {
+				/*******************************/
+										/* Test if measurement stopped */
+				/*******************************/
+
+										if ((dw_Status & 2) == 2) {
+				   /***********************/
+											/* A stop signal occur */
+				   /***********************/
+
+											*pb_TorCounterStatus
+												=
+												2;
+
+				   /******************/
+											/* Read the value */
+				   /******************/
+
+											*pul_TorCounterValue
+												=
+												inl
+												(devpriv->
+												s_BoardInfos.
+												ui_Address
+												+
+												0
+												+
+												(16 * b_TorCounter) + (64 * b_ModulNbr));
+
+											break;
+										}	// if ((dw_Status & 2) == 2)
+										else {
+				   /*******************************/
+											/* Test if measurement started */
+				   /*******************************/
+
+											if ((dw_Status & 1) == 1) {
+				      /************************/
+												/* A start signal occur */
+				      /************************/
+
+												*pb_TorCounterStatus
+													=
+													1;
+											}	// if ((dw_Status & 1) == 1)
+											else {
+				      /***************************/
+												/* Measurement not started */
+				      /***************************/
+
+												*pb_TorCounterStatus
+													=
+													0;
+											}	// if ((dw_Status & 1) == 1)
+										}	// if ((dw_Status & 2) == 2)
+									}	// if ((dw_Status & 8) == 8)
+
+									if (dw_TimeOut == ui_TimeOut) {
+				/*****************/
+										/* Timeout occur */
+				/*****************/
+
+										break;
+									} else {
+				/*************************/
+										/* Increment the timeout */
+				/*************************/
+
+										dw_TimeOut
+											=
+											dw_TimeOut
+											+
+											1;
+
+										mdelay(1000);
+									}
+								}	// for (;;)
+
+			  /*************************/
+								/* Test if timeout occur */
+			  /*************************/
+
+								if ((*pb_TorCounterStatus != 3) && (dw_TimeOut == ui_TimeOut) && (ui_TimeOut != 0)) {
+			     /*****************/
+									/* Timeout occur */
+			     /*****************/
+
+									*pb_TorCounterStatus
+										=
+										4;
+								}
+							} else {
+			  /******************************/
+								/* Timeout parameter is wrong */
+			  /******************************/
+
+								DPRINTK("Timeout parameter is wrong\n");
+								i_ReturnValue =
+									-7;
+							}
+							break;
+
+						default:
+							printk("Inputs wrong\n");
+						}	// switch end
+					}	// if (dw_Status & 0x1)
+					else {
+		       /***************************/
+						/* Tor counter not enabled */
+		       /***************************/
+
+						DPRINTK("Tor counter not enabled\n");
+						i_ReturnValue = -6;
+					}	// if (dw_Status & 0x1)
+				} else {
+		    /*******************************/
+					/* Tor counter not initialised */
+		    /*******************************/
+
+					DPRINTK("Tor counter not initialised\n");
+					i_ReturnValue = -5;
+				}
+			}	// if (b_TorCounter <= 1)
+			else {
+		 /**********************************/
+				/* Tor counter selection is wrong */
+		 /**********************************/
+
+				DPRINTK("Tor counter selection is wrong\n");
+				i_ReturnValue = -4;
+			}	// if (b_TorCounter <= 1)
+		} else {
+	      /******************************************/
+			/* The module is not a tor counter module */
+	      /******************************************/
+
+			DPRINTK("The module is not a tor counter module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}

+ 57 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_30MHZ		30
+#define APCI1710_33MHZ		33
+#define APCI1710_40MHZ		40
+
+#define APCI1710_GATE_INPUT	10
+
+#define APCI1710_TOR_SIMPLE_MODE	2
+#define APCI1710_TOR_DOUBLE_MODE	3
+#define APCI1710_TOR_QUADRUPLE_MODE	4
+
+#define APCI1710_SINGLE			0
+#define APCI1710_CONTINUOUS		1
+
+#define APCI1710_TOR_GETPROGRESSSTATUS	0
+#define APCI1710_TOR_GETCOUNTERVALUE	1
+#define APCI1710_TOR_READINTERRUPT	2
+
+/*
+ * TOR_COUNTER INISIALISATION FUNCTION
+ */
+INT i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev,
+					struct comedi_subdevice *s,
+					struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev,
+						struct comedi_subdevice *s,
+						struct comedi_insn *insn,
+						unsigned int *data);
+
+INT i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev,
+						   struct comedi_subdevice *s,
+						   struct comedi_insn *insn,
+						   unsigned int *data);
+/*
+ * TOR_COUNTER READ FUNCTION
+ */
+INT i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev,
+							   struct comedi_subdevice *s,
+							   struct comedi_insn *insn,
+							   unsigned int *data);

+ 1038 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c

@@ -0,0 +1,1038 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1710    | Compiler : gcc                        |
+  | Module name : TTL.C           | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-1710 TTL I/O module                              |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 13/05/98 | S. Weber  | TTL digital input / output implementation      |
+  |----------|-----------|------------------------------------------------|
+  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
+  |          |           |   available                                    |
+  +-----------------------------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "APCI1710_Ttl.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_InitTTLIODirection                    |
+|                               (BYTE_    b_BoardHandle,                     |
+|				 BYTE_    b_ModulNbr,                        |
+|				 BYTE_    b_PortAMode,                       |
+|				 BYTE_    b_PortBMode,                       |
+|				 BYTE_    b_PortCMode,                       |
+|				 BYTE_    b_PortDMode)                       |
++----------------------------------------------------------------------------+
+| Task           APCI1710_TTL_INIT (using defaults)   : Configure the TTL I/O operating mode from selected     |
+|                     module  (b_ModulNbr). You must calling this function be|
+|                     for you call any other function witch access of TTL.   |
+				 APCI1710_TTL_INITDIRECTION(user inputs for direction)
+
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 3)
+		b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+		b_InitType = (BYTE) data[0];
+		b_PortAMode	= (BYTE) data[1];
+		b_PortBMode = (BYTE) data[2];
+		b_PortCMode = (BYTE) data[3];
+		b_PortDMode	= (BYTE) data[4];|
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a TTL module                      |
+|		     -4: Function not available for this version             |
+|		     -5: Port A mode selection is wrong                      |
+|		     -6: Port B mode selection is wrong                      |
+|		     -7: Port C mode selection is wrong                      |
+|		     -8: Port D mode selection is wrong                      |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	BYTE b_ModulNbr;
+	BYTE b_InitType;
+	BYTE b_PortAMode;
+	BYTE b_PortBMode;
+	BYTE b_PortCMode;
+	BYTE b_PortDMode;
+
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	b_InitType = (BYTE) data[0];
+	i_ReturnValue = insn->n;
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /**************************/
+		/* Test if TTL I/O module */
+	   /**************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TTL_IO) {
+			switch (b_InitType) {
+			case APCI1710_TTL_INIT:
+
+				devpriv->s_ModuleInfo[b_ModulNbr].
+					s_TTLIOInfo.b_TTLInit = 1;
+
+	      /***************************/
+				/* Set TTL port A to input */
+	      /***************************/
+
+				devpriv->s_ModuleInfo[b_ModulNbr].
+					s_TTLIOInfo.b_PortConfiguration[0] = 0;
+
+	      /***************************/
+				/* Set TTL port B to input */
+	      /***************************/
+
+				devpriv->s_ModuleInfo[b_ModulNbr].
+					s_TTLIOInfo.b_PortConfiguration[1] = 0;
+
+	      /***************************/
+				/* Set TTL port C to input */
+	      /***************************/
+
+				devpriv->s_ModuleInfo[b_ModulNbr].
+					s_TTLIOInfo.b_PortConfiguration[2] = 0;
+
+	      /****************************/
+				/* Set TTL port D to output */
+	      /****************************/
+
+				devpriv->s_ModuleInfo[b_ModulNbr].
+					s_TTLIOInfo.b_PortConfiguration[3] = 1;
+
+	      /*************************/
+				/* Set the configuration */
+	      /*************************/
+
+				outl(0x8,
+					devpriv->s_BoardInfos.ui_Address + 20 +
+					(64 * b_ModulNbr));
+				break;
+
+			case APCI1710_TTL_INITDIRECTION:
+
+				b_PortAMode = (BYTE) data[1];
+				b_PortBMode = (BYTE) data[2];
+				b_PortCMode = (BYTE) data[3];
+				b_PortDMode = (BYTE) data[4];
+
+	      /********************/
+				/* Test the version */
+	      /********************/
+
+				if ((devpriv->s_BoardInfos.
+						dw_MolduleConfiguration
+						[b_ModulNbr] & 0xFFFF) >=
+					0x3230) {
+		 /************************/
+					/* Test the port A mode */
+		 /************************/
+
+					if ((b_PortAMode == 0)
+						|| (b_PortAMode == 1)) {
+		    /************************/
+						/* Test the port B mode */
+		    /************************/
+
+						if ((b_PortBMode == 0)
+							|| (b_PortBMode == 1)) {
+		       /************************/
+							/* Test the port C mode */
+		       /************************/
+
+							if ((b_PortCMode == 0)
+								|| (b_PortCMode
+									== 1)) {
+			  /************************/
+								/* Test the port D mode */
+			  /************************/
+
+								if ((b_PortDMode == 0) || (b_PortDMode == 1)) {
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TTLIOInfo.
+										b_TTLInit
+										=
+										1;
+
+			     /***********************/
+									/* Set TTL port A mode */
+			     /***********************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TTLIOInfo.
+										b_PortConfiguration
+										[0]
+										=
+										b_PortAMode;
+
+			     /***********************/
+									/* Set TTL port B mode */
+			     /***********************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TTLIOInfo.
+										b_PortConfiguration
+										[1]
+										=
+										b_PortBMode;
+
+			     /***********************/
+									/* Set TTL port C mode */
+			     /***********************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TTLIOInfo.
+										b_PortConfiguration
+										[2]
+										=
+										b_PortCMode;
+
+			     /***********************/
+									/* Set TTL port D mode */
+			     /***********************/
+
+									devpriv->
+										s_ModuleInfo
+										[b_ModulNbr].
+										s_TTLIOInfo.
+										b_PortConfiguration
+										[3]
+										=
+										b_PortDMode;
+
+			     /*************************/
+									/* Set the configuration */
+			     /*************************/
+
+									outl((b_PortAMode << 0) | (b_PortBMode << 1) | (b_PortCMode << 2) | (b_PortDMode << 3), devpriv->s_BoardInfos.ui_Address + 20 + (64 * b_ModulNbr));
+								} else {
+			     /**********************************/
+									/* Port D mode selection is wrong */
+			     /**********************************/
+
+									DPRINTK("Port D mode selection is wrong\n");
+									i_ReturnValue
+										=
+										-8;
+								}
+							} else {
+			  /**********************************/
+								/* Port C mode selection is wrong */
+			  /**********************************/
+
+								DPRINTK("Port C mode selection is wrong\n");
+								i_ReturnValue =
+									-7;
+							}
+						} else {
+		       /**********************************/
+							/* Port B mode selection is wrong */
+		       /**********************************/
+
+							DPRINTK("Port B mode selection is wrong\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+		    /**********************************/
+						/* Port A mode selection is wrong */
+		    /**********************************/
+
+						DPRINTK("Port A mode selection is wrong\n");
+						i_ReturnValue = -5;
+					}
+				} else {
+		 /*******************************************/
+					/* Function not available for this version */
+		 /*******************************************/
+
+					DPRINTK("Function not available for this version\n");
+					i_ReturnValue = -4;
+				}
+				break;
+
+				DPRINTK("\n");
+			default:
+				printk("Bad Config Type\n");
+			}	// switch end
+		} else {
+	      /**********************************/
+			/* The module is not a TTL module */
+	      /**********************************/
+
+			DPRINTK("The module is not a TTL module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            INPUT FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_   i_APCI1710_ReadTTLIOChannelValue               |
+|                                       (BYTE_     b_BoardHandle,            |
+|                                        BYTE_     b_ModulNbr,               |
+|                                        BYTE_     b_SelectedPort,           |
+|                                        BYTE_     b_InputChannel,           |
+|                                        PBYTE_   pb_ChannelStatus)          |
++----------------------------------------------------------------------------+
+| Task              : Read the status from selected TTL digital input        |
+|                     (b_InputChannel)
++----------------------------------------------------------------------------+
+| Task              : Read the status from digital input port                |
+|                     (b_SelectedPort) from selected TTL module (b_ModulNbr) |
++----------------------------------------------------------------------------+
+
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 7)       |
+|                     BYTE_ b_SelectedPort,       : Selection from TTL I/O   |
+|                                                   port (0 to 2)            |
+|                                                      0 : Port A selection  |
+|                                                      1 : Port B selection  |
+|                                                      2 : Port C selection  |
+|                                                      3 : Port D selection  |
+|                     BYTE_ b_InputChannel        : Selection from digital   |
+|                                                   input ( 0 to 2)
+APCI1710_TTL_READCHANNEL
+	b_ModulNbr	  = CR_AREF(insn->chanspec);
+	b_SelectedPort= CR_RANGE(insn->chanspec);
+	b_InputChannel= CR_CHAN(insn->chanspec);
+	b_ReadType	  = (BYTE) data[0];
+
+ APCI1710_TTL_READPORT|
+	b_ModulNbr	  = CR_AREF(insn->chanspec);
+	b_SelectedPort= CR_RANGE(insn->chanspec);
+	b_ReadType	  = (BYTE) data[0];
+
++----------------------------------------------------------------------------+
+| Output Parameters : data[0]
+
+	PBYTE_  pb_ChannelStatus    : Digital input channel    |
+|                                                   status                   |
+|                                                   0 : Channle is not active|
+|                                                   1 : Channle is active    |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a TTL module                      |
+|                    -4: The selected TTL input port is wrong                |
+|                    -5: The selected TTL digital input is wrong             |
+|                    -6: TTL I/O not initialised                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg;
+	BYTE b_ModulNbr;
+	BYTE b_SelectedPort;
+	BYTE b_InputChannel;
+	BYTE b_ReadType;
+	PBYTE pb_ChannelStatus;
+	PBYTE pb_PortValue;
+
+	i_ReturnValue = insn->n;
+	b_ReadType = (BYTE) data[0];
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_SelectedPort = CR_RANGE(insn->chanspec);
+	b_InputChannel = CR_CHAN(insn->chanspec);
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /**************************/
+		/* Test if TTL I/O module */
+	   /**************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TTL_IO) {
+			switch (b_ReadType) {
+
+			case APCI1710_TTL_READCHANNEL:
+				pb_ChannelStatus = (PBYTE) & data[0];
+	      /********************************/
+				/* Test the TTL I/O port number */
+	      /********************************/
+
+				if (((b_SelectedPort <= 2)
+						&& ((devpriv->s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) ==
+							0x3130))
+					|| ((b_SelectedPort <= 3)
+						&& ((devpriv->s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) >=
+							0x3230))) {
+		 /******************************************/
+					/* Test the digital imnput channel number */
+		 /******************************************/
+
+					if (((b_InputChannel <= 7)
+							&& (b_SelectedPort < 3))
+						|| ((b_InputChannel <= 1)
+							&& (b_SelectedPort ==
+								3))) {
+		    /******************************************/
+						/* Test if the TTL I/O module initialised */
+		    /******************************************/
+
+						if (devpriv->
+							s_ModuleInfo
+							[b_ModulNbr].
+							s_TTLIOInfo.b_TTLInit ==
+							1) {
+		       /***********************************/
+							/* Test if TTL port used for input */
+		       /***********************************/
+
+							if (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) == 0x3130) || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) {
+			  /**************************/
+								/* Read all digital input */
+			  /**************************/
+
+								dw_StatusReg =
+									inl
+									(devpriv->
+									s_BoardInfos.
+									ui_Address
+									+
+									(64 * b_ModulNbr));
+
+								*pb_ChannelStatus
+									=
+									(BYTE) (
+									(dw_StatusReg
+										>>
+										(8 * b_SelectedPort)) >> b_InputChannel) & 1;
+							} else {
+			  /*******************************/
+								/* Selected TTL I/O port error */
+			  /*******************************/
+
+								DPRINTK("Selected TTL I/O port error\n");
+								i_ReturnValue =
+									-4;
+							}
+						} else {
+		       /***************************/
+							/* TTL I/O not initialised */
+		       /***************************/
+
+							DPRINTK("TTL I/O not initialised\n");
+							i_ReturnValue = -6;
+						}
+					} else {
+		    /********************************/
+						/* Selected digital input error */
+		    /********************************/
+
+						DPRINTK("Selected digital input error\n");
+						i_ReturnValue = -5;
+					}
+				} else {
+		 /*******************************/
+					/* Selected TTL I/O port error */
+		 /*******************************/
+
+					DPRINTK("Selected TTL I/O port error\n");
+					i_ReturnValue = -4;
+				}
+				break;
+
+			case APCI1710_TTL_READPORT:
+				pb_PortValue = (PBYTE) & data[0];
+			  /********************************/
+				/* Test the TTL I/O port number */
+			  /********************************/
+
+				if (((b_SelectedPort <= 2)
+						&& ((devpriv->s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) ==
+							0x3130))
+					|| ((b_SelectedPort <= 3)
+						&& ((devpriv->s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) >=
+							0x3230))) {
+		 /******************************************/
+					/* Test if the TTL I/O module initialised */
+		 /******************************************/
+
+					if (devpriv->s_ModuleInfo[b_ModulNbr].
+						s_TTLIOInfo.b_TTLInit == 1) {
+		    /***********************************/
+						/* Test if TTL port used for input */
+		    /***********************************/
+
+						if (((devpriv->s_BoardInfos.
+									dw_MolduleConfiguration
+									[b_ModulNbr]
+									&
+									0xFFFF)
+								== 0x3130)
+							|| (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) {
+		       /**************************/
+							/* Read all digital input */
+		       /**************************/
+
+							dw_StatusReg =
+								inl(devpriv->
+								s_BoardInfos.
+								ui_Address +
+								(64 * b_ModulNbr));
+
+							*pb_PortValue =
+								(BYTE) (
+								(dw_StatusReg >>
+									(8 * b_SelectedPort)) & 0xFF);
+						} else {
+		       /*******************************/
+							/* Selected TTL I/O port error */
+		       /*******************************/
+
+							DPRINTK("Selected TTL I/O port error\n");
+							i_ReturnValue = -4;
+						}
+					} else {
+		    /***************************/
+						/* TTL I/O not initialised */
+		    /***************************/
+
+						DPRINTK("TTL I/O not initialised\n");
+						i_ReturnValue = -5;
+					}
+				} else {
+		 /*******************************/
+					/* Selected TTL I/O port error */
+		 /*******************************/
+
+					DPRINTK("Selected TTL I/O port error\n");
+					i_ReturnValue = -4;
+				}
+				break;
+
+			default:
+				printk("Bad ReadType\n");
+
+			}	//End Switch
+		} else {
+	      /**********************************/
+			/* The module is not a TTL module */
+	      /**********************************/
+
+			DPRINTK("The module is not a TTL module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device
+*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)              |
++----------------------------------------------------------------------------+
+| Task              : Read the status from all digital input ports           |
+|                     (port A, port B and port C) from selected TTL          |
+|		      module (b_ModulNbr) 				     |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle         : Handle of board APCI-1710|
+|                     BYTE_ b_ModulNbr            : Module number to         |
+|                                                   configure (0 to 3)       |
++----------------------------------------------------------------------------+
+| Output Parameters : PULONG_  pul_PortValue      : Digital TTL inputs port  |
+|                                                   status                   |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a TTL module                      |
+|                    -4: TTL I/O not initialised                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg;
+	BYTE b_ModulNbr;
+	PULONG pul_PortValue;
+
+	b_ModulNbr = (BYTE) CR_AREF(insn->chanspec);
+	i_ReturnValue = insn->n;
+	pul_PortValue = (PULONG) & data[0];
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /**************************/
+		/* Test if TTL I/O module */
+	   /**************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TTL_IO) {
+	      /******************************************/
+			/* Test if the TTL I/O module initialised */
+	      /******************************************/
+
+			if (devpriv->
+				s_ModuleInfo[b_ModulNbr].
+				s_TTLIOInfo.b_TTLInit == 1) {
+		 /**************************/
+				/* Read all digital input */
+		 /**************************/
+
+				dw_StatusReg = inl(devpriv->s_BoardInfos.
+					ui_Address + (64 * b_ModulNbr));
+
+		 /**********************/
+				/* Test if TTL Rev1.0 */
+		 /**********************/
+
+				if ((devpriv->s_BoardInfos.
+						dw_MolduleConfiguration
+						[b_ModulNbr] & 0xFFFF) ==
+					0x3130) {
+					*pul_PortValue =
+						dw_StatusReg & 0xFFFFFFUL;
+				} else {
+		    /**************************************/
+					/* Test if port A not used for output */
+		    /**************************************/
+
+					if (devpriv->s_ModuleInfo[b_ModulNbr].
+						s_TTLIOInfo.
+						b_PortConfiguration[0] == 1) {
+						*pul_PortValue =
+							dw_StatusReg &
+							0x3FFFF00UL;
+					}
+
+		    /**************************************/
+					/* Test if port B not used for output */
+		    /**************************************/
+
+					if (devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_TTLIOInfo.
+						b_PortConfiguration[1] == 1) {
+						*pul_PortValue =
+							dw_StatusReg &
+							0x3FF00FFUL;
+					}
+
+		    /**************************************/
+					/* Test if port C not used for output */
+		    /**************************************/
+
+					if (devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_TTLIOInfo.
+						b_PortConfiguration[2] == 1) {
+						*pul_PortValue =
+							dw_StatusReg &
+							0x300FFFFUL;
+					}
+
+		    /**************************************/
+					/* Test if port D not used for output */
+		    /**************************************/
+
+					if (devpriv->
+						s_ModuleInfo[b_ModulNbr].
+						s_TTLIOInfo.
+						b_PortConfiguration[3] == 1) {
+						*pul_PortValue =
+							dw_StatusReg &
+							0xFFFFFFUL;
+					}
+				}
+			} else {
+		 /***************************/
+				/* TTL I/O not initialised */
+		 /***************************/
+				DPRINTK("TTL I/O not initialised\n");
+				i_ReturnValue = -5;
+			}
+		} else {
+	      /**********************************/
+			/* The module is not a TTL module */
+	      /**********************************/
+			DPRINTK("The module is not a TTL module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            OUTPUT FUNCTIONS                                |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : _INT_ i_APCI1710_SetTTLIOChlOn                         |
+|                               (BYTE_           b_BoardHandle,              |
+|                                BYTE_           b_ModulNbr,                 |
+|                                BYTE_           b_OutputChannel)
+INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s,
+	struct comedi_insn *insn,unsigned int *data)           |
++----------------------------------------------------------------------------+
+| Task              : Sets or resets  the output witch has been passed with the         |
+|                     parameter b_Channel. Setting an output means setting   |
+|                     an ouput high.                                         |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE_ b_BoardHandle   : Handle of board APCI-1710      |
+|                     BYTE_ b_ModulNbr      : Selected module number (0 to 3)|
+|                     BYTE_ b_OutputChannel : Selection from digital output  |
+|                                             channel (0 or 1)               |
+|                                                0      : PD0                |
+|                                                1      : PD1                |
+|						 2 to 9 : PA                 |
+|						10 to 17: PB                 |
+|						18 to 25: PC                 |
+
+  b_ModulNbr	   = CR_AREF(insn->chanspec);
+	b_OutputChannel= CR_CHAN(insn->chanspec);
+	ui_State	   = data[0]; // ON or OFF
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -1: The handle parameter of the board is wrong          |
+|                    -2: The module parameter is wrong                       |
+|                    -3: The module is not a TTL I/O module                  |
+|                    -4: The selected digital output is wrong                |
+|                    -5: TTL I/O not initialised see function                |
+|                        " i_APCI1710_InitTTLIO"
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = 0;
+	DWORD dw_StatusReg = 0;
+	BYTE b_ModulNbr;
+	BYTE b_OutputChannel;
+	UINT ui_State;
+
+	i_ReturnValue = insn->n;
+	b_ModulNbr = CR_AREF(insn->chanspec);
+	b_OutputChannel = CR_CHAN(insn->chanspec);
+	ui_State = data[0];	// ON or OFF
+
+	/**************************/
+	/* Test the module number */
+	/**************************/
+
+	if (b_ModulNbr < 4) {
+	   /**************************/
+		/* Test if TTL I/O module */
+	   /**************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModulNbr] &
+				0xFFFF0000UL) == APCI1710_TTL_IO) {
+	      /******************************************/
+			/* Test if the TTL I/O module initialised */
+	      /******************************************/
+
+			if (devpriv->s_ModuleInfo[b_ModulNbr].
+				s_TTLIOInfo.b_TTLInit == 1) {
+		 /***********************************/
+				/* Test the TTL I/O channel number */
+		 /***********************************/
+
+				if (((b_OutputChannel <= 1)
+						&& ((devpriv->s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) ==
+							0x3130))
+					|| ((b_OutputChannel <= 25)
+						&& ((devpriv->s_BoardInfos.
+								dw_MolduleConfiguration
+								[b_ModulNbr] &
+								0xFFFF) >=
+							0x3230))) {
+		    /****************************************************/
+					/* Test if the selected channel is a output channel */
+		    /****************************************************/
+
+					if (((b_OutputChannel <= 1)
+							&& (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_TTLIOInfo.
+								b_PortConfiguration
+								[3] == 1))
+						|| ((b_OutputChannel >= 2)
+							&& (b_OutputChannel <=
+								9)
+							&& (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_TTLIOInfo.
+								b_PortConfiguration
+								[0] == 1))
+						|| ((b_OutputChannel >= 10)
+							&& (b_OutputChannel <=
+								17)
+							&& (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_TTLIOInfo.
+								b_PortConfiguration
+								[1] == 1))
+						|| ((b_OutputChannel >= 18)
+							&& (b_OutputChannel <=
+								25)
+							&& (devpriv->
+								s_ModuleInfo
+								[b_ModulNbr].
+								s_TTLIOInfo.
+								b_PortConfiguration
+								[2] == 1))) {
+		       /************************/
+						/* Test if PD0 selected */
+		       /************************/
+
+						if (b_OutputChannel == 0) {
+
+							outl(ui_State,
+								devpriv->
+								s_BoardInfos.
+								ui_Address +
+								(64 * b_ModulNbr));
+						} else {
+			  /************************/
+							/* Test if PD1 selected */
+			  /************************/
+
+							if (b_OutputChannel ==
+								1) {
+
+								outl(ui_State,
+									devpriv->
+									s_BoardInfos.
+									ui_Address
+									+ 4 +
+									(64 * b_ModulNbr));
+							} else {
+								b_OutputChannel
+									=
+									b_OutputChannel
+									- 2;
+
+			     /********************/
+								/* Read all channel */
+			     /********************/
+
+								dw_StatusReg =
+									inl
+									(devpriv->
+									s_BoardInfos.
+									ui_Address
+									+
+									(64 * b_ModulNbr));
+								if (ui_State)	// ON
+								{
+									dw_StatusReg
+										=
+										(dw_StatusReg
+										>>
+										((b_OutputChannel / 8) * 8)) & 0xFF;
+									dw_StatusReg
+										=
+										dw_StatusReg
+										|
+										(1
+										<<
+										(b_OutputChannel
+											%
+											8));
+								} else	// Off
+								{
+									dw_StatusReg
+										=
+										(dw_StatusReg
+										>>
+										((b_OutputChannel / 8) * 8)) & 0xFF;
+									dw_StatusReg
+										=
+										dw_StatusReg
+										&
+										(0xFF
+										-
+										(1 << (b_OutputChannel % 8)));
+
+								}
+
+			     /****************************/
+								/* Set the new output value */
+			     /****************************/
+
+								outl(dw_StatusReg, devpriv->s_BoardInfos.ui_Address + 8 + ((b_OutputChannel / 8) * 4) + (64 * b_ModulNbr));
+							}
+						}
+					} else {
+		       /************************************/
+						/* The selected TTL output is wrong */
+		       /************************************/
+
+						DPRINTK(" The selected TTL output is wrong\n");
+						i_ReturnValue = -4;
+					}
+				} else {
+		    /************************************/
+					/* The selected TTL output is wrong */
+		    /************************************/
+
+					DPRINTK("The selected TTL output is wrong\n");
+					i_ReturnValue = -4;
+				}
+			} else {
+		 /***************************/
+				/* TTL I/O not initialised */
+		 /***************************/
+
+				DPRINTK("TTL I/O not initialised\n");
+				i_ReturnValue = -5;
+			}
+		} else {
+	      /**************************************/
+			/* The module is not a TTL I/O module */
+	      /**************************************/
+
+			DPRINTK("The module is not a TTL I/O module\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /***********************/
+		/* Module number error */
+	   /***********************/
+
+		DPRINTK("Module number error\n");
+		i_ReturnValue = -2;
+	}
+
+	return (i_ReturnValue);
+}

+ 44 - 0
drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h

@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define APCI1710_TTL_INIT		0
+#define APCI1710_TTL_INITDIRECTION	1
+
+#define APCI1710_TTL_READCHANNEL	0
+#define APCI1710_TTL_READPORT		1
+
+/*
+ * TTL INISIALISATION FUNCTION
+ */
+INT i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+
+/*
+ * TTL INPUT FUNCTION
+ */
+INT i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+
+/*
+ * TTL OUTPUT FUNCTIONS
+ */
+INT i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);

+ 203 - 0
drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c

@@ -0,0 +1,203 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project : ADDI HEADER READ WRITER |     Compiler   : Visual C++       |
+  | Module name : S5920.cpp           |     Version    : 6.0              |
+  +-------------------------------+---------------------------------------+
+  | Author : E. LIBS                      Date : 02/05/2002               |
+  +-----------------------------------------------------------------------+
+  | Description   : DLL with the S5920 PCI Controller functions           |
+  +-----------------------------------------------------------------------+
+  |                             UPDATE'S                                  |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 28/08/02 | LIBS Eric | Add return codes each time a function of the   |
+  |          |           | Addi Library is called                         |
+  +-----------------------------------------------------------------------+
+  | 31/07/03 | KRAUTH J. | Changes for the MSX-Box                        |
+  +-----------------------------------------------------------------------+
+*/
+
+#include "addi_amcc_S5920.h"
+
+/*+----------------------------------------------------------------------------+*/
+/*| Function   Name   : INT i_AddiHeaderRW_ReadEeprom                          |*/
+/*|                               (INT    i_NbOfWordsToRead,                   |*/
+/*|                                DWORD dw_PCIBoardEepromAddress,             |*/
+/*|                                WORD   w_EepromStartAddress,                |*/
+/*|                                PWORD pw_DataRead)                          |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Task              : Read word from the 5920 eeprom.                        |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Input Parameters  : INT    i_NbOfWordsToRead : Nbr. of word to read        |*/
+/*|                     DWORD dw_PCIBoardEepromAddress : Address of the eeprom |*/
+/*|                     WORD   w_EepromStartAddress : Eeprom strat address     |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Output Parameters : PWORD pw_DataRead : Read data                          |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Return Value      : -                                                      |*/
+/*+----------------------------------------------------------------------------+*/
+
+INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead,
+	DWORD dw_PCIBoardEepromAddress,
+	WORD w_EepromStartAddress, PWORD pw_DataRead)
+{
+	DWORD dw_eeprom_busy = 0;
+	INT i_Counter = 0;
+	INT i_WordCounter;
+	INT i;
+	BYTE pb_ReadByte[1];
+	BYTE b_ReadLowByte = 0;
+	BYTE b_ReadHighByte = 0;
+	BYTE b_SelectedAddressLow = 0;
+	BYTE b_SelectedAddressHigh = 0;
+	WORD w_ReadWord = 0;
+
+	for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead;
+		i_WordCounter++) {
+		do {
+			dw_eeprom_busy =
+				inl(dw_PCIBoardEepromAddress +
+				AMCC_OP_REG_MCSR);
+			dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+		}
+		while (dw_eeprom_busy == EEPROM_BUSY);
+
+		for (i_Counter = 0; i_Counter < 2; i_Counter++) {
+			b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256;	//Read the low 8 bit part
+			b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256;	//Read the high 8 bit part
+
+			//Select the load low address mode
+			outb(NVCMD_LOAD_LOW,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				3);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Load the low address
+			outb(b_SelectedAddressLow,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				2);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Select the load high address mode
+			outb(NVCMD_LOAD_HIGH,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				3);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Load the high address
+			outb(b_SelectedAddressHigh,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				2);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Select the READ mode
+			outb(NVCMD_BEGIN_READ,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				3);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Read data into the EEPROM
+			*pb_ReadByte =
+				inb(dw_PCIBoardEepromAddress +
+				AMCC_OP_REG_MCSR + 2);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Select the upper address part
+			if (i_Counter == 0) {
+				b_ReadLowByte = pb_ReadByte[0];
+			} else {
+				b_ReadHighByte = pb_ReadByte[0];
+			}
+
+			//Sleep
+			for (i = 0; i < 10000; i++) ;
+
+		}
+		w_ReadWord =
+			(b_ReadLowByte | (((unsigned short)b_ReadHighByte) *
+				256));
+
+		pw_DataRead[i_WordCounter] = w_ReadWord;
+
+		w_EepromStartAddress += 2;	// to read the next word
+
+	}			// for (...) i_NbOfWordsToRead
+	return (0);
+}

+ 27 - 0
drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h

@@ -0,0 +1,27 @@
+/*
+ *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define AMCC_OP_REG_MCSR	0x3c
+#define EEPROM_BUSY		0x80000000
+#define NVCMD_LOAD_LOW		(0x4 << 5)	/* nvRam load low command */
+#define NVCMD_LOAD_HIGH		(0x5 << 5)	/* nvRam load high command */
+#define NVCMD_BEGIN_READ	(0x7 << 5)	/* nvRam begin read command */
+#define NVCMD_BEGIN_WRITE	(0x6 << 5)	/* EEPROM begin write command */
+
+INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead,
+			      DWORD dw_PCIBoardEepromAddress,
+			      WORD w_EepromStartAddress, PWORD pw_DataRead);

+ 476 - 0
drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h

@@ -0,0 +1,476 @@
+/*
+ *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/* Header file for AMCC  s 5933 */
+
+#ifndef _AMCC_S5933_H_
+#define _AMCC_S5933_H_
+
+#include "../../comedidev.h"
+
+#include "../comedi_pci.h"
+
+#ifdef PCI_SUPPORT_VER1
+#error     No support for 2.1.55 and older
+#endif
+
+/* written on base0 */
+#define FIFO_ADVANCE_ON_BYTE_2	0x20000000
+
+/* added for step 6 dma written on base2 */
+#define AMWEN_ENABLE		0x02
+
+#define A2P_FIFO_WRITE_ENABLE	0x01
+
+/* for transfer count enable bit */
+#define AGCSTS_TC_ENABLE	0x10000000
+
+/*
+ * ADDON RELATED ADDITIONS
+ */
+/* Constant */
+#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW		0x00
+#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH		0x1200
+#define APCI3120_A2P_FIFO_MANAGEMENT			0x04000400L
+#define APCI3120_AMWEN_ENABLE				0x02
+#define APCI3120_A2P_FIFO_WRITE_ENABLE			0x01
+#define APCI3120_FIFO_ADVANCE_ON_BYTE_2			0x20000000L
+#define APCI3120_ENABLE_WRITE_TC_INT			0x00004000L
+#define APCI3120_CLEAR_WRITE_TC_INT			0x00040000L
+#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE	0x0
+#define APCI3120_DISABLE_BUS_MASTER_ADD_ON		0x0
+#define APCI3120_DISABLE_BUS_MASTER_PCI			0x0
+
+/* ADD_ON ::: this needed since apci supports 16 bit interface to add on */
+#define APCI3120_ADD_ON_AGCSTS_LOW	0x3C
+#define APCI3120_ADD_ON_AGCSTS_HIGH	(APCI3120_ADD_ON_AGCSTS_LOW + 2)
+#define APCI3120_ADD_ON_MWAR_LOW	0x24
+#define APCI3120_ADD_ON_MWAR_HIGH	(APCI3120_ADD_ON_MWAR_LOW + 2)
+#define APCI3120_ADD_ON_MWTC_LOW	0x058
+#define APCI3120_ADD_ON_MWTC_HIGH	(APCI3120_ADD_ON_MWTC_LOW + 2)
+
+/* AMCC */
+#define APCI3120_AMCC_OP_MCSR		0x3C
+#define APCI3120_AMCC_OP_REG_INTCSR	0x38
+
+/*
+ * AMCC Operation Register Offsets - PCI
+ */
+#define AMCC_OP_REG_OMB1		0x00
+#define AMCC_OP_REG_OMB2		0x04
+#define AMCC_OP_REG_OMB3		0x08
+#define AMCC_OP_REG_OMB4		0x0c
+#define AMCC_OP_REG_IMB1		0x10
+#define AMCC_OP_REG_IMB2		0x14
+#define AMCC_OP_REG_IMB3		0x18
+#define AMCC_OP_REG_IMB4		0x1c
+#define AMCC_OP_REG_FIFO		0x20
+#define AMCC_OP_REG_MWAR		0x24
+#define AMCC_OP_REG_MWTC		0x28
+#define AMCC_OP_REG_MRAR		0x2c
+#define AMCC_OP_REG_MRTC		0x30
+#define AMCC_OP_REG_MBEF		0x34
+#define AMCC_OP_REG_INTCSR		0x38
+/* INT source */
+#define  AMCC_OP_REG_INTCSR_SRC		(AMCC_OP_REG_INTCSR + 2)
+/* FIFO ctrl */
+#define  AMCC_OP_REG_INTCSR_FEC		(AMCC_OP_REG_INTCSR + 3)
+#define AMCC_OP_REG_MCSR		0x3c
+/* Data in byte 2 */
+#define  AMCC_OP_REG_MCSR_NVDATA	(AMCC_OP_REG_MCSR + 2)
+/* Command in byte 3 */
+#define  AMCC_OP_REG_MCSR_NVCMD		(AMCC_OP_REG_MCSR + 3)
+
+#define AMCC_FIFO_DEPTH_DWORD	8
+#define AMCC_FIFO_DEPTH_BYTES	(8 * sizeof(u32))
+
+/*
+ * AMCC Operation Registers Size - PCI
+ */
+#define AMCC_OP_REG_SIZE	 64	/* in bytes */
+
+/*
+ * AMCC Operation Register Offsets - Add-on
+ */
+#define AMCC_OP_REG_AIMB1	0x00
+#define AMCC_OP_REG_AIMB2	0x04
+#define AMCC_OP_REG_AIMB3	0x08
+#define AMCC_OP_REG_AIMB4	0x0c
+#define AMCC_OP_REG_AOMB1	0x10
+#define AMCC_OP_REG_AOMB2	0x14
+#define AMCC_OP_REG_AOMB3	0x18
+#define AMCC_OP_REG_AOMB4	0x1c
+#define AMCC_OP_REG_AFIFO	0x20
+#define AMCC_OP_REG_AMWAR	0x24
+#define AMCC_OP_REG_APTA	0x28
+#define AMCC_OP_REG_APTD	0x2c
+#define AMCC_OP_REG_AMRAR	0x30
+#define AMCC_OP_REG_AMBEF	0x34
+#define AMCC_OP_REG_AINT	0x38
+#define AMCC_OP_REG_AGCSTS	0x3c
+#define AMCC_OP_REG_AMWTC	0x58
+#define AMCC_OP_REG_AMRTC	0x5c
+
+/*
+ * AMCC - Add-on General Control/Status Register
+ */
+#define AGCSTS_CONTROL_MASK	0xfffff000
+#define  AGCSTS_NV_ACC_MASK	0xe0000000
+#define  AGCSTS_RESET_MASK	0x0e000000
+#define  AGCSTS_NV_DA_MASK	0x00ff0000
+#define  AGCSTS_BIST_MASK	0x0000f000
+#define AGCSTS_STATUS_MASK	0x000000ff
+#define  AGCSTS_TCZERO_MASK	0x000000c0
+#define  AGCSTS_FIFO_ST_MASK	0x0000003f
+
+#define AGCSTS_RESET_MBFLAGS	0x08000000
+#define AGCSTS_RESET_P2A_FIFO	0x04000000
+#define AGCSTS_RESET_A2P_FIFO	0x02000000
+#define AGCSTS_RESET_FIFOS	(AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO)
+
+#define AGCSTS_A2P_TCOUNT	0x00000080
+#define AGCSTS_P2A_TCOUNT	0x00000040
+
+#define AGCSTS_FS_P2A_EMPTY	0x00000020
+#define AGCSTS_FS_P2A_HALF	0x00000010
+#define AGCSTS_FS_P2A_FULL	0x00000008
+
+#define AGCSTS_FS_A2P_EMPTY	0x00000004
+#define AGCSTS_FS_A2P_HALF	0x00000002
+#define AGCSTS_FS_A2P_FULL	0x00000001
+
+/*
+ * AMCC - Add-on Interrupt Control/Status Register
+ */
+#define AINT_INT_MASK		0x00ff0000
+#define AINT_SEL_MASK		0x0000ffff
+#define  AINT_IS_ENSEL_MASK	0x00001f1f
+
+#define AINT_INT_ASSERTED	0x00800000
+#define AINT_BM_ERROR		0x00200000
+#define AINT_BIST_INT		0x00100000
+
+#define AINT_RT_COMPLETE	0x00080000
+#define AINT_WT_COMPLETE	0x00040000
+
+#define AINT_OUT_MB_INT		0x00020000
+#define AINT_IN_MB_INT		0x00010000
+
+#define AINT_READ_COMPL		0x00008000
+#define AINT_WRITE_COMPL	0x00004000
+
+#define AINT_OMB_ENABLE 	0x00001000
+#define AINT_OMB_SELECT 	0x00000c00
+#define AINT_OMB_BYTE		0x00000300
+
+#define AINT_IMB_ENABLE 	0x00000010
+#define AINT_IMB_SELECT 	0x0000000c
+#define AINT_IMB_BYTE		0x00000003
+
+/* Enable Bus Mastering */
+#define EN_A2P_TRANSFERS	0x00000400
+/* FIFO Flag Reset */
+#define RESET_A2P_FLAGS		0x04000000L
+/* FIFO Relative Priority */
+#define A2P_HI_PRIORITY		0x00000100L
+/* Identify Interrupt Sources */
+#define ANY_S593X_INT		0x00800000L
+#define READ_TC_INT		0x00080000L
+#define WRITE_TC_INT		0x00040000L
+#define IN_MB_INT		0x00020000L
+#define MASTER_ABORT_INT	0x00100000L
+#define TARGET_ABORT_INT	0x00200000L
+#define BUS_MASTER_INT		0x00200000L
+
+/****************************************************************************/
+
+struct pcilst_struct {
+	struct pcilst_struct *next;
+	int used;
+	struct pci_dev *pcidev;
+	unsigned short vendor;
+	unsigned short device;
+	unsigned char pci_bus;
+	unsigned char pci_slot;
+	unsigned char pci_func;
+	resource_size_t io_addr[5];
+	unsigned int irq;
+};
+
+/* ptr to root list of all amcc devices */
+struct pcilst_struct *amcc_devices;
+
+static const int i_ADDIDATADeviceID[] = { 0x15B8, 0x10E8 };
+
+/****************************************************************************/
+
+void v_pci_card_list_init(unsigned short pci_vendor, char display);
+void v_pci_card_list_cleanup(unsigned short pci_vendor);
+struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id,
+						       unsigned short
+						       device_id);
+int i_find_free_pci_card_by_position(unsigned short vendor_id,
+				     unsigned short device_id,
+				     unsigned short pci_bus,
+				     unsigned short pci_slot,
+				     struct pcilst_struct **card);
+struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id,
+						    unsigned short device_id,
+						    unsigned short pci_bus,
+						    unsigned short pci_slot,
+						    int i_Master);
+
+int pci_card_alloc(struct pcilst_struct *amcc, int master);
+int i_pci_card_free(struct pcilst_struct *amcc);
+void v_pci_card_list_display(void);
+int i_pci_card_data(struct pcilst_struct *amcc,
+		    unsigned char *pci_bus, unsigned char *pci_slot,
+		    unsigned char *pci_func, resource_size_t * io_addr,
+		    unsigned int *irq);
+
+/****************************************************************************/
+
+/* build list of amcc cards in this system */
+void v_pci_card_list_init(unsigned short pci_vendor, char display)
+{
+	struct pci_dev *pcidev;
+	struct pcilst_struct *amcc, *last;
+	int i;
+	int i_Count = 0;
+	amcc_devices = NULL;
+	last = NULL;
+
+	for (pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
+	     pcidev != NULL;
+	     pcidev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pcidev)) {
+		for (i_Count = 0; i_Count < 2; i_Count++) {
+			pci_vendor = i_ADDIDATADeviceID[i_Count];
+			if (pcidev->vendor == pci_vendor) {
+				amcc = kmalloc(sizeof(*amcc), GFP_KERNEL);
+				memset(amcc, 0, sizeof(*amcc));
+
+				amcc->pcidev = pcidev;
+				if (last)
+					last->next = amcc;
+				else
+					amcc_devices = amcc;
+				last = amcc;
+
+				amcc->vendor = pcidev->vendor;
+				amcc->device = pcidev->device;
+				amcc->pci_bus = pcidev->bus->number;
+				amcc->pci_slot = PCI_SLOT(pcidev->devfn);
+				amcc->pci_func = PCI_FUNC(pcidev->devfn);
+				/* Note: resources may be invalid if PCI device
+				 * not enabled, but they are corrected in
+				 * pci_card_alloc. */
+				for (i = 0; i < 5; i++)
+					amcc->io_addr[i] =
+					    pci_resource_start(pcidev, i);
+				amcc->irq = pcidev->irq;
+
+			}
+		}
+	}
+
+	if (display)
+		v_pci_card_list_display();
+}
+
+/****************************************************************************/
+/* free up list of amcc cards in this system */
+void v_pci_card_list_cleanup(unsigned short pci_vendor)
+{
+	struct pcilst_struct *amcc, *next;
+
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		kfree(amcc);
+	}
+
+	amcc_devices = NULL;
+}
+
+/****************************************************************************/
+/* find first unused card with this device_id */
+struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id,
+						       unsigned short device_id)
+{
+	struct pcilst_struct *amcc, *next;
+
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		if ((!amcc->used) && (amcc->device == device_id)
+		    && (amcc->vendor == vendor_id))
+			return amcc;
+
+	}
+
+	return NULL;
+}
+
+/****************************************************************************/
+/* find card on requested position */
+int i_find_free_pci_card_by_position(unsigned short vendor_id,
+				     unsigned short device_id,
+				     unsigned short pci_bus,
+				     unsigned short pci_slot,
+				     struct pcilst_struct **card)
+{
+	struct pcilst_struct *amcc, *next;
+
+	*card = NULL;
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		if ((amcc->vendor == vendor_id) && (amcc->device == device_id)
+		    && (amcc->pci_bus == pci_bus)
+		    && (amcc->pci_slot == pci_slot)) {
+			if (!(amcc->used)) {
+				*card = amcc;
+				return 0;	/* ok, card is found */
+			} else {
+				rt_printk(" - \nCard on requested position is used b:s %d:%d!\n",
+					  pci_bus, pci_slot);
+				return 2;	/* card exist but is used */
+			}
+		}
+	}
+
+	/* no card found */
+	return 1;
+}
+
+/****************************************************************************/
+/* mark card as used */
+int pci_card_alloc(struct pcilst_struct *amcc, int master)
+{
+	int i;
+
+	if (!amcc)
+		return -1;
+
+	if (amcc->used)
+		return 1;
+	if (comedi_pci_enable(amcc->pcidev, "addi_amcc_s5933"))
+		return -1;
+	/* Resources will be accurate now. */
+	for (i = 0; i < 5; i++)
+		amcc->io_addr[i] = pci_resource_start(amcc->pcidev, i);
+	if (master)
+		pci_set_master(amcc->pcidev);
+	amcc->used = 1;
+
+	return 0;
+}
+
+/****************************************************************************/
+/* mark card as free */
+int i_pci_card_free(struct pcilst_struct *amcc)
+{
+	if (!amcc)
+		return -1;
+
+	if (!amcc->used)
+		return 1;
+	amcc->used = 0;
+	comedi_pci_disable(amcc->pcidev);
+	return 0;
+}
+
+/****************************************************************************/
+/* display list of found cards */
+void v_pci_card_list_display(void)
+{
+	struct pcilst_struct *amcc, *next;
+
+	printk(KERN_DEBUG "List of pci cards\n");
+	printk(KERN_DEBUG "bus:slot:func vendor device io_amcc io_daq irq used\n");
+
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		printk
+		    ("%2d   %2d   %2d  0x%4x 0x%4x   0x%8llx 0x%8llx  %2u  %2d\n",
+		     amcc->pci_bus, amcc->pci_slot, amcc->pci_func,
+		     amcc->vendor, amcc->device,
+		     (unsigned long long)amcc->io_addr[0],
+		     (unsigned long long)amcc->io_addr[2], amcc->irq,
+		     amcc->used);
+
+	}
+}
+
+/****************************************************************************/
+/* return all card information for driver */
+int i_pci_card_data(struct pcilst_struct *amcc,
+		    unsigned char *pci_bus, unsigned char *pci_slot,
+		    unsigned char *pci_func, resource_size_t * io_addr,
+		    unsigned int *irq)
+{
+	int i;
+
+	if (!amcc)
+		return -1;
+	*pci_bus = amcc->pci_bus;
+	*pci_slot = amcc->pci_slot;
+	*pci_func = amcc->pci_func;
+	for (i = 0; i < 5; i++)
+		io_addr[i] = amcc->io_addr[i];
+	*irq = amcc->irq;
+	return 0;
+}
+
+/****************************************************************************/
+/* select and alloc card */
+struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id,
+						    unsigned short device_id,
+						    unsigned short pci_bus,
+						    unsigned short pci_slot,
+						    int i_Master)
+{
+	struct pcilst_struct *card;
+
+	if ((pci_bus < 1) & (pci_slot < 1)) {
+		/* use autodetection */
+		card = ptr_find_free_pci_card_by_device(vendor_id, device_id);
+		if (card == NULL) {
+			rt_printk(" - Unused card not found in system!\n");
+			return NULL;
+		}
+	} else {
+		switch (i_find_free_pci_card_by_position(vendor_id, device_id,
+							 pci_bus, pci_slot,
+							 &card)) {
+		case 1:
+			rt_printk(" - Card not found on requested position b:s %d:%d!\n",
+				  pci_bus, pci_slot);
+			return NULL;
+		case 2:
+			rt_printk(" - Card on requested position is used b:s %d:%d!\n",
+				  pci_bus, pci_slot);
+			return NULL;
+		}
+	}
+
+	if (pci_card_alloc(card, i_Master) != 0) {
+		rt_printk(" - Can't allocate card!\n");
+		return NULL;
+
+	}
+
+	return card;
+}
+#endif

+ 3062 - 0
drivers/staging/comedi/drivers/addi-data/addi_common.c

@@ -0,0 +1,3062 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project   : ADDI DATA         | Compiler : GCC 		          |
+  | Modulname : addi_common.c     | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Author    :           | Date     :                    		  |
+  +-----------------------------------------------------------------------+
+  | Description : ADDI COMMON Main Module                                 |
+  +-----------------------------------------------------------------------+
+  | CONFIG OPTIONS                                                        |
+  |	option[0] - PCI bus number - if bus number and slot number are 0, |
+  |			         then driver search for first unused card |
+  |	option[1] - PCI slot number                                       |
+  |							                  |
+  |	option[2] = 0  - DMA ENABLE                                       |
+  |               = 1  - DMA DISABLE                                      |
+  +----------+-----------+------------------------------------------------+
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include "../../comedidev.h"
+#include <asm/io.h>
+#if defined(CONFIG_APCI_1710) || defined(CONFIG_APCI_3200) || defined(CONFIG_APCI_3300)
+#include <asm/i387.h>
+#endif
+#include "../comedi_fc.h"
+
+#include "addi_common.h"
+#include "addi_amcc_s5933.h"
+
+//Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>");
+//Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module");
+//Update-0.7.57->0.7.68MODULE_LICENSE("GPL");
+
+#define devpriv ((addi_private *)dev->private)
+#define this_board ((boardtype *)dev->board_ptr)
+
+#if defined(CONFIG_APCI_1710) || defined(CONFIG_APCI_3200) || defined(CONFIG_APCI_3300)
+//BYTE b_SaveFPUReg [94];
+
+void fpu_begin(void)
+{
+	//asm ("fstenv b_SaveFPUReg");
+	kernel_fpu_begin();
+}
+
+void fpu_end(void)
+{
+	// asm ("frstor b_SaveFPUReg");
+	kernel_fpu_end();
+}
+#endif
+
+#include "addi_eeprom.c"
+#if (defined (CONFIG_APCI_3120) || defined (CONFIG_APCI_3001))
+#include "hwdrv_apci3120.c"
+#endif
+#ifdef CONFIG_APCI_1032
+#include "hwdrv_apci1032.c"
+#endif
+#ifdef CONFIG_APCI_1516
+#include "hwdrv_apci1516.c"
+#endif
+#ifdef CONFIG_APCI_2016
+#include "hwdrv_apci2016.c"
+#endif
+#ifdef CONFIG_APCI_2032
+#include "hwdrv_apci2032.c"
+#endif
+#ifdef CONFIG_APCI_2200
+#include "hwdrv_apci2200.c"
+#endif
+#ifdef CONFIG_APCI_1564
+#include "hwdrv_apci1564.c"
+#endif
+#ifdef CONFIG_APCI_1500
+#include "hwdrv_apci1500.c"
+#endif
+#ifdef CONFIG_APCI_3501
+#include "hwdrv_apci3501.c"
+#endif
+#ifdef CONFIG_APCI_035
+#include "hwdrv_apci035.c"
+#endif
+#if (defined (CONFIG_APCI_3200) || defined (CONFIG_APCI_3300))
+#include "hwdrv_apci3200.c"
+#endif
+#ifdef CONFIG_APCI_1710
+#include "hwdrv_APCI1710.c"
+#endif
+#ifdef CONFIG_APCI_16XX
+#include "hwdrv_apci16xx.c"
+#endif
+#ifdef CONFIG_APCI_3XXX
+#include "hwdrv_apci3xxx.c"
+#endif
+
+#ifndef COMEDI_SUBD_TTLIO
+#define COMEDI_SUBD_TTLIO   11	/* Digital Input Output But TTL */
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(addi_apci_tbl) = {
+#ifdef CONFIG_APCI_3120
+	{APCI3120_BOARD_VENDOR_ID, 0x818D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_1032
+	{APCI1032_BOARD_VENDOR_ID, 0x1003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_1516
+	{APCI1516_BOARD_VENDOR_ID, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_2016
+	{APCI2016_BOARD_VENDOR_ID, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_2032
+	{APCI2032_BOARD_VENDOR_ID, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_2200
+	{APCI2200_BOARD_VENDOR_ID, 0x1005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_1564
+	{APCI1564_BOARD_VENDOR_ID, 0x1006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_1500
+	{APCI1500_BOARD_VENDOR_ID, 0x80fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_3001
+	{APCI3120_BOARD_VENDOR_ID, 0x828D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_3501
+	{APCI3501_BOARD_VENDOR_ID, 0x3001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_035
+	{APCI035_BOARD_VENDOR_ID, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_3200
+	{APCI3200_BOARD_VENDOR_ID, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_3300
+	{APCI3200_BOARD_VENDOR_ID, 0x3007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_1710
+	{APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_16XX
+	{0x15B8, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x100A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+#ifdef CONFIG_APCI_3XXX
+	{0x15B8, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x300F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x300E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x301A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x301B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x301C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x301D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x301E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x301F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x300B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x15B8, 0x3024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#endif
+	{0}
+};
+
+MODULE_DEVICE_TABLE(pci, addi_apci_tbl);
+
+static const boardtype boardtypes[] = {
+#ifdef CONFIG_APCI_3120
+	{"apci3120",
+			APCI3120_BOARD_VENDOR_ID,
+			0x818D,
+			AMCC_OP_REG_SIZE,
+			APCI3120_ADDRESS_RANGE,
+			8,
+			0,
+			ADDIDATA_NO_EEPROM,
+			NULL,
+			16,
+			8,
+			16,
+			8,
+			0xffff,
+			0x3fff,
+			&range_apci3120_ai,
+			&range_apci3120_ao,
+			4,
+			4,
+			0x0f,
+			0,
+			NULL,
+			1,
+			1,
+			1,
+			10000,
+			100000,
+			v_APCI3120_Interrupt,
+			i_APCI3120_Reset,
+			i_APCI3120_InsnConfigAnalogInput,
+			i_APCI3120_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			i_APCI3120_CommandTestAnalogInput,
+			i_APCI3120_CommandAnalogInput,
+			i_APCI3120_StopCyclicAcquisition,
+			NULL,
+			i_APCI3120_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			i_APCI3120_InsnReadDigitalInput,
+			NULL,
+			i_APCI3120_InsnBitsDigitalInput,
+			i_APCI3120_InsnConfigDigitalOutput,
+			i_APCI3120_InsnWriteDigitalOutput,
+			i_APCI3120_InsnBitsDigitalOutput,
+			NULL,
+			i_APCI3120_InsnConfigTimer,
+			i_APCI3120_InsnWriteTimer,
+			i_APCI3120_InsnReadTimer,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_1032
+	{"apci1032",
+			APCI1032_BOARD_VENDOR_ID,
+			0x1003,
+			4,
+			APCI1032_ADDRESS_RANGE,
+			0,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_93C76,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			32,
+			0,
+			0,
+			0,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			0,
+			v_APCI1032_Interrupt,
+			i_APCI1032_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI1032_ConfigDigitalInput,
+			i_APCI1032_Read1DigitalInput,
+			NULL,
+			i_APCI1032_ReadMoreDigitalInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_1516
+	{"apci1516",
+			APCI1516_BOARD_VENDOR_ID,
+			0x1001,
+			128,
+			APCI1516_ADDRESS_RANGE,
+			32,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_S5920,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			8,
+			8,
+			0,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			NULL,
+			i_APCI1516_Reset,
+			NULL, NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI1516_Read1DigitalInput,
+			NULL,
+			i_APCI1516_ReadMoreDigitalInput,
+			i_APCI1516_ConfigDigitalOutput,
+			i_APCI1516_WriteDigitalOutput,
+			i_APCI1516_ReadDigitalOutput,
+			NULL,
+			i_APCI1516_ConfigWatchdog,
+			i_APCI1516_StartStopWriteWatchdog,
+			i_APCI1516_ReadWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_2016
+	{"apci2016",
+			APCI2016_BOARD_VENDOR_ID,
+			0x1002,
+			128,
+			APCI2016_ADDRESS_RANGE,
+			32,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_S5920,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			0,
+			16,
+			0,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			NULL,
+			i_APCI2016_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI2016_ConfigDigitalOutput,
+			i_APCI2016_WriteDigitalOutput,
+			i_APCI2016_BitsDigitalOutput,
+			NULL,
+			i_APCI2016_ConfigWatchdog,
+			i_APCI2016_StartStopWriteWatchdog,
+			i_APCI2016_ReadWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_2032
+	{"apci2032",
+			APCI2032_BOARD_VENDOR_ID,
+			0x1004,
+			4,
+			APCI2032_ADDRESS_RANGE,
+			0,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_93C76,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			0,
+			32,
+			0xffffffff,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			v_APCI2032_Interrupt,
+			i_APCI2032_Reset,
+			NULL, NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI2032_ConfigDigitalOutput,
+			i_APCI2032_WriteDigitalOutput,
+			i_APCI2032_ReadDigitalOutput,
+			i_APCI2032_ReadInterruptStatus,
+			i_APCI2032_ConfigWatchdog,
+			i_APCI2032_StartStopWriteWatchdog,
+			i_APCI2032_ReadWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_2200
+	{"apci2200",
+			APCI2200_BOARD_VENDOR_ID,
+			0x1005,
+			4,
+			APCI2200_ADDRESS_RANGE,
+			0,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_93C76,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			8,
+			16,
+			0,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			NULL,
+			i_APCI2200_Reset,
+			NULL, NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI2200_Read1DigitalInput,
+			NULL,
+			i_APCI2200_ReadMoreDigitalInput,
+			i_APCI2200_ConfigDigitalOutput,
+			i_APCI2200_WriteDigitalOutput,
+			i_APCI2200_ReadDigitalOutput,
+			NULL,
+			i_APCI2200_ConfigWatchdog,
+			i_APCI2200_StartStopWriteWatchdog,
+			i_APCI2200_ReadWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_1564
+	{"apci1564",
+			APCI1564_BOARD_VENDOR_ID,
+			0x1006,
+			128,
+			APCI1564_ADDRESS_RANGE,
+			0,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_93C76,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			32,
+			32,
+			0xffffffff,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			v_APCI1564_Interrupt,
+			i_APCI1564_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI1564_ConfigDigitalInput,
+			i_APCI1564_Read1DigitalInput,
+			NULL,
+			i_APCI1564_ReadMoreDigitalInput,
+			i_APCI1564_ConfigDigitalOutput,
+			i_APCI1564_WriteDigitalOutput,
+			i_APCI1564_ReadDigitalOutput,
+			i_APCI1564_ReadInterruptStatus,
+			i_APCI1564_ConfigTimerCounterWatchdog,
+			i_APCI1564_StartStopWriteTimerCounterWatchdog,
+			i_APCI1564_ReadTimerCounterWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_1500
+	{"apci1500",
+			APCI1500_BOARD_VENDOR_ID,
+			0x80fc,
+			128,
+			APCI1500_ADDRESS_RANGE,
+			4,
+			0,
+			ADDIDATA_NO_EEPROM,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			16,
+			16,
+			0xffff,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			v_APCI1500_Interrupt,
+			i_APCI1500_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI1500_ConfigDigitalInputEvent,
+			i_APCI1500_Initialisation,
+			i_APCI1500_StartStopInputEvent,
+			i_APCI1500_ReadMoreDigitalInput,
+			i_APCI1500_ConfigDigitalOutputErrorInterrupt,
+			i_APCI1500_WriteDigitalOutput,
+			i_APCI1500_ConfigureInterrupt,
+			NULL,
+			i_APCI1500_ConfigCounterTimerWatchdog,
+			i_APCI1500_StartStopTriggerTimerCounterWatchdog,
+			i_APCI1500_ReadInterruptMask,
+			i_APCI1500_ReadCounterTimerWatchdog,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_3001
+	{"apci3001",
+			APCI3120_BOARD_VENDOR_ID,
+			0x828D,
+			AMCC_OP_REG_SIZE,
+			APCI3120_ADDRESS_RANGE,
+			8,
+			0,
+			ADDIDATA_NO_EEPROM,
+			NULL,
+			16,
+			8,
+			16,
+			0,
+			0xfff,
+			0,
+			&range_apci3120_ai,
+			NULL,
+			4,
+			4,
+			0x0f,
+			0,
+			NULL,
+			1,
+			1,
+			1,
+			10000,
+			100000,
+			v_APCI3120_Interrupt,
+			i_APCI3120_Reset,
+			i_APCI3120_InsnConfigAnalogInput,
+			i_APCI3120_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			i_APCI3120_CommandTestAnalogInput,
+			i_APCI3120_CommandAnalogInput,
+			i_APCI3120_StopCyclicAcquisition,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3120_InsnReadDigitalInput,
+			NULL,
+			i_APCI3120_InsnBitsDigitalInput,
+			i_APCI3120_InsnConfigDigitalOutput,
+			i_APCI3120_InsnWriteDigitalOutput,
+			i_APCI3120_InsnBitsDigitalOutput,
+			NULL,
+			i_APCI3120_InsnConfigTimer,
+			i_APCI3120_InsnWriteTimer,
+			i_APCI3120_InsnReadTimer,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_3501
+	{"apci3501",
+			APCI3501_BOARD_VENDOR_ID,
+			0x3001,
+			64,
+			APCI3501_ADDRESS_RANGE,
+			0,
+			0,
+			ADDIDATA_EEPROM,
+			ADDIDATA_S5933,
+			0,
+			0,
+			0,
+			8,
+			0,
+			16383,
+			NULL,
+			&range_apci3501_ao,
+			2,
+			2,
+			0x3,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			0,
+			0,
+			v_APCI3501_Interrupt,
+			i_APCI3501_Reset,
+			NULL, NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3501_ConfigAnalogOutput,
+			i_APCI3501_WriteAnalogOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3501_ReadDigitalInput,
+			i_APCI3501_ConfigDigitalOutput,
+			i_APCI3501_WriteDigitalOutput,
+			i_APCI3501_ReadDigitalOutput,
+			NULL,
+			i_APCI3501_ConfigTimerCounterWatchdog,
+			i_APCI3501_StartStopWriteTimerCounterWatchdog,
+			i_APCI3501_ReadTimerCounterWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_035
+	{"apci035",
+			APCI035_BOARD_VENDOR_ID,
+			0x0300,
+			127,
+			APCI035_ADDRESS_RANGE,
+			0,
+			0,
+			1,
+			ADDIDATA_S5920,
+			16,
+			8,
+			16,
+			0,
+			0xff,
+			0,
+			&range_apci035_ai,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			0,
+			1,
+			0,
+			10000,
+			100000,
+			v_APCI035_Interrupt,
+			i_APCI035_Reset,
+			i_APCI035_ConfigAnalogInput,
+			i_APCI035_ReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI035_ConfigTimerWatchdog,
+			i_APCI035_StartStopWriteTimerWatchdog,
+			i_APCI035_ReadTimerWatchdog,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_3200
+	{"apci3200",
+			APCI3200_BOARD_VENDOR_ID,
+			0x3000,
+			128,
+			256,
+			4,
+			4,
+			ADDIDATA_EEPROM,
+			ADDIDATA_S5920,
+			16,
+			8,
+			16,
+			0,
+			0x3ffff,
+			0,
+			&range_apci3200_ai,
+			NULL,
+			4,
+			4,
+			0,
+			0,
+			NULL,
+			0,
+			0,
+			0,
+			10000,
+			100000,
+			v_APCI3200_Interrupt,
+			i_APCI3200_Reset,
+			i_APCI3200_ConfigAnalogInput,
+			i_APCI3200_ReadAnalogInput,
+			i_APCI3200_InsnWriteReleaseAnalogInput,
+			i_APCI3200_InsnBits_AnalogInput_Test,
+			i_APCI3200_CommandTestAnalogInput,
+			i_APCI3200_CommandAnalogInput,
+			i_APCI3200_StopCyclicAcquisition,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3200_ReadDigitalInput,
+			i_APCI3200_ConfigDigitalOutput,
+			i_APCI3200_WriteDigitalOutput,
+			i_APCI3200_ReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_3300
+	//Begin JK 20.10.2004: APCI-3300 integration
+	{"apci3300",
+			APCI3200_BOARD_VENDOR_ID,
+			0x3007,
+			128,
+			256,
+			4,
+			4,
+			ADDIDATA_EEPROM,
+			ADDIDATA_S5920,
+			0,
+			8,
+			8,
+			0,
+			0x3ffff,
+			0,
+			&range_apci3300_ai,
+			NULL,
+			4,
+			4,
+			0,
+			0,
+			NULL,
+			0,
+			0,
+			0,
+			10000,
+			100000,
+			v_APCI3200_Interrupt,
+			i_APCI3200_Reset,
+			i_APCI3200_ConfigAnalogInput,
+			i_APCI3200_ReadAnalogInput,
+			i_APCI3200_InsnWriteReleaseAnalogInput,
+			i_APCI3200_InsnBits_AnalogInput_Test,
+			i_APCI3200_CommandTestAnalogInput,
+			i_APCI3200_CommandAnalogInput,
+			i_APCI3200_StopCyclicAcquisition,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3200_ReadDigitalInput,
+			i_APCI3200_ConfigDigitalOutput,
+			i_APCI3200_WriteDigitalOutput,
+			i_APCI3200_ReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_1710
+	{"apci1710", APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID,
+			128,
+			8,
+			256,
+			0,
+			ADDIDATA_NO_EEPROM,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			0,
+			v_APCI1710_Interrupt,
+			i_APCI1710_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+#endif
+#ifdef CONFIG_APCI_16XX
+	{"apci1648",
+			0x15B8,
+			0x1009,
+			128,
+			0,
+			0,
+			0,
+			ADDIDATA_NO_EEPROM,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			0,
+			0,
+			0,
+			48,
+			&range_apci16xx_ttl,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			i_APCI16XX_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI16XX_InsnConfigInitTTLIO,
+			i_APCI16XX_InsnBitsReadTTLIO,
+			i_APCI16XX_InsnReadTTLIOAllPortValue,
+		i_APCI16XX_InsnBitsWriteTTLIO},
+
+	{"apci1696",
+			0x15B8,
+			0x100A,
+			128,
+			0,
+			0,
+			0,
+			ADDIDATA_NO_EEPROM,
+			NULL,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			NULL,
+			0,
+			0,
+			0,
+			96,
+			&range_apci16xx_ttl,
+			0,
+			0,
+			0,
+			0,
+			0,
+			NULL,
+			i_APCI16XX_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI16XX_InsnConfigInitTTLIO,
+			i_APCI16XX_InsnBitsReadTTLIO,
+			i_APCI16XX_InsnReadTTLIOAllPortValue,
+		i_APCI16XX_InsnBitsWriteTTLIO},
+#endif
+#ifdef CONFIG_APCI_3XXX
+	{"apci3000-16",
+			0x15B8,
+			0x3010,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			0,
+			4095,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3000-8",
+			0x15B8,
+			0x300F,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			0,
+			4095,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3000-4",
+			0x15B8,
+			0x300E,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			4,
+			2,
+			4,
+			0,
+			4095,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3006-16",
+			0x15B8,
+			0x3013,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3006-8",
+			0x15B8,
+			0x3014,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3006-4",
+			0x15B8,
+			0x3015,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			4,
+			2,
+			4,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3010-16",
+			0x15B8,
+			0x3016,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			0,
+			4095,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3010-8",
+			0x15B8,
+			0x3017,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			0,
+			4095,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3010-4",
+			0x15B8,
+			0x3018,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			4,
+			2,
+			4,
+			0,
+			4095,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3016-16",
+			0x15B8,
+			0x3019,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3016-8",
+			0x15B8,
+			0x301A,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3016-4",
+			0x15B8,
+			0x301B,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			4,
+			2,
+			4,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3100-16-4",
+			0x15B8,
+			0x301C,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			4,
+			4095,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3100-8-4",
+			0x15B8,
+			0x301D,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			4,
+			4095,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3106-16-4",
+			0x15B8,
+			0x301E,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			4,
+			65535,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3106-8-4",
+			0x15B8,
+			0x301F,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			4,
+			65535,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			10000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3110-16-4",
+			0x15B8,
+			0x3020,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			4,
+			4095,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3110-8-4",
+			0x15B8,
+			0x3021,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			4,
+			4095,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3116-16-4",
+			0x15B8,
+			0x3022,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			16,
+			8,
+			16,
+			4,
+			65535,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3116-8-4",
+			0x15B8,
+			0x3023,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			8,
+			4,
+			8,
+			4,
+			65535,
+			4095,
+			&range_apci3XXX_ai,
+			&range_apci3XXX_ao,
+			4,
+			4,
+			1,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+
+	{"apci3003",
+			0x15B8,
+			0x300B,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			0,
+			4,
+			4,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			0,
+			NULL,
+			0,
+			0,
+			7,
+			2500,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+
+	{"apci3002-16",
+			0x15B8,
+			0x3002,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			0,
+			16,
+			16,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			0,
+			NULL,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+
+	{"apci3002-8",
+			0x15B8,
+			0x3003,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			0,
+			8,
+			8,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			0,
+			NULL,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+
+	{"apci3002-4",
+			0x15B8,
+			0x3004,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			0,
+			4,
+			4,
+			0,
+			65535,
+			0,
+			&range_apci3XXX_ai,
+			NULL,
+			4,
+			4,
+			1,
+			0,
+			NULL,
+			0,
+			0,
+			6,
+			5000,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			i_APCI3XXX_InsnConfigAnalogInput,
+			i_APCI3XXX_InsnReadAnalogInput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnReadDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnBitsDigitalInput,
+			NULL,
+			i_APCI3XXX_InsnWriteDigitalOutput,
+			i_APCI3XXX_InsnBitsDigitalOutput,
+			i_APCI3XXX_InsnReadDigitalOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+		NULL},
+
+	{"apci3500",
+			0x15B8,
+			0x3024,
+			256,
+			256,
+			256,
+			256,
+			ADDIDATA_NO_EEPROM,
+			ADDIDATA_9054,
+			0,
+			0,
+			0,
+			4,
+			0,
+			4095,
+			NULL,
+			&range_apci3XXX_ao,
+			0,
+			0,
+			0,
+			24,
+			&range_apci3XXX_ttl,
+			0,
+			0,
+			0,
+			0,
+			0,
+			v_APCI3XXX_Interrupt,
+			i_APCI3XXX_Reset,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnWriteAnalogOutput,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			NULL,
+			i_APCI3XXX_InsnConfigInitTTLIO,
+			i_APCI3XXX_InsnBitsTTLIO,
+			i_APCI3XXX_InsnReadTTLIO,
+		i_APCI3XXX_InsnWriteTTLIO},
+#endif
+};
+
+#define n_boardtypes (sizeof(boardtypes)/sizeof(boardtype))
+
+struct comedi_driver driver_addi = {
+      driver_name:"addi_common",
+      module:THIS_MODULE,
+      attach:i_ADDI_Attach,
+      detach:i_ADDI_Detach,
+      num_names:n_boardtypes,
+      board_name:&boardtypes[0].pc_DriverName,
+      offset:sizeof(boardtype),
+};
+
+COMEDI_PCI_INITCLEANUP(driver_addi, addi_apci_tbl);
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :static int i_ADDI_Attach(struct comedi_device *dev,            |
+|										struct comedi_devconfig *it)        |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              :Detects the card.                                       |
+|  			 Configure the driver for a particular board.            |
+|  			 This function does all the initializations and memory   |
+|			 allocation of data structures for the driver.	         |
++----------------------------------------------------------------------------+
+| Input Parameters  :struct comedi_device *dev										 |
+|                    struct comedi_devconfig *it									 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :  0            					                     |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+static int i_ADDI_Attach(struct comedi_device * dev, struct comedi_devconfig * it)
+{
+	struct comedi_subdevice *s;
+	int ret, pages, i, n_subdevices;
+	DWORD dw_Dummy;
+	resource_size_t io_addr[5];
+	unsigned int irq;
+	resource_size_t iobase_a, iobase_main, iobase_addon, iobase_reserved;
+	struct pcilst_struct *card = NULL;
+	unsigned char pci_bus, pci_slot, pci_func;
+	int i_Dma = 0;
+	static char c_Identifier[150];
+
+	sprintf(c_Identifier, "Addi-Data GmbH Comedi %s",
+		this_board->pc_DriverName);
+
+	if ((ret = alloc_private(dev, sizeof(addi_private))) < 0) {
+	  	return -ENOMEM;
+	}
+
+	if (!pci_list_builded) {
+		v_pci_card_list_init(this_board->i_VendorId, 1);	//1 for displaying the list..
+		pci_list_builded = 1;
+	}
+	//rt_printk("comedi%d: addi_common: board=%s",dev->minor,this_board->pc_DriverName);
+
+	if ((this_board->i_Dma) && (it->options[2] == 0)) {
+		i_Dma = 1;
+	}
+
+	if ((card = ptr_select_and_alloc_pci_card(this_board->i_VendorId,
+				this_board->i_DeviceId,
+				it->options[0],
+				it->options[1], i_Dma)) == NULL) {
+		return -EIO;
+	}
+	devpriv->allocated = 1;
+
+	if ((i_pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0],
+				&irq)) < 0) {
+		i_pci_card_free(card);
+		printk(" - Can't get AMCC data!\n");
+		return -EIO;
+	}
+
+	iobase_a = io_addr[0];
+	iobase_main = io_addr[1];
+	iobase_addon = io_addr[2];
+	iobase_reserved = io_addr[3];
+	printk("\nBus %d: Slot %d: Funct%d\nBase0: 0x%8llx\nBase1: 0x%8llx\nBase2: 0x%8llx\nBase3: 0x%8llx\n", pci_bus, pci_slot, pci_func, (unsigned long long)io_addr[0], (unsigned long long)io_addr[1], (unsigned long long)io_addr[2], (unsigned long long)io_addr[3]);
+
+	if ((this_board->pc_EepromChip == NULL)
+		|| (strcmp(this_board->pc_EepromChip, ADDIDATA_9054) != 0)) {
+	   /************************************/
+		/* Test if more that 1 address used */
+	   /************************************/
+
+		if (this_board->i_IorangeBase1 != 0) {
+			dev->iobase = (unsigned long)iobase_main;	// DAQ base address...
+		} else {
+			dev->iobase = (unsigned long)iobase_a;	// DAQ base address...
+		}
+
+		dev->board_name = this_board->pc_DriverName;
+		devpriv->amcc = card;
+		devpriv->iobase = (INT) dev->iobase;
+		devpriv->i_IobaseAmcc = (INT) iobase_a;	//AMCC base address...
+		devpriv->i_IobaseAddon = (INT) iobase_addon;	//ADD ON base address....
+		devpriv->i_IobaseReserved = (INT) iobase_reserved;
+		devpriv->ps_BoardInfo = this_board;
+	} else {
+		dev->board_name = this_board->pc_DriverName;
+		dev->iobase = (unsigned long)io_addr[2];
+		devpriv->amcc = card;
+		devpriv->iobase = (INT) io_addr[2];
+		devpriv->ps_BoardInfo = this_board;
+		devpriv->i_IobaseReserved = (INT) io_addr[3];
+		printk("\nioremap begin");
+		devpriv->dw_AiBase =
+			(ULONG_PTR) ioremap(io_addr[3],
+			this_board->i_IorangeBase3);
+		printk("\nioremap end");
+	}
+
+	//##
+
+	if (irq > 0) {
+		if (comedi_request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED,
+				c_Identifier, dev) < 0) {
+			printk(", unable to allocate IRQ %u, DISABLING IT",
+				irq);
+			irq = 0;	/* Can't use IRQ */
+		} else {
+			rt_printk("\nirq=%u", irq);
+		}
+	} else {
+		rt_printk(", IRQ disabled");
+	}
+
+	printk("\nOption %d %d %d\n", it->options[0], it->options[1],
+		it->options[2]);
+	dev->irq = irq;
+
+	// Read eepeom and fill boardtype Structure
+
+	if (this_board->i_PCIEeprom) {
+		printk("\nPCI Eeprom used");
+		if (!(strcmp(this_board->pc_EepromChip, "S5920"))) {
+			// Set 3 wait stait
+			if (!(strcmp(this_board->pc_DriverName, "apci035"))) {
+				outl(0x80808082, devpriv->i_IobaseAmcc + 0x60);
+			} else {
+				outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
+			}
+			// Enable the interrupt for the controler
+			dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
+			outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
+			printk("\nEnable the interrupt for the controler");
+		}
+		printk("\nRead Eeprom");
+		i_EepromReadMainHeader(io_addr[0], this_board->pc_EepromChip,
+			dev);
+	} else {
+		printk("\nPCI Eeprom unused");
+	}
+
+	if (it->options[2] > 0) {
+		devpriv->us_UseDma = ADDI_DISABLE;
+	} else {
+		devpriv->us_UseDma = ADDI_ENABLE;
+	}
+
+	if (this_board->i_Dma) {
+		printk("\nDMA used");
+		if (devpriv->us_UseDma == ADDI_ENABLE) {
+			// alloc DMA buffers
+			devpriv->b_DmaDoubleBuffer = 0;
+			for (i = 0; i < 2; i++) {
+				for (pages = 4; pages >= 0; pages--) {
+					if ((devpriv->ul_DmaBufferVirtual[i] =
+							(void *)
+							__get_free_pages
+							(GFP_KERNEL, pages))) {
+						break;
+					}
+				}
+				if (devpriv->ul_DmaBufferVirtual[i]) {
+					devpriv->ui_DmaBufferPages[i] = pages;
+					devpriv->ui_DmaBufferSize[i] =
+						PAGE_SIZE * pages;
+					devpriv->ui_DmaBufferSamples[i] =
+						devpriv->
+						ui_DmaBufferSize[i] >> 1;
+					devpriv->ul_DmaBufferHw[i] =
+						virt_to_bus((void *)devpriv->
+						ul_DmaBufferVirtual[i]);
+				}
+			}
+			if (!devpriv->ul_DmaBufferVirtual[0]) {
+				rt_printk
+					(", Can't allocate DMA buffer, DMA disabled!");
+				devpriv->us_UseDma = ADDI_DISABLE;
+			}
+
+			if (devpriv->ul_DmaBufferVirtual[1]) {
+				devpriv->b_DmaDoubleBuffer = 1;
+			}
+		}
+
+		if ((devpriv->us_UseDma == ADDI_ENABLE)) {
+			rt_printk("\nDMA ENABLED\n");
+		} else {
+			printk("\nDMA DISABLED\n");
+		}
+	}
+
+	if (!strcmp(this_board->pc_DriverName, "apci1710")) {
+#ifdef CONFIG_APCI_1710
+		i_ADDI_AttachPCI1710(dev);
+
+		// save base address
+		devpriv->s_BoardInfos.ui_Address = io_addr[2];
+#endif
+	} else {
+		//Update-0.7.57->0.7.68dev->n_subdevices = 7;
+		n_subdevices = 7;
+		if ((ret = alloc_subdevices(dev, n_subdevices)) < 0)
+			return ret;
+
+		// Allocate and Initialise AI Subdevice Structures
+		s = dev->subdevices + 0;
+		if ((this_board->i_NbrAiChannel)
+			|| (this_board->i_NbrAiChannelDiff)) {
+			dev->read_subdev = s;
+			s->type = COMEDI_SUBD_AI;
+			s->subdev_flags =
+				SDF_READABLE | SDF_RT | SDF_COMMON | SDF_GROUND
+				| SDF_DIFF;
+			if (this_board->i_NbrAiChannel) {
+				s->n_chan = this_board->i_NbrAiChannel;
+				devpriv->b_SingelDiff = 0;
+			} else {
+				s->n_chan = this_board->i_NbrAiChannelDiff;
+				devpriv->b_SingelDiff = 1;
+			}
+			s->maxdata = this_board->i_AiMaxdata;
+			s->len_chanlist = this_board->i_AiChannelList;
+			s->range_table = this_board->pr_AiRangelist;
+
+			/* Set the initialisation flag */
+			devpriv->b_AiInitialisation = 1;
+
+			s->insn_config =
+				this_board->i_hwdrv_InsnConfigAnalogInput;
+			s->insn_read = this_board->i_hwdrv_InsnReadAnalogInput;
+			s->insn_write =
+				this_board->i_hwdrv_InsnWriteAnalogInput;
+			s->insn_bits = this_board->i_hwdrv_InsnBitsAnalogInput;
+			s->do_cmdtest =
+				this_board->i_hwdrv_CommandTestAnalogInput;
+			s->do_cmd = this_board->i_hwdrv_CommandAnalogInput;
+			s->cancel = this_board->i_hwdrv_CancelAnalogInput;
+
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+
+		// Allocate and Initialise AO Subdevice Structures
+		s = dev->subdevices + 1;
+		if (this_board->i_NbrAoChannel) {
+			s->type = COMEDI_SUBD_AO;
+			s->subdev_flags =
+				SDF_WRITEABLE | SDF_GROUND | SDF_COMMON |
+				SDF_RT;
+			s->n_chan = this_board->i_NbrAoChannel;
+			s->maxdata = this_board->i_AoMaxdata;
+			s->len_chanlist = this_board->i_NbrAoChannel;
+			s->range_table = this_board->pr_AoRangelist;
+			s->insn_config =
+				this_board->i_hwdrv_InsnConfigAnalogOutput;
+			s->insn_write =
+				this_board->i_hwdrv_InsnWriteAnalogOutput;
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+		// Allocate and Initialise DI Subdevice Structures
+		s = dev->subdevices + 2;
+		if (this_board->i_NbrDiChannel) {
+			s->type = COMEDI_SUBD_DI;
+			s->subdev_flags =
+				SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+			s->n_chan = this_board->i_NbrDiChannel;
+			s->maxdata = 1;
+			s->len_chanlist = this_board->i_NbrDiChannel;
+			s->range_table = &range_digital;
+			s->io_bits = 0;	/* all bits input */
+			s->insn_config =
+				this_board->i_hwdrv_InsnConfigDigitalInput;
+			s->insn_read = this_board->i_hwdrv_InsnReadDigitalInput;
+			s->insn_write =
+				this_board->i_hwdrv_InsnWriteDigitalInput;
+			s->insn_bits = this_board->i_hwdrv_InsnBitsDigitalInput;
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+		// Allocate and Initialise DO Subdevice Structures
+		s = dev->subdevices + 3;
+		if (this_board->i_NbrDoChannel) {
+			s->type = COMEDI_SUBD_DO;
+			s->subdev_flags =
+				SDF_READABLE | SDF_WRITEABLE | SDF_RT |
+				SDF_GROUND | SDF_COMMON;
+			s->n_chan = this_board->i_NbrDoChannel;
+			s->maxdata = this_board->i_DoMaxdata;
+			s->len_chanlist = this_board->i_NbrDoChannel;
+			s->range_table = &range_digital;
+			s->io_bits = 0xf;	/* all bits output */
+
+			s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput;	//for digital output memory..
+			s->insn_write =
+				this_board->i_hwdrv_InsnWriteDigitalOutput;
+			s->insn_bits =
+				this_board->i_hwdrv_InsnBitsDigitalOutput;
+			s->insn_read =
+				this_board->i_hwdrv_InsnReadDigitalOutput;
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+
+		// Allocate and Initialise Timer Subdevice Structures
+		s = dev->subdevices + 4;
+		if (this_board->i_Timer) {
+			s->type = COMEDI_SUBD_TIMER;
+			s->subdev_flags =
+				SDF_WRITEABLE | SDF_RT | SDF_GROUND |
+				SDF_COMMON;
+			s->n_chan = 1;
+			s->maxdata = 0;
+			s->len_chanlist = 1;
+			s->range_table = &range_digital;
+
+			s->insn_write = this_board->i_hwdrv_InsnWriteTimer;
+			s->insn_read = this_board->i_hwdrv_InsnReadTimer;
+			s->insn_config = this_board->i_hwdrv_InsnConfigTimer;
+			s->insn_bits = this_board->i_hwdrv_InsnBitsTimer;
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+
+		// Allocate and Initialise TTL
+		s = dev->subdevices + 5;
+		if (this_board->i_NbrTTLChannel) {
+			s->type = COMEDI_SUBD_TTLIO;
+			s->subdev_flags =
+				SDF_WRITEABLE | SDF_READABLE | SDF_RT |
+				SDF_GROUND | SDF_COMMON;
+			s->n_chan = this_board->i_NbrTTLChannel;
+			s->maxdata = 1;
+			s->io_bits = 0;	/* all bits input */
+			s->len_chanlist = this_board->i_NbrTTLChannel;
+			s->range_table = &range_digital;
+			s->insn_config = this_board->i_hwdr_ConfigInitTTLIO;
+			s->insn_bits = this_board->i_hwdr_ReadTTLIOBits;
+			s->insn_read = this_board->i_hwdr_ReadTTLIOAllPortValue;
+			s->insn_write = this_board->i_hwdr_WriteTTLIOChlOnOff;
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+
+		/* EEPROM */
+		s = dev->subdevices + 6;
+		if (this_board->i_PCIEeprom) {
+			s->type = COMEDI_SUBD_MEMORY;
+			s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
+			s->n_chan = 256;
+			s->maxdata = 0xffff;
+			s->insn_read = i_ADDIDATA_InsnReadEeprom;
+		} else {
+			s->type = COMEDI_SUBD_UNUSED;
+		}
+	}
+
+	printk("\ni_ADDI_Attach end\n");
+	i_ADDI_Reset(dev);
+	devpriv->b_ValidDriver = 1;
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : static int i_ADDI_Detach(struct comedi_device *dev)           |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : Deallocates resources of the addi_common driver        |
+|			  Free the DMA buffers, unregister irq.				     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      : 0             					                     |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+static int i_ADDI_Detach(struct comedi_device * dev)
+{
+
+	if (dev->private) {
+		if (devpriv->b_ValidDriver) {
+			i_ADDI_Reset(dev);
+		}
+
+		if (dev->irq) {
+			comedi_free_irq(dev->irq, dev);
+		}
+
+		if ((devpriv->ps_BoardInfo->pc_EepromChip == NULL)
+			|| (strcmp(devpriv->ps_BoardInfo->pc_EepromChip,
+					ADDIDATA_9054) != 0)) {
+			if (devpriv->allocated) {
+				i_pci_card_free(devpriv->amcc);
+			}
+
+			if (devpriv->ul_DmaBufferVirtual[0]) {
+				free_pages((unsigned long)devpriv->
+					ul_DmaBufferVirtual[0],
+					devpriv->ui_DmaBufferPages[0]);
+			}
+
+			if (devpriv->ul_DmaBufferVirtual[1]) {
+				free_pages((unsigned long)devpriv->
+					ul_DmaBufferVirtual[1],
+					devpriv->ui_DmaBufferPages[1]);
+			}
+		} else {
+			iounmap((void *)devpriv->dw_AiBase);
+
+			if (devpriv->allocated) {
+				i_pci_card_free(devpriv->amcc);
+			}
+		}
+
+		if (pci_list_builded) {
+			//v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC);
+			v_pci_card_list_cleanup(this_board->i_VendorId);
+			pci_list_builded = 0;
+		}
+	}
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : static int i_ADDI_Reset(struct comedi_device *dev)			 |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Disables all interrupts, Resets digital output to low, |
+|				Set all analog output to low						 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      : 0           					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+static int i_ADDI_Reset(struct comedi_device * dev)
+{
+
+	this_board->i_hwdrv_Reset(dev);
+	return 0;
+}
+
+// Interrupt function
+/*
++----------------------------------------------------------------------------+
+| Function name     :                                                        |
+|static void v_ADDI_Interrupt(int irq, void *d  PT_REGS_ARG)                 |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Registerd interrupt routine						     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 	int irq												 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+static irqreturn_t v_ADDI_Interrupt(int irq, void *d PT_REGS_ARG)
+{
+	struct comedi_device *dev = d;
+	this_board->v_hwdrv_Interrupt(irq, d);
+	return IRQ_RETVAL(1);
+}
+
+// EEPROM Read Function
+/*
++----------------------------------------------------------------------------+
+| Function name     :                                                        |
+|INT i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev,struct comedi_subdevice *s,
+							struct comedi_insn *insn,unsigned int *data)
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Read 256 words from EEPROM          				     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  :(struct comedi_device *dev,struct comedi_subdevice *s,
+			struct comedi_insn *insn,unsigned int *data) 						 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+static int i_ADDIDATA_InsnReadEeprom(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	WORD w_Data;
+	WORD w_Address;
+	w_Address = CR_CHAN(insn->chanspec);	// address to be read as 0,1,2,3...255
+
+	w_Data = w_EepromReadWord(devpriv->i_IobaseAmcc,
+		this_board->pc_EepromChip, 0x100 + (2 * w_Address));
+	data[0] = w_Data;
+	//multiplied by 2 bcozinput will be like 0,1,2...255
+	return insn->n;
+
+}

+ 462 - 0
drivers/staging/comedi/drivers/addi-data/addi_common.h

@@ -0,0 +1,462 @@
+/*
+ *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/kmod.h>
+#include <linux/uaccess.h>
+#include "../../comedidev.h"
+#include "addi_amcc_s5933.h"
+
+#define ERROR	-1
+#define SUCCESS	1
+
+/* variable type definition */
+typedef unsigned char BYTE, *PBYTE;
+typedef short SHORT, *PSHORT;
+typedef unsigned short USHORT, *PUSHORT;
+typedef unsigned short WORD, *PWORD;
+typedef int INT, *PINT;;
+typedef unsigned int UINT, *PUINT;
+typedef int LONG, *PLONG;		/* 32-bit */
+typedef unsigned int ULONG, *PULONG;	/* 32-bit */
+typedef unsigned int DWORD, *PDWORD;	/* 32-bit */
+typedef unsigned long ULONG_PTR;
+
+typedef const struct comedi_lrange *PCRANGE;
+
+#define LOBYTE(W)	(BYTE)((W) & 0xFF)
+#define HIBYTE(W)	(BYTE)(((W) >> 8) & 0xFF)
+#define MAKEWORD(H, L)	(USHORT)((L) | ((H) << 8))
+#define LOWORD(W)	(USHORT)((W) & 0xFFFF)
+#define HIWORD(W)	(USHORT)(((W) >> 16) & 0xFFFF)
+#define MAKEDWORD(H, L)	(UINT)((L) | ((H) << 16))
+
+#define ADDI_ENABLE		1
+#define ADDI_DISABLE		0
+#define APCI1710_SAVE_INTERRUPT	1
+
+#define ADDIDATA_EEPROM		1
+#define ADDIDATA_NO_EEPROM	0
+#define ADDIDATA_93C76		"93C76"
+#define ADDIDATA_S5920		"S5920"
+#define ADDIDATA_S5933		"S5933"
+#define ADDIDATA_9054		"9054"
+
+/* ADDIDATA Enable Disable */
+#define ADDIDATA_ENABLE		1
+#define ADDIDATA_DISABLE	0
+
+/* Structures */
+
+/* structure for the boardtype */
+typedef struct {
+	const char *pc_DriverName;	// driver name
+	INT i_VendorId;		//PCI vendor a device ID of card
+	INT i_DeviceId;
+	INT i_IorangeBase0;
+	INT i_IorangeBase1;
+	INT i_IorangeBase2;	//  base 2 range
+	INT i_IorangeBase3;	//  base 3 range
+	INT i_PCIEeprom;	// eeprom present or not
+	char *pc_EepromChip;	// type of chip
+	INT i_NbrAiChannel;	// num of A/D chans
+	INT i_NbrAiChannelDiff;	// num of A/D chans in diff mode
+	INT i_AiChannelList;	// len of chanlist
+	INT i_NbrAoChannel;	// num of D/A chans
+	INT i_AiMaxdata;	// resolution of A/D
+	INT i_AoMaxdata;	// resolution of D/A
+	PCRANGE pr_AiRangelist;	// rangelist for A/D
+	PCRANGE pr_AoRangelist;	// rangelist for D/A
+
+	INT i_NbrDiChannel;	// Number of DI channels
+	INT i_NbrDoChannel;	// Number of DO channels
+	INT i_DoMaxdata;	// data to set all chanels high
+
+	INT i_NbrTTLChannel;	// Number of TTL channels
+	PCRANGE pr_TTLRangelist;	// rangelist for TTL
+
+	INT i_Dma;		// dma present or not
+	INT i_Timer;		//   timer subdevice present or not
+	BYTE b_AvailableConvertUnit;
+	UINT ui_MinAcquisitiontimeNs;	// Minimum Acquisition in Nano secs
+	UINT ui_MinDelaytimeNs;	// Minimum Delay in Nano secs
+
+	/* interrupt and reset */
+	void (*v_hwdrv_Interrupt)(int irq, void *d);
+	int (*i_hwdrv_Reset)(struct comedi_device *dev);
+
+	/* Subdevice functions */
+
+	/* ANALOG INPUT */
+	int (*i_hwdrv_InsnConfigAnalogInput)(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+	int (*i_hwdrv_InsnReadAnalogInput)(struct comedi_device *dev,
+					    struct comedi_subdevice *s,
+					    struct comedi_insn *insn,
+					    unsigned int *data);
+	int (*i_hwdrv_InsnWriteAnalogInput)(struct comedi_device *dev,
+					    struct comedi_subdevice *s,
+					    struct comedi_insn *insn,
+					    unsigned int *data);
+	int (*i_hwdrv_InsnBitsAnalogInput)(struct comedi_device *dev,
+					   struct comedi_subdevice *s,
+					   struct comedi_insn *insn,
+					   unsigned int *data);
+	int (*i_hwdrv_CommandTestAnalogInput)(struct comedi_device *dev,
+					      struct comedi_subdevice *s,
+					      struct comedi_cmd *cmd);
+	int (*i_hwdrv_CommandAnalogInput)(struct comedi_device *dev,
+					  struct comedi_subdevice *s);
+	int (*i_hwdrv_CancelAnalogInput)(struct comedi_device *dev,
+					 struct comedi_subdevice *s);
+
+	/* Analog Output */
+	int (*i_hwdrv_InsnConfigAnalogOutput)(struct comedi_device *dev,
+					      struct comedi_subdevice *s,
+					      struct comedi_insn *insn,
+					      unsigned int *data);
+	int (*i_hwdrv_InsnWriteAnalogOutput)(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+	int (*i_hwdrv_InsnBitsAnalogOutput)(struct comedi_device *dev,
+					    struct comedi_subdevice *s,
+					    struct comedi_insn *insn,
+					    unsigned int *data);
+
+	/* Digital Input */
+	int (*i_hwdrv_InsnConfigDigitalInput) (struct comedi_device *dev,
+					       struct comedi_subdevice *s,
+					       struct comedi_insn *insn,
+					       unsigned int *data);
+	int (*i_hwdrv_InsnReadDigitalInput) (struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+	int (*i_hwdrv_InsnWriteDigitalInput) (struct comedi_device *dev,
+					      struct comedi_subdevice *s,
+					      struct comedi_insn *insn,
+					      unsigned int *data);
+	int (*i_hwdrv_InsnBitsDigitalInput) (struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+
+	/* Digital Output */
+	int (*i_hwdrv_InsnConfigDigitalOutput)(struct comedi_device *dev,
+					       struct comedi_subdevice *s,
+					       struct comedi_insn *insn,
+					       unsigned int *data);
+	int (*i_hwdrv_InsnWriteDigitalOutput)(struct comedi_device *dev,
+					      struct comedi_subdevice *s,
+					      struct comedi_insn *insn,
+					      unsigned int *data);
+	int (*i_hwdrv_InsnBitsDigitalOutput)(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+	int (*i_hwdrv_InsnReadDigitalOutput)(struct comedi_device *dev,
+					     struct comedi_subdevice *s,
+					     struct comedi_insn *insn,
+					     unsigned int *data);
+
+	/* TIMER */
+	int (*i_hwdrv_InsnConfigTimer)(struct comedi_device *dev,
+				       struct comedi_subdevice *s,
+				       struct comedi_insn *insn, unsigned int *data);
+	int (*i_hwdrv_InsnWriteTimer)(struct comedi_device *dev,
+				      struct comedi_subdevice *s, struct comedi_insn *insn,
+				      unsigned int *data);
+	int (*i_hwdrv_InsnReadTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+	int (*i_hwdrv_InsnBitsTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+
+	/* TTL IO */
+	int (*i_hwdr_ConfigInitTTLIO)(struct comedi_device *dev,
+				      struct comedi_subdevice *s, struct comedi_insn *insn,
+				      unsigned int *data);
+	int (*i_hwdr_ReadTTLIOBits)(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+	int (*i_hwdr_ReadTTLIOAllPortValue)(struct comedi_device *dev,
+					    struct comedi_subdevice *s,
+					    struct comedi_insn *insn,
+					    unsigned int *data);
+	int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+} boardtype;
+
+//MODULE INFO STRUCTURE
+
+typedef union {
+	/* Incremental counter infos */
+	struct {
+		union {
+			struct {
+				BYTE b_ModeRegister1;
+				BYTE b_ModeRegister2;
+				BYTE b_ModeRegister3;
+				BYTE b_ModeRegister4;
+			} s_ByteModeRegister;
+			DWORD dw_ModeRegister1_2_3_4;
+		} s_ModeRegister;
+
+		struct {
+			unsigned int b_IndexInit:1;
+			unsigned int b_CounterInit:1;
+			unsigned int b_ReferenceInit:1;
+			unsigned int b_IndexInterruptOccur:1;
+			unsigned int b_CompareLogicInit:1;
+			unsigned int b_FrequencyMeasurementInit:1;
+			unsigned int b_FrequencyMeasurementEnable:1;
+		} s_InitFlag;
+
+	} s_SiemensCounterInfo;
+
+	/* SSI infos */
+	struct {
+		BYTE b_SSIProfile;
+		BYTE b_PositionTurnLength;
+		BYTE b_TurnCptLength;
+		BYTE b_SSIInit;
+	} s_SSICounterInfo;
+
+	/* TTL I/O infos */
+	struct {
+		BYTE b_TTLInit;
+		BYTE b_PortConfiguration[4];
+	} s_TTLIOInfo;
+
+	/* Digital I/O infos */
+	struct {
+		BYTE b_DigitalInit;
+		BYTE b_ChannelAMode;
+		BYTE b_ChannelBMode;
+		BYTE b_OutputMemoryEnabled;
+		DWORD dw_OutputMemory;
+	} s_DigitalIOInfo;
+
+      /*********************/
+	/* 82X54 timer infos */
+      /*********************/
+
+	struct {
+		struct {
+			BYTE b_82X54Init;
+			BYTE b_InputClockSelection;
+			BYTE b_InputClockLevel;
+			BYTE b_OutputLevel;
+			BYTE b_HardwareGateLevel;
+			DWORD dw_ConfigurationWord;
+		} s_82X54TimerInfo[3];
+		BYTE b_InterruptMask;
+	} s_82X54ModuleInfo;
+
+      /*********************/
+	/* Chronometer infos */
+      /*********************/
+
+	struct {
+		BYTE b_ChronoInit;
+		BYTE b_InterruptMask;
+		BYTE b_PCIInputClock;
+		BYTE b_TimingUnit;
+		BYTE b_CycleMode;
+		double d_TimingInterval;
+		DWORD dw_ConfigReg;
+	} s_ChronoModuleInfo;
+
+      /***********************/
+	/* Pulse encoder infos */
+      /***********************/
+
+	struct {
+		struct {
+			BYTE b_PulseEncoderInit;
+		} s_PulseEncoderInfo[4];
+		DWORD dw_SetRegister;
+		DWORD dw_ControlRegister;
+		DWORD dw_StatusRegister;
+	} s_PulseEncoderModuleInfo;
+
+	/* Tor conter infos */
+	struct {
+		struct {
+			BYTE b_TorCounterInit;
+			BYTE b_TimingUnit;
+			BYTE b_InterruptEnable;
+			double d_TimingInterval;
+			ULONG ul_RealTimingInterval;
+		} s_TorCounterInfo[2];
+		BYTE b_PCIInputClock;
+	} s_TorCounterModuleInfo;
+
+	/* PWM infos */
+	struct {
+		struct {
+			BYTE b_PWMInit;
+			BYTE b_TimingUnit;
+			BYTE b_InterruptEnable;
+			double d_LowTiming;
+			double d_HighTiming;
+			ULONG ul_RealLowTiming;
+			ULONG ul_RealHighTiming;
+		} s_PWMInfo[2];
+		BYTE b_ClockSelection;
+	} s_PWMModuleInfo;
+
+	/* ETM infos */
+	struct {
+		struct {
+			BYTE b_ETMEnable;
+			BYTE b_ETMInterrupt;
+		} s_ETMInfo[2];
+		BYTE b_ETMInit;
+		BYTE b_TimingUnit;
+		BYTE b_ClockSelection;
+		double d_TimingInterval;
+		ULONG ul_Timing;
+	} s_ETMModuleInfo;
+
+	/* CDA infos */
+	struct {
+		BYTE b_CDAEnable;
+		BYTE b_CDAInterrupt;
+		BYTE b_CDAInit;
+		BYTE b_FctSelection;
+		BYTE b_CDAReadFIFOOverflow;
+	} s_CDAModuleInfo;
+
+} str_ModuleInfo;
+
+/* Private structure for the addi_apci3120 driver */
+typedef struct {
+
+	INT iobase;
+	INT i_IobaseAmcc;	// base+size for AMCC chip
+	INT i_IobaseAddon;	//addon base address
+	INT i_IobaseReserved;
+	ULONG_PTR dw_AiBase;
+	struct pcilst_struct *amcc;	// ptr too AMCC data
+	BYTE allocated;		// we have blocked card
+	BYTE b_ValidDriver;	// driver is ok
+	BYTE b_AiContinuous;	// we do unlimited AI
+	BYTE b_AiInitialisation;
+	UINT ui_AiActualScan;	//how many scans we finished
+	UINT ui_AiBufferPtr;	// data buffer ptr in samples
+	UINT ui_AiNbrofChannels;	// how many channels is measured
+	UINT ui_AiScanLength;	// Length of actual scanlist
+	UINT ui_AiActualScanPosition;	// position in actual scan
+	PUINT pui_AiChannelList;	// actual chanlist
+	UINT ui_AiChannelList[32];	// actual chanlist
+	BYTE b_AiChannelConfiguration[32];	// actual chanlist
+	UINT ui_AiReadData[32];
+	DWORD dw_AiInitialised;
+	UINT ui_AiTimer0;	//Timer Constant for Timer0
+	UINT ui_AiTimer1;	//Timer constant for Timer1
+	UINT ui_AiFlags;
+	UINT ui_AiDataLength;
+	short *AiData;	// Pointer to sample data
+	UINT ui_AiNbrofScans;	// number of scans to do
+	USHORT us_UseDma;	// To use Dma or not
+	BYTE b_DmaDoubleBuffer;	// we can use double buffering
+	UINT ui_DmaActualBuffer;	// which buffer is used now
+	//*UPDATE-0.7.57->0.7.68
+	//ULONG               ul_DmaBufferVirtual[2];// pointers to begin of DMA buffer
+	short *ul_DmaBufferVirtual[2];	// pointers to begin of DMA buffer
+	ULONG ul_DmaBufferHw[2];	// hw address of DMA buff
+	UINT ui_DmaBufferSize[2];	// size of dma buffer in bytes
+	UINT ui_DmaBufferUsesize[2];	// which size we may now used for transfer
+	UINT ui_DmaBufferSamples[2];	// size in samples
+	UINT ui_DmaBufferPages[2];	// number of pages in buffer
+	BYTE b_DigitalOutputRegister;	// Digital Output Register
+	BYTE b_OutputMemoryStatus;
+	BYTE b_AnalogInputChannelNbr;	// Analog input channel Nbr
+	BYTE b_AnalogOutputChannelNbr;	// Analog input Output  Nbr
+	BYTE b_TimerSelectMode;	// Contain data written at iobase + 0C
+	BYTE b_ModeSelectRegister;	// Contain data written at iobase + 0E
+	USHORT us_OutputRegister;	// Contain data written at iobase + 0
+	BYTE b_InterruptState;
+	BYTE b_TimerInit;	// Specify if InitTimerWatchdog was load
+	BYTE b_TimerStarted;	// Specify if timer 2 is running or not
+	BYTE b_Timer2Mode;	// Specify the timer 2 mode
+	BYTE b_Timer2Interrupt;	//Timer2  interrupt enable or disable
+	BYTE b_AiCyclicAcquisition;	// indicate cyclic acquisition
+	BYTE b_InterruptMode;	// eoc eos or dma
+	BYTE b_EocEosInterrupt;	// Enable disable eoc eos interrupt
+	UINT ui_EocEosConversionTime;
+	BYTE b_EocEosConversionTimeBase;
+	BYTE b_SingelDiff;
+	BYTE b_ExttrigEnable;	/* To enable or disable external trigger */
+
+	/* Pointer to the current process */
+	struct task_struct *tsk_Current;
+	boardtype *ps_BoardInfo;
+
+	/* Hardware board infos for 1710 */
+	struct {
+		UINT ui_Address;	/* Board address */
+		UINT ui_FlashAddress;
+		BYTE b_InterruptNbr;	/* Board interrupt number */
+		BYTE b_SlotNumber;	/* PCI slot number */
+		BYTE b_BoardVersion;
+		DWORD dw_MolduleConfiguration[4];	/* Module config */
+	} s_BoardInfos;
+
+	/* Interrupt infos */
+	struct {
+		ULONG ul_InterruptOccur;	/* 0   : No interrupt occur */
+						/* > 0 : Interrupt occur */
+		UINT ui_Read;	/* Read FIFO */
+		UINT ui_Write;	/* Write FIFO */
+		struct {
+			BYTE b_OldModuleMask;
+			ULONG ul_OldInterruptMask;	/* Interrupt mask */
+			ULONG ul_OldCounterLatchValue;	/* Interrupt counter value */
+		} s_FIFOInterruptParameters[APCI1710_SAVE_INTERRUPT];
+	} s_InterruptParameters;
+
+	str_ModuleInfo s_ModuleInfo[4];
+	ULONG ul_TTLPortConfiguration[10];
+
+} addi_private;
+
+static unsigned short pci_list_builded;	/* set to 1 when list of card is known */
+
+/* Function declarations */
+static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it);
+static int i_ADDI_Detach(struct comedi_device *dev);
+static int i_ADDI_Reset(struct comedi_device *dev);
+
+static irqreturn_t v_ADDI_Interrupt(int irq, void *d PT_REGS_ARG);
+static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);

+ 1158 - 0
drivers/staging/comedi/drivers/addi-data/addi_eeprom.c

@@ -0,0 +1,1158 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project   : ADDI DATA         | Compiler : GCC 			              |
+  | Modulname : addi_eeprom.c     | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
+  +-----------------------------------------------------------------------+
+  | Description : ADDI EEPROM  Module                                     |
+  +-----------------------------------------------------------------------+
+  |                             UPDATE'S                                  |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          | 		 | 						  |
+  |          |           | 						  |
+  +----------+-----------+------------------------------------------------+
+*/
+
+#define NVCMD_BEGIN_READ 	(0x7 << 5 )	// nvRam begin read command
+#define NVCMD_LOAD_LOW   	(0x4 << 5 )	// nvRam load low command
+#define NVCMD_LOAD_HIGH  	(0x5 << 5 )	// nvRam load high command
+#define EE76_CMD_LEN    	13	// bits in instructions
+#define EE_READ         	0x0180	// 01 1000 0000 read instruction
+
+#define	WORD				unsigned short
+#define PWORD				unsigned short *
+#define PDWORD				unsigned int  *
+
+#ifndef DWORD
+#define	DWORD				unsigned int
+#endif
+
+#define EEPROM_DIGITALINPUT 			0
+#define EEPROM_DIGITALOUTPUT			1
+#define EEPROM_ANALOGINPUT				2
+#define EEPROM_ANALOGOUTPUT				3
+#define EEPROM_TIMER					4
+#define EEPROM_WATCHDOG					5
+#define EEPROM_TIMER_WATCHDOG_COUNTER	10
+
+struct str_Functionality {
+	BYTE b_Type;
+	WORD w_Address;
+};
+
+typedef struct {
+	WORD w_HeaderSize;
+	BYTE b_Nfunctions;
+	struct str_Functionality s_Functions[7];
+} str_MainHeader;
+
+typedef struct {
+	WORD w_Nchannel;
+	BYTE b_Interruptible;
+	WORD w_NinterruptLogic;
+} str_DigitalInputHeader;
+
+typedef struct {
+	WORD w_Nchannel;
+} str_DigitalOutputHeader;
+
+// used for timer as well as watchdog
+
+typedef struct {
+	WORD w_HeaderSize;
+	BYTE b_Resolution;
+	BYTE b_Mode;		// in case of Watchdog it is functionality
+	WORD w_MinTiming;
+	BYTE b_TimeBase;
+} str_TimerDetails;
+typedef struct {
+
+	WORD w_Ntimer;
+	str_TimerDetails s_TimerDetails[4];	//  supports 4 timers
+} str_TimerMainHeader;
+
+typedef struct {
+	WORD w_Nchannel;
+	BYTE b_Resolution;
+} str_AnalogOutputHeader;
+
+typedef struct {
+	WORD w_Nchannel;
+	WORD w_MinConvertTiming;
+	WORD w_MinDelayTiming;
+	BYTE b_HasDma;
+	BYTE b_Resolution;
+} str_AnalogInputHeader;
+
+		/*****************************************/
+		/*            Read Header Functions              */
+		/*****************************************/
+
+INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, struct comedi_device *dev);
+
+INT i_EepromReadDigitalInputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_DigitalInputHeader * s_Header);
+
+INT i_EepromReadDigitalOutputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_DigitalOutputHeader * s_Header);
+
+INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_TimerMainHeader * s_Header);
+
+INT i_EepromReadAnlogOutputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_AnalogOutputHeader * s_Header);
+
+INT i_EepromReadAnlogInputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_AnalogInputHeader * s_Header);
+
+		/******************************************/
+		/*      Eeprom Specific Functions                         */
+		/******************************************/
+WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation,
+	WORD w_EepromStartAddress);
+void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress);
+void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue);
+void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress);
+void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand,
+	BYTE b_DataLengthInBits);
+void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value);
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : WORD w_EepromReadWord                                  |
+|				(WORD	w_PCIBoardEepromAddress,             		 |
+|				 char *	pc_PCIChipInformation,               		 |
+|				 WORD   w_EepromStartAddress)                		 |
++----------------------------------------------------------------------------+
+| Task              : Read from eepromn a word                               |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|		      WORD w_EepromStartAddress    : Selected eeprom address |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : Read word value from eeprom                            |
++----------------------------------------------------------------------------+
+*/
+
+WORD w_EepromReadWord(WORD w_PCIBoardEepromAddress, char *pc_PCIChipInformation,
+	WORD w_EepromStartAddress)
+{
+
+	BYTE b_Counter = 0;
+
+	BYTE b_ReadByte = 0;
+
+	BYTE b_ReadLowByte = 0;
+
+	BYTE b_ReadHighByte = 0;
+
+	BYTE b_SelectedAddressLow = 0;
+
+	BYTE b_SelectedAddressHigh = 0;
+
+	WORD w_ReadWord = 0;
+
+	/**************************/
+
+	/* Test the PCI chip type */
+
+	/**************************/
+
+	if ((!strcmp(pc_PCIChipInformation, "S5920")) ||
+		(!strcmp(pc_PCIChipInformation, "S5933")))
+	{
+
+		for (b_Counter = 0; b_Counter < 2; b_Counter++)
+		{
+
+			b_SelectedAddressLow = (w_EepromStartAddress + b_Counter) % 256;	//Read the low 8 bit part
+
+			b_SelectedAddressHigh = (w_EepromStartAddress + b_Counter) / 256;	//Read the high 8 bit part
+
+	      /************************************/
+
+			/* Select the load low address mode */
+
+	      /************************************/
+
+			outb(NVCMD_LOAD_LOW, w_PCIBoardEepromAddress + 0x3F);
+
+	      /****************/
+
+			/* Wait on busy */
+
+	      /****************/
+
+			v_EepromWaitBusy(w_PCIBoardEepromAddress);
+
+	      /************************/
+
+			/* Load the low address */
+
+	      /************************/
+
+			outb(b_SelectedAddressLow,
+				w_PCIBoardEepromAddress + 0x3E);
+
+	      /****************/
+
+			/* Wait on busy */
+
+	      /****************/
+
+			v_EepromWaitBusy(w_PCIBoardEepromAddress);
+
+	      /*************************************/
+
+			/* Select the load high address mode */
+
+	      /*************************************/
+
+			outb(NVCMD_LOAD_HIGH, w_PCIBoardEepromAddress + 0x3F);
+
+	      /****************/
+
+			/* Wait on busy */
+
+	      /****************/
+
+			v_EepromWaitBusy(w_PCIBoardEepromAddress);
+
+	      /*************************/
+
+			/* Load the high address */
+
+	      /*************************/
+
+			outb(b_SelectedAddressHigh,
+				w_PCIBoardEepromAddress + 0x3E);
+
+	      /****************/
+
+			/* Wait on busy */
+
+	      /****************/
+
+			v_EepromWaitBusy(w_PCIBoardEepromAddress);
+
+	      /************************/
+
+			/* Select the READ mode */
+
+	      /************************/
+
+			outb(NVCMD_BEGIN_READ, w_PCIBoardEepromAddress + 0x3F);
+
+	      /****************/
+
+			/* Wait on busy */
+
+	      /****************/
+
+			v_EepromWaitBusy(w_PCIBoardEepromAddress);
+
+	      /*****************************/
+
+			/* Read data into the EEPROM */
+
+	      /*****************************/
+
+			b_ReadByte = inb(w_PCIBoardEepromAddress + 0x3E);
+
+	      /****************/
+
+			/* Wait on busy */
+
+	      /****************/
+
+			v_EepromWaitBusy(w_PCIBoardEepromAddress);
+
+	      /*********************************/
+
+			/* Select the upper address part */
+
+	      /*********************************/
+
+			if (b_Counter == 0)
+			{
+
+				b_ReadLowByte = b_ReadByte;
+
+			}	// if(b_Counter==0)
+
+			else
+			{
+
+				b_ReadHighByte = b_ReadByte;
+
+			}	// if(b_Counter==0)
+
+		}		// for (b_Counter=0; b_Counter<2; b_Counter++)
+
+		w_ReadWord = (b_ReadLowByte | (((WORD) b_ReadHighByte) * 256));
+
+	}			// end of if ((!strcmp(pc_PCIChipInformation, "S5920")) || (!strcmp(pc_PCIChipInformation, "S5933")))
+
+	if (!strcmp(pc_PCIChipInformation, "93C76"))
+	{
+
+	   /*************************************/
+
+		/* Read 16 bit from the EEPROM 93C76 */
+
+	   /*************************************/
+
+		v_EepromCs76Read(w_PCIBoardEepromAddress, w_EepromStartAddress,
+			&w_ReadWord);
+
+	}
+
+	return (w_ReadWord);
+
+}
+
+/*
+
++----------------------------------------------------------------------------+
+
+| Function   Name   : void v_EepromWaitBusy                                  |
+
+|			(WORD	w_PCIBoardEepromAddress)                    	 |
+
++----------------------------------------------------------------------------+
+
+| Task              : Wait the busy flag from PCI controller                 |
+
++----------------------------------------------------------------------------+
+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom base address |
+
++----------------------------------------------------------------------------+
+
+| Output Parameters : -                                                      |
+
++----------------------------------------------------------------------------+
+
+| Return Value      : -                                                      |
+
++----------------------------------------------------------------------------+
+
+*/
+
+void v_EepromWaitBusy(WORD w_PCIBoardEepromAddress)
+{
+
+	BYTE b_EepromBusy = 0;
+
+	do
+	{
+
+	   /*************/
+
+		/* IMPORTANT */
+
+	   /*************/
+
+	   /************************************************************************/
+
+		/* An error has been written in the AMCC 5933 book at the page B-13 */
+
+		/* Ex: if you read a byte and look for the busy statusEEPROM=0x80 and   */
+
+		/*      the operator register is AMCC_OP_REG_MCSR+3 */
+
+		/*      WORD read  EEPROM=0x8000 andAMCC_OP_REG_MCSR+2                  */
+
+		/*      DWORD read  EEPROM=0x80000000 and AMCC_OP_REG_MCSR */
+
+	   /************************************************************************/
+
+		b_EepromBusy = inb(w_PCIBoardEepromAddress + 0x3F);
+		b_EepromBusy = b_EepromBusy & 0x80;
+
+	}
+	while (b_EepromBusy == 0x80);
+
+}
+
+/*
+
++---------------------------------------------------------------------------------+
+
+| Function   Name   : void v_EepromClock76(DWORD dw_Address,                      |
+
+|					   DWORD dw_RegisterValue)                 			  |
+
++---------------------------------------------------------------------------------+
+
+| Task              : This function sends the clocking sequence to the EEPROM.    |
+
++---------------------------------------------------------------------------------+
+
+| Input Parameters  : DWORD dw_Address : PCI eeprom base address                  |
+
+|		      DWORD dw_RegisterValue : PCI eeprom register value to write.|
+
++---------------------------------------------------------------------------------+
+
+| Output Parameters : -                                                           |
+
++---------------------------------------------------------------------------------+
+
+| Return Value      : -                                                           |
+
++---------------------------------------------------------------------------------+
+
+*/
+
+void v_EepromClock76(DWORD dw_Address, DWORD dw_RegisterValue)
+{
+
+   /************************/
+
+	/* Set EEPROM clock Low */
+
+   /************************/
+
+	outl(dw_RegisterValue & 0x6, dw_Address);
+
+   /***************/
+
+	/* Wait 0.1 ms */
+
+   /***************/
+
+	udelay(100);
+
+   /*************************/
+
+	/* Set EEPROM clock High */
+
+   /*************************/
+
+	outl(dw_RegisterValue | 0x1, dw_Address);
+
+   /***************/
+
+	/* Wait 0.1 ms */
+
+   /***************/
+
+	udelay(100);
+
+}
+
+/*
+
++---------------------------------------------------------------------------------+
+
+| Function   Name   : void v_EepromSendCommand76(DWORD dw_Address,                |
+
+|					   DWORD   dw_EepromCommand,                		  |
+
+|					   BYTE    b_DataLengthInBits)                        |
+
++---------------------------------------------------------------------------------+
+
+| Task              : This function sends a Command to the EEPROM 93C76.          |
+
++---------------------------------------------------------------------------------+
+
+| Input Parameters  : DWORD dw_Address : PCI eeprom base address                  |
+
+|		      DWORD dw_EepromCommand : PCI eeprom command to write.       |
+
+|		      BYTE  b_DataLengthInBits : PCI eeprom command data length.  |
+
++---------------------------------------------------------------------------------+
+
+| Output Parameters : -                                                           |
+
++---------------------------------------------------------------------------------+
+
+| Return Value      : -                                                           |
+
++---------------------------------------------------------------------------------+
+
+*/
+
+void v_EepromSendCommand76(DWORD dw_Address, DWORD dw_EepromCommand,
+	BYTE b_DataLengthInBits)
+{
+
+	char c_BitPos = 0;
+
+	DWORD dw_RegisterValue = 0;
+
+   /*****************************/
+
+	/* Enable EEPROM Chip Select */
+
+   /*****************************/
+
+	dw_RegisterValue = 0x2;
+
+   /********************************************************************/
+
+	/* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
+
+   /********************************************************************/
+
+	outl(dw_RegisterValue, dw_Address);
+
+   /***************/
+
+	/* Wait 0.1 ms */
+
+   /***************/
+
+	udelay(100);
+
+   /*******************************************/
+
+	/* Send EEPROM command - one bit at a time */
+
+   /*******************************************/
+
+	for (c_BitPos = (b_DataLengthInBits - 1); c_BitPos >= 0; c_BitPos--)
+	{
+
+      /**********************************/
+
+		/* Check if current bit is 0 or 1 */
+
+      /**********************************/
+
+		if (dw_EepromCommand & (1 << c_BitPos))
+		{
+
+	 /***********/
+
+			/* Write 1 */
+
+	 /***********/
+
+			dw_RegisterValue = dw_RegisterValue | 0x4;
+
+		}
+
+		else
+		{
+
+	 /***********/
+
+			/* Write 0 */
+
+	 /***********/
+
+			dw_RegisterValue = dw_RegisterValue & 0x3;
+
+		}
+
+      /*********************/
+
+		/* Write the command */
+
+      /*********************/
+
+		outl(dw_RegisterValue, dw_Address);
+
+      /***************/
+
+		/* Wait 0.1 ms */
+
+      /***************/
+
+		udelay(100);
+
+      /****************************/
+
+		/* Trigger the EEPROM clock */
+
+      /****************************/
+
+		v_EepromClock76(dw_Address, dw_RegisterValue);
+
+	}
+
+}
+
+/*
+
++---------------------------------------------------------------------------------+
+
+| Function   Name   : void v_EepromCs76Read(DWORD dw_Address,                     |
+
+|					   WORD    w_offset,                      			  |
+
+|					   PWORD   pw_Value)                      			  |
+
++---------------------------------------------------------------------------------+
+
+| Task              : This function read a value from the EEPROM 93C76.           |
+
++---------------------------------------------------------------------------------+
+
+| Input Parameters  : DWORD dw_Address : PCI eeprom base address                  |
+
+|		      WORD    w_offset : Offset of the adress to read             |
+
+|		      PWORD   pw_Value : PCI eeprom 16 bit read value.            |
+
++---------------------------------------------------------------------------------+
+
+| Output Parameters : -                                                           |
+
++---------------------------------------------------------------------------------+
+
+| Return Value      : -                                                           |
+
++---------------------------------------------------------------------------------+
+
+*/
+
+void v_EepromCs76Read(DWORD dw_Address, WORD w_offset, PWORD pw_Value)
+{
+
+        char c_BitPos = 0;
+
+	DWORD dw_RegisterValue = 0;
+
+	DWORD dw_RegisterValueRead = 0;
+
+   /*************************************************/
+
+	/* Send EEPROM read command and offset to EEPROM */
+
+   /*************************************************/
+
+	v_EepromSendCommand76(dw_Address, (EE_READ << 4) | (w_offset / 2),
+		EE76_CMD_LEN);
+
+   /*******************************/
+
+	/* Get the last register value */
+
+   /*******************************/
+
+	dw_RegisterValue = (((w_offset / 2) & 0x1) << 2) | 0x2;
+
+   /*****************************/
+
+	/* Set the 16-bit value of 0 */
+
+   /*****************************/
+
+	*pw_Value = 0;
+
+   /************************/
+
+	/* Get the 16-bit value */
+
+   /************************/
+
+	for (c_BitPos = 0; c_BitPos < 16; c_BitPos++)
+	{
+
+      /****************************/
+
+		/* Trigger the EEPROM clock */
+
+      /****************************/
+
+		v_EepromClock76(dw_Address, dw_RegisterValue);
+
+      /**********************/
+
+		/* Get the result bit */
+
+      /**********************/
+
+		dw_RegisterValueRead = inl(dw_Address);
+
+      /***************/
+
+		/* Wait 0.1 ms */
+
+      /***************/
+
+		udelay(100);
+
+      /***************************************/
+
+		/* Get bit value and shift into result */
+
+      /***************************************/
+
+		if (dw_RegisterValueRead & 0x8)
+		{
+
+	 /**********/
+
+			/* Read 1 */
+
+	 /**********/
+
+			*pw_Value = (*pw_Value << 1) | 0x1;
+
+		}
+
+		else
+		{
+
+	 /**********/
+
+			/* Read 0 */
+
+	 /**********/
+
+			*pw_Value = (*pw_Value << 1);
+
+		}
+
+	}
+
+   /*************************/
+
+	/* Clear all EEPROM bits */
+
+   /*************************/
+
+	dw_RegisterValue = 0x0;
+
+   /********************************************************************/
+
+	/* Toggle EEPROM's Chip select to get it out of Shift Register Mode */
+
+   /********************************************************************/
+
+	outl(dw_RegisterValue, dw_Address);
+
+   /***************/
+
+	/* Wait 0.1 ms */
+
+   /***************/
+
+	udelay(100);
+
+}
+
+	/******************************************/
+	/*      EEPROM HEADER READ FUNCTIONS      */
+	/******************************************/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name  : INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress,  |
+|				char *	pc_PCIChipInformation,struct comedi_device *dev)    |
++----------------------------------------------------------------------------+
+| Task              : Read from eeprom Main Header                           |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|			  struct comedi_device *dev		   : comedi device structure |
+|											 pointer				 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0							                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_EepromReadMainHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, struct comedi_device *dev)
+{
+	WORD w_Temp, i, w_Count = 0;
+	UINT ui_Temp;
+	str_MainHeader s_MainHeader;
+	str_DigitalInputHeader s_DigitalInputHeader;
+	str_DigitalOutputHeader s_DigitalOutputHeader;
+	//str_TimerMainHeader     s_TimerMainHeader,s_WatchdogMainHeader;
+	str_AnalogOutputHeader s_AnalogOutputHeader;
+	str_AnalogInputHeader s_AnalogInputHeader;
+
+	// Read size
+	s_MainHeader.w_HeaderSize =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + 8);
+
+	// Read nbr of functionality
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + 10);
+	s_MainHeader.b_Nfunctions = (BYTE) w_Temp & 0x00FF;
+
+	// Read functionality details
+	for (i = 0; i < s_MainHeader.b_Nfunctions; i++) {
+		// Read Type
+		w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+			pc_PCIChipInformation, 0x100 + 12 + w_Count);
+		s_MainHeader.s_Functions[i].b_Type = (BYTE) w_Temp & 0x3F;
+		w_Count = w_Count + 2;
+		//Read Address
+		s_MainHeader.s_Functions[i].w_Address =
+			w_EepromReadWord(w_PCIBoardEepromAddress,
+			pc_PCIChipInformation, 0x100 + 12 + w_Count);
+		w_Count = w_Count + 2;
+	}
+
+	// Display main header info
+	for (i = 0; i < s_MainHeader.b_Nfunctions; i++) {
+
+		switch (s_MainHeader.s_Functions[i].b_Type) {
+		case EEPROM_DIGITALINPUT:
+			i_EepromReadDigitalInputHeader(w_PCIBoardEepromAddress,
+				pc_PCIChipInformation,
+				s_MainHeader.s_Functions[i].w_Address,
+				&s_DigitalInputHeader);
+			this_board->i_NbrDiChannel =
+				s_DigitalInputHeader.w_Nchannel;
+			break;
+
+		case EEPROM_DIGITALOUTPUT:
+			i_EepromReadDigitalOutputHeader(w_PCIBoardEepromAddress,
+				pc_PCIChipInformation,
+				s_MainHeader.s_Functions[i].w_Address,
+				&s_DigitalOutputHeader);
+			this_board->i_NbrDoChannel =
+				s_DigitalOutputHeader.w_Nchannel;
+			ui_Temp = 0xffffffff;
+			this_board->i_DoMaxdata =
+				ui_Temp >> (32 - this_board->i_NbrDoChannel);
+			break;
+
+		case EEPROM_ANALOGINPUT:
+			i_EepromReadAnlogInputHeader(w_PCIBoardEepromAddress,
+				pc_PCIChipInformation,
+				s_MainHeader.s_Functions[i].w_Address,
+				&s_AnalogInputHeader);
+			if (!(strcmp(this_board->pc_DriverName, "apci3200")))
+				this_board->i_NbrAiChannel =
+					s_AnalogInputHeader.w_Nchannel * 4;
+			else
+				this_board->i_NbrAiChannel =
+					s_AnalogInputHeader.w_Nchannel;
+			this_board->i_Dma = s_AnalogInputHeader.b_HasDma;
+			this_board->ui_MinAcquisitiontimeNs =
+				(UINT) s_AnalogInputHeader.w_MinConvertTiming *
+				1000;
+			this_board->ui_MinDelaytimeNs =
+				(UINT) s_AnalogInputHeader.w_MinDelayTiming *
+				1000;
+			ui_Temp = 0xffff;
+			this_board->i_AiMaxdata =
+				ui_Temp >> (16 -
+				s_AnalogInputHeader.b_Resolution);
+			break;
+
+		case EEPROM_ANALOGOUTPUT:
+			i_EepromReadAnlogOutputHeader(w_PCIBoardEepromAddress,
+				pc_PCIChipInformation,
+				s_MainHeader.s_Functions[i].w_Address,
+				&s_AnalogOutputHeader);
+			this_board->i_NbrAoChannel =
+				s_AnalogOutputHeader.w_Nchannel;
+			ui_Temp = 0xffff;
+			this_board->i_AoMaxdata =
+				ui_Temp >> (16 -
+				s_AnalogOutputHeader.b_Resolution);
+			break;
+
+		case EEPROM_TIMER:
+			this_board->i_Timer = 1;	//Timer subdevice present
+			break;
+
+		case EEPROM_WATCHDOG:
+			this_board->i_Timer = 1;	//Timer subdevice present
+			break;
+
+		case EEPROM_TIMER_WATCHDOG_COUNTER:
+			this_board->i_Timer = 1;	//Timer subdevice present
+		}
+	}
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name  : INT i_EepromReadDigitalInputHeader(WORD 					 |
+|			w_PCIBoardEepromAddress,char *pc_PCIChipInformation,	 |
+|			WORD w_Address,str_DigitalInputHeader *s_Header)		 |
+|																	 |
++----------------------------------------------------------------------------+
+| Task              : Read Digital Input Header                              |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|			 str_DigitalInputHeader *s_Header: Digita Input Header   |
+|												   Pointer			 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0							                             |
++----------------------------------------------------------------------------+
+*/
+INT i_EepromReadDigitalInputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_DigitalInputHeader * s_Header)
+{
+	WORD w_Temp;
+
+	// read nbr of channels
+	s_Header->w_Nchannel =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + w_Address + 6);
+
+	// interruptible or not
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + w_Address + 8);
+	s_Header->b_Interruptible = (BYTE) (w_Temp >> 7) & 0x01;
+
+// How many interruptible logic
+	s_Header->w_NinterruptLogic =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + w_Address + 10);
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name  : INT i_EepromReadDigitalOutputHeader(WORD 				 |
+|			w_PCIBoardEepromAddress,char *pc_PCIChipInformation,	 |
+|			WORD w_Address,str_DigitalOutputHeader *s_Header)	     |
+|																	 |
++----------------------------------------------------------------------------+
+| Task              : Read Digital Output Header                             |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|			 str_DigitalOutputHeader *s_Header: Digital Output Header|
+|											   Pointer				 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0							                             |
++----------------------------------------------------------------------------+
+*/
+INT i_EepromReadDigitalOutputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_DigitalOutputHeader * s_Header)
+{
+// Read Nbr channels
+	s_Header->w_Nchannel =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + w_Address + 6);
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name  : INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress, |
+|			char *pc_PCIChipInformation,WORD w_Address,				 |
+|			str_TimerMainHeader *s_Header)							 |
++----------------------------------------------------------------------------+
+| Task              : Read Timer or Watchdog Header                          |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|			 str_TimerMainHeader *s_Header: Timer Header			 |
+|											   Pointer				 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0							                             |
++----------------------------------------------------------------------------+
+*/
+INT i_EepromReadTimerHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_TimerMainHeader * s_Header)
+{
+
+	WORD i, w_Size = 0, w_Temp;
+
+//Read No of Timer
+	s_Header->w_Ntimer =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + w_Address + 6);
+//Read header size
+
+	for (i = 0; i < s_Header->w_Ntimer; i++) {
+		s_Header->s_TimerDetails[i].w_HeaderSize =
+			w_EepromReadWord(w_PCIBoardEepromAddress,
+			pc_PCIChipInformation,
+			0x100 + w_Address + 8 + w_Size + 0);
+		w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+			pc_PCIChipInformation,
+			0x100 + w_Address + 8 + w_Size + 2);
+
+		//Read Resolution
+		s_Header->s_TimerDetails[i].b_Resolution =
+			(BYTE) (w_Temp >> 10) & 0x3F;
+
+		//Read Mode
+		s_Header->s_TimerDetails[i].b_Mode =
+			(BYTE) (w_Temp >> 4) & 0x3F;
+
+		w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+			pc_PCIChipInformation,
+			0x100 + w_Address + 8 + w_Size + 4);
+
+		//Read MinTiming
+		s_Header->s_TimerDetails[i].w_MinTiming = (w_Temp >> 6) & 0x3FF;
+
+		//Read Timebase
+		s_Header->s_TimerDetails[i].b_TimeBase = (BYTE) (w_Temp) & 0x3F;
+		w_Size += s_Header->s_TimerDetails[i].w_HeaderSize;
+	}
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name  : INT i_EepromReadAnlogOutputHeader(WORD 					 |
+|			w_PCIBoardEepromAddress,char *pc_PCIChipInformation,	 |
+|			WORD w_Address,str_AnalogOutputHeader *s_Header)         |
++----------------------------------------------------------------------------+
+| Task              : Read Nalog Output  Header                              |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|			 str_AnalogOutputHeader *s_Header:Anlog Output Header    |
+|											   Pointer				 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0							                             |
++----------------------------------------------------------------------------+
+*/
+
+INT i_EepromReadAnlogOutputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_AnalogOutputHeader * s_Header)
+{
+	WORD w_Temp;
+	// No of channels for 1st hard component
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + w_Address + 10);
+	s_Header->w_Nchannel = (w_Temp >> 4) & 0x03FF;
+	// Resolution for 1st hard component
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + w_Address + 16);
+	s_Header->b_Resolution = (BYTE) (w_Temp >> 8) & 0xFF;
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name  : INT i_EepromReadAnlogInputHeader(WORD 					 |
+|			w_PCIBoardEepromAddress,char *pc_PCIChipInformation,     |
+|			WORD w_Address,str_AnalogInputHeader *s_Header)          |
++----------------------------------------------------------------------------+
+| Task              : Read Nalog Output  Header                              |
++----------------------------------------------------------------------------+
+| Input Parameters  : WORD w_PCIBoardEepromAddress : PCI eeprom address      |
+|																	 |
+|		      char *pc_PCIChipInformation  : PCI Chip Type.          |
+|																	 |
+|			 str_AnalogInputHeader *s_Header:Anlog Input Header      |
+|											   Pointer				 |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0							                             |
++----------------------------------------------------------------------------+
+*/
+
+// Reads only for ONE  hardware component
+INT i_EepromReadAnlogInputHeader(WORD w_PCIBoardEepromAddress,
+	char *pc_PCIChipInformation, WORD w_Address,
+	str_AnalogInputHeader * s_Header)
+{
+	WORD w_Temp, w_Offset;
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + w_Address + 10);
+	s_Header->w_Nchannel = (w_Temp >> 4) & 0x03FF;
+	s_Header->w_MinConvertTiming =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + w_Address + 16);
+	s_Header->w_MinDelayTiming =
+		w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation,
+		0x100 + w_Address + 30);
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + w_Address + 20);
+	s_Header->b_HasDma = (w_Temp >> 13) & 0x01;	// whether dma present or not
+
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 72);	// reading Y
+	w_Temp = w_Temp & 0x00FF;
+	if (w_Temp)		//Y>0
+	{
+		w_Offset = 74 + (2 * w_Temp) + (10 * (1 + (w_Temp / 16)));	// offset of first analog input single header
+		w_Offset = w_Offset + 2;	// resolution
+	} else			//Y=0
+	{
+		w_Offset = 74;
+		w_Offset = w_Offset + 2;	// resolution
+	}
+
+// read Resolution
+	w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress,
+		pc_PCIChipInformation, 0x100 + w_Address + w_Offset);
+	s_Header->b_Resolution = w_Temp & 0x001F;	// last 5 bits
+
+	return 0;
+}

+ 457 - 0
drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h

@@ -0,0 +1,457 @@
+/*
+	Modified by umesh on 16th may 2001
+	Modified by sarath on 22nd may 2001
+*/
+
+/*
+    comedi/drivers/amcc_s5933_v_58.h
+
+    Stuff for AMCC S5933 PCI Controller
+
+    Author: Michal Dobes <majkl@tesnet.cz>
+
+    Inspirated from general-purpose AMCC S5933 PCI Matchmaker driver
+    made by Andrea Cisternino  <acister@pcape1.pi.infn.it>
+    and as result of espionage from MITE code made by David A. Schleef.
+    Thanks to AMCC for their on-line documentation and bus master DMA
+    example.
+*/
+
+#ifndef _AMCC_S5933_H_
+#define _AMCC_S5933_H_
+
+#include <linux/pci.h>
+#include "../../comedidev.h"
+
+#ifdef PCI_SUPPORT_VER1
+#error    Sorry, no support for 2.1.55 and older! :-((((
+#endif
+
+/***********Added by sarath for compatibility with APCI3120
+
+*************************/
+
+#define FIFO_ADVANCE_ON_BYTE_2     0x20000000	// written on base0
+
+#define AMWEN_ENABLE                     0x02	// added for step 6 dma written on base2
+#define A2P_FIFO_WRITE_ENABLE            0x01
+
+#define AGCSTS_TC_ENABLE		   0x10000000	// Added for transfer count enable bit
+
+//  ADDON RELATED ADDITIONS
+// Constant
+#define     APCI3120_ENABLE_TRANSFER_ADD_ON_LOW       0x00
+#define     APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH      0x1200
+#define     APCI3120_A2P_FIFO_MANAGEMENT              0x04000400L
+#define     APCI3120_AMWEN_ENABLE                     0x02
+#define     APCI3120_A2P_FIFO_WRITE_ENABLE            0x01
+#define     APCI3120_FIFO_ADVANCE_ON_BYTE_2           0x20000000L
+#define     APCI3120_ENABLE_WRITE_TC_INT              0x00004000L
+#define     APCI3120_CLEAR_WRITE_TC_INT               0x00040000L
+#define     APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0
+#define     APCI3120_DISABLE_BUS_MASTER_ADD_ON        0x0
+#define     APCI3120_DISABLE_BUS_MASTER_PCI           0x0
+
+ // ADD_ON ::: this needed since apci supports 16 bit interface to add on
+#define     APCI3120_ADD_ON_AGCSTS_LOW       0x3C
+#define     APCI3120_ADD_ON_AGCSTS_HIGH      APCI3120_ADD_ON_AGCSTS_LOW + 2
+#define     APCI3120_ADD_ON_MWAR_LOW         0x24
+#define     APCI3120_ADD_ON_MWAR_HIGH        APCI3120_ADD_ON_MWAR_LOW + 2
+#define     APCI3120_ADD_ON_MWTC_LOW         0x058
+#define     APCI3120_ADD_ON_MWTC_HIGH        APCI3120_ADD_ON_MWTC_LOW + 2
+
+// AMCC
+#define     APCI3120_AMCC_OP_MCSR            0x3C
+#define     APCI3120_AMCC_OP_REG_INTCSR      0x38
+
+/*******from here all upward definitions are added by sarath */
+
+/****************************************************************************/
+/* AMCC Operation Register Offsets - PCI                                    */
+/****************************************************************************/
+
+#define AMCC_OP_REG_OMB1         0x00
+#define AMCC_OP_REG_OMB2         0x04
+#define AMCC_OP_REG_OMB3         0x08
+#define AMCC_OP_REG_OMB4         0x0c
+#define AMCC_OP_REG_IMB1         0x10
+#define AMCC_OP_REG_IMB2         0x14
+#define AMCC_OP_REG_IMB3         0x18
+#define AMCC_OP_REG_IMB4         0x1c
+#define AMCC_OP_REG_FIFO         0x20
+#define AMCC_OP_REG_MWAR         0x24
+#define AMCC_OP_REG_MWTC         0x28
+#define AMCC_OP_REG_MRAR         0x2c
+#define AMCC_OP_REG_MRTC         0x30
+#define AMCC_OP_REG_MBEF         0x34
+#define AMCC_OP_REG_INTCSR       0x38
+#define  AMCC_OP_REG_INTCSR_SRC  (AMCC_OP_REG_INTCSR + 2)	/* INT source */
+#define  AMCC_OP_REG_INTCSR_FEC  (AMCC_OP_REG_INTCSR + 3)	/* FIFO ctrl */
+#define AMCC_OP_REG_MCSR         0x3c
+#define  AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2)	/* Data in byte 2 */
+#define  AMCC_OP_REG_MCSR_NVCMD  (AMCC_OP_REG_MCSR + 3)	/* Command in byte 3 */
+
+#define AMCC_FIFO_DEPTH_DWORD	8
+#define AMCC_FIFO_DEPTH_BYTES	(8 * sizeof (u32))
+
+/****************************************************************************/
+/* AMCC Operation Registers Size - PCI                                      */
+/****************************************************************************/
+
+#define AMCC_OP_REG_SIZE	 64	/* in bytes */
+
+/****************************************************************************/
+/* AMCC Operation Register Offsets - Add-on                                 */
+/****************************************************************************/
+
+#define AMCC_OP_REG_AIMB1         0x00
+#define AMCC_OP_REG_AIMB2         0x04
+#define AMCC_OP_REG_AIMB3         0x08
+#define AMCC_OP_REG_AIMB4         0x0c
+#define AMCC_OP_REG_AOMB1         0x10
+#define AMCC_OP_REG_AOMB2         0x14
+#define AMCC_OP_REG_AOMB3         0x18
+#define AMCC_OP_REG_AOMB4         0x1c
+#define AMCC_OP_REG_AFIFO         0x20
+#define AMCC_OP_REG_AMWAR         0x24
+#define AMCC_OP_REG_APTA          0x28
+#define AMCC_OP_REG_APTD          0x2c
+#define AMCC_OP_REG_AMRAR         0x30
+#define AMCC_OP_REG_AMBEF         0x34
+#define AMCC_OP_REG_AINT          0x38
+#define AMCC_OP_REG_AGCSTS        0x3c
+#define AMCC_OP_REG_AMWTC         0x58
+#define AMCC_OP_REG_AMRTC         0x5c
+
+/****************************************************************************/
+/* AMCC - Add-on General Control/Status Register                            */
+/****************************************************************************/
+
+#define AGCSTS_CONTROL_MASK	0xfffff000
+#define  AGCSTS_NV_ACC_MASK	0xe0000000
+#define  AGCSTS_RESET_MASK	0x0e000000
+#define  AGCSTS_NV_DA_MASK	0x00ff0000
+#define  AGCSTS_BIST_MASK	0x0000f000
+#define AGCSTS_STATUS_MASK	0x000000ff
+#define  AGCSTS_TCZERO_MASK	0x000000c0
+#define  AGCSTS_FIFO_ST_MASK	0x0000003f
+
+#define AGCSTS_RESET_MBFLAGS	0x08000000
+#define AGCSTS_RESET_P2A_FIFO	0x04000000
+#define AGCSTS_RESET_A2P_FIFO	0x02000000
+#define AGCSTS_RESET_FIFOS	(AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO)
+
+#define AGCSTS_A2P_TCOUNT	0x00000080
+#define AGCSTS_P2A_TCOUNT	0x00000040
+
+#define AGCSTS_FS_P2A_EMPTY	0x00000020
+#define AGCSTS_FS_P2A_HALF	0x00000010
+#define AGCSTS_FS_P2A_FULL	0x00000008
+
+#define AGCSTS_FS_A2P_EMPTY	0x00000004
+#define AGCSTS_FS_A2P_HALF	0x00000002
+#define AGCSTS_FS_A2P_FULL	0x00000001
+
+/****************************************************************************/
+/* AMCC - Add-on Interrupt Control/Status Register                            */
+/****************************************************************************/
+
+#define AINT_INT_MASK		0x00ff0000
+#define AINT_SEL_MASK		0x0000ffff
+#define  AINT_IS_ENSEL_MASK	0x00001f1f
+
+#define AINT_INT_ASSERTED	0x00800000
+#define AINT_BM_ERROR		0x00200000
+#define AINT_BIST_INT		0x00100000
+
+#define AINT_RT_COMPLETE	0x00080000
+#define AINT_WT_COMPLETE	0x00040000
+
+#define AINT_OUT_MB_INT		0x00020000
+#define AINT_IN_MB_INT		0x00010000
+
+#define AINT_READ_COMPL		0x00008000
+#define AINT_WRITE_COMPL	0x00004000
+
+#define AINT_OMB_ENABLE 	0x00001000
+#define AINT_OMB_SELECT 	0x00000c00
+#define AINT_OMB_BYTE		0x00000300
+
+#define AINT_IMB_ENABLE 	0x00000010
+#define AINT_IMB_SELECT 	0x0000000c
+#define AINT_IMB_BYTE		0x00000003
+
+/* Enable Bus Mastering */
+#define EN_A2P_TRANSFERS	0x00000400
+/* FIFO Flag Reset */
+#define RESET_A2P_FLAGS		0x04000000L
+/* FIFO Relative Priority */
+#define A2P_HI_PRIORITY		0x00000100L
+/* Identify Interrupt Sources */
+#define ANY_S593X_INT		0x00800000L
+#define READ_TC_INT		0x00080000L
+#define WRITE_TC_INT		0x00040000L
+#define IN_MB_INT		0x00020000L
+#define MASTER_ABORT_INT	0x00100000L
+#define TARGET_ABORT_INT	0x00200000L
+#define BUS_MASTER_INT		0x00200000L
+
+/****************************************************************************/
+
+struct pcilst_struct {
+	struct pcilst_struct *next;
+	int used;
+	struct pci_dev *pcidev;
+	unsigned short vendor;
+	unsigned short device;
+	unsigned int master;
+	unsigned char pci_bus;
+	unsigned char pci_slot;
+	unsigned char pci_func;
+	unsigned int io_addr[5];
+	unsigned int irq;
+};
+
+struct pcilst_struct *amcc_devices;	// ptr to root list of all amcc devices
+
+/****************************************************************************/
+
+void v_pci_card_list_init(unsigned short pci_vendor, char display);
+void v_pci_card_list_cleanup(unsigned short pci_vendor);
+struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id,
+						       unsigned short
+						       device_id);
+int i_find_free_pci_card_by_position(unsigned short vendor_id,
+				     unsigned short device_id,
+				     unsigned short pci_bus,
+				     unsigned short pci_slot,
+				     struct pcilst_struct **card);
+struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id,
+						    unsigned short device_id,
+						    unsigned short pci_bus,
+						    unsigned short pci_slot);
+
+int i_pci_card_alloc(struct pcilst_struct *amcc);
+int i_pci_card_free(struct pcilst_struct *amcc);
+void v_pci_card_list_display(void);
+int i_pci_card_data(struct pcilst_struct *amcc,
+		    unsigned char *pci_bus, unsigned char *pci_slot,
+		    unsigned char *pci_func, unsigned short *io_addr,
+		    unsigned short *irq, unsigned short *master);
+
+/****************************************************************************/
+
+/* build list of amcc cards in this system */
+void v_pci_card_list_init(unsigned short pci_vendor, char display)
+{
+	struct pci_dev *pcidev;
+	struct pcilst_struct *amcc, *last;
+	int i;
+
+	amcc_devices = NULL;
+	last = NULL;
+
+	pci_for_each_dev(pcidev) {
+		if (pcidev->vendor == pci_vendor) {
+			amcc = kmalloc(sizeof(*amcc), GFP_KERNEL);
+			memset(amcc, 0, sizeof(*amcc));
+
+			amcc->pcidev = pcidev;
+			if (last) {
+				last->next = amcc;
+			} else {
+				amcc_devices = amcc;
+			}
+			last = amcc;
+
+			amcc->vendor = pcidev->vendor;
+			amcc->device = pcidev->device;
+#if 0
+			amcc->master = pcidev->master;	// how get this information under 2.4 kernels?
+#endif
+			amcc->pci_bus = pcidev->bus->number;
+			amcc->pci_slot = PCI_SLOT(pcidev->devfn);
+			amcc->pci_func = PCI_FUNC(pcidev->devfn);
+			for (i = 0; i < 5; i++)
+				amcc->io_addr[i] =
+				    pcidev->resource[i].start & ~3UL;
+			amcc->irq = pcidev->irq;
+		}
+	}
+
+	if (display)
+		v_pci_card_list_display();
+}
+
+/****************************************************************************/
+/* free up list of amcc cards in this system */
+void v_pci_card_list_cleanup(unsigned short pci_vendor)
+{
+	struct pcilst_struct *amcc, *next;
+
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		kfree(amcc);
+	}
+
+	amcc_devices = NULL;
+}
+
+/****************************************************************************/
+/* find first unused card with this device_id */
+struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id,
+						       unsigned short device_id)
+{
+	struct pcilst_struct *amcc, *next;
+
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		if ((!amcc->used) && (amcc->device == device_id)
+		    && (amcc->vendor == vendor_id))
+			return amcc;
+
+	}
+
+	return NULL;
+}
+
+/****************************************************************************/
+/* find card on requested position */
+int i_find_free_pci_card_by_position(unsigned short vendor_id,
+				     unsigned short device_id,
+				     unsigned short pci_bus,
+				     unsigned short pci_slot,
+				     struct pcilst_struct **card)
+{
+	struct pcilst_struct *amcc, *next;
+
+	*card = NULL;
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		if ((amcc->vendor == vendor_id) && (amcc->device == device_id)
+		    && (amcc->pci_bus == pci_bus)
+		    && (amcc->pci_slot == pci_slot)) {
+			if (!(amcc->used)) {
+				*card = amcc;
+				return 0;	// ok, card is found
+			} else {
+				rt_printk
+				    (" - \nCard on requested position is used b:s %d:%d!\n",
+				     pci_bus, pci_slot);
+				return 2;	// card exist but is used
+			}
+		}
+	}
+
+	return 1;		// no card found
+}
+
+/****************************************************************************/
+/* mark card as used */
+int i_pci_card_alloc(struct pcilst_struct *amcc)
+{
+	if (!amcc)
+		return -1;
+
+	if (amcc->used)
+		return 1;
+	amcc->used = 1;
+	return 0;
+}
+
+/****************************************************************************/
+/* mark card as free */
+int i_pci_card_free(struct pcilst_struct *amcc)
+{
+	if (!amcc)
+		return -1;
+
+	if (!amcc->used)
+		return 1;
+	amcc->used = 0;
+	return 0;
+}
+
+/****************************************************************************/
+/* display list of found cards */
+void v_pci_card_list_display(void)
+{
+	struct pcilst_struct *amcc, *next;
+
+	printk("List of pci cards\n");
+	printk("bus:slot:func vendor device master io_amcc io_daq irq used\n");
+
+	for (amcc = amcc_devices; amcc; amcc = next) {
+		next = amcc->next;
+		printk
+		    ("%2d   %2d   %2d  0x%4x 0x%4x   %3s   0x%4x 0x%4x  %2d  %2d\n",
+		     amcc->pci_bus, amcc->pci_slot, amcc->pci_func,
+		     amcc->vendor, amcc->device, amcc->master ? "yes" : "no",
+		     amcc->io_addr[0], amcc->io_addr[2], amcc->irq, amcc->used);
+
+	}
+}
+
+/****************************************************************************/
+/* return all card information for driver */
+int i_pci_card_data(struct pcilst_struct *amcc,
+		    unsigned char *pci_bus, unsigned char *pci_slot,
+		    unsigned char *pci_func, unsigned short *io_addr,
+		    unsigned short *irq, unsigned short *master)
+{
+	int i;
+
+	if (!amcc)
+		return -1;
+	*pci_bus = amcc->pci_bus;
+	*pci_slot = amcc->pci_slot;
+	*pci_func = amcc->pci_func;
+	for (i = 0; i < 5; i++)
+		io_addr[i] = amcc->io_addr[i];
+	*irq = amcc->irq;
+	*master = amcc->master;
+	return 0;
+}
+
+/****************************************************************************/
+/* select and alloc card */
+struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id,
+						    unsigned short device_id,
+						    unsigned short pci_bus,
+						    unsigned short pci_slot)
+{
+	struct pcilst_struct *card;
+
+	if ((pci_bus < 1) & (pci_slot < 1)) {	// use autodetection
+		if ((card = ptr_find_free_pci_card_by_device(vendor_id,
+							     device_id)) ==
+		    NULL) {
+			rt_printk(" - Unused card not found in system!\n");
+			return NULL;
+		}
+	} else {
+		switch (i_find_free_pci_card_by_position(vendor_id, device_id,
+							 pci_bus, pci_slot,
+							 &card)) {
+		case 1:
+			rt_printk
+			    (" - Card not found on requested position b:s %d:%d!\n",
+			     pci_bus, pci_slot);
+			return NULL;
+		case 2:
+			rt_printk
+			    (" - Card on requested position is used b:s %d:%d!\n",
+			     pci_bus, pci_slot);
+			return NULL;
+		}
+	}
+
+	if (i_pci_card_alloc(card) != 0) {
+		rt_printk(" - Can't allocate card!\n");
+		return NULL;
+	}
+
+	return card;
+}
+
+#endif

+ 1265 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c

@@ -0,0 +1,1265 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-1710       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci1710.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-1710                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+#include "hwdrv_APCI1710.h"
+#include "APCI1710_Inp_cpt.c"
+
+#include "APCI1710_Ssi.c"
+#include "APCI1710_Tor.c"
+#include "APCI1710_Ttl.c"
+#include "APCI1710_Dig_io.c"
+#include "APCI1710_82x54.c"
+#include "APCI1710_Chrono.c"
+#include "APCI1710_Pwm.c"
+#include "APCI1710_INCCPT.c"
+
+void i_ADDI_AttachPCI1710(struct comedi_device * dev)
+{
+	struct comedi_subdevice *s;
+	int ret = 0;
+	int n_subdevices = 9;
+
+	//Update-0.7.57->0.7.68dev->n_subdevices = 9;
+	if ((ret = alloc_subdevices(dev, n_subdevices)) < 0)
+		return;
+
+	// Allocate and Initialise Timer Subdevice Structures
+	s = dev->subdevices + 0;
+
+	s->type = COMEDI_SUBD_TIMER;
+	s->subdev_flags = SDF_WRITEABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 3;
+	s->maxdata = 0;
+	s->len_chanlist = 3;
+	s->range_table = &range_digital;
+	s->insn_write = i_APCI1710_InsnWriteEnableDisableTimer;
+	s->insn_read = i_APCI1710_InsnReadAllTimerValue;
+	s->insn_config = i_APCI1710_InsnConfigInitTimer;
+	s->insn_bits = i_APCI1710_InsnBitsTimer;
+
+	// Allocate and Initialise DIO Subdevice Structures
+	s = dev->subdevices + 1;
+
+	s->type = COMEDI_SUBD_DIO;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 7;
+	s->maxdata = 1;
+	s->len_chanlist = 7;
+	s->range_table = &range_digital;
+	s->insn_config = i_APCI1710_InsnConfigDigitalIO;
+	s->insn_read = i_APCI1710_InsnReadDigitalIOChlValue;
+	s->insn_bits = i_APCI1710_InsnBitsDigitalIOPortOnOff;
+	s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff;
+
+	// Allocate and Initialise Chrono Subdevice Structures
+	s = dev->subdevices + 2;
+
+	s->type = COMEDI_SUBD_CHRONO;
+	s->subdev_flags = SDF_WRITEABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 4;
+	s->maxdata = 0;
+	s->len_chanlist = 4;
+	s->range_table = &range_digital;
+	s->insn_write = i_APCI1710_InsnWriteEnableDisableChrono;
+	s->insn_read = i_APCI1710_InsnReadChrono;
+	s->insn_config = i_APCI1710_InsnConfigInitChrono;
+	s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO;
+
+	// Allocate and Initialise PWM Subdevice Structures
+	s = dev->subdevices + 3;
+	s->type = COMEDI_SUBD_PWM;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 3;
+	s->maxdata = 1;
+	s->len_chanlist = 3;
+	s->range_table = &range_digital;
+	s->io_bits = 0;		//all bits input
+	s->insn_config = i_APCI1710_InsnConfigPWM;
+	s->insn_read = i_APCI1710_InsnReadGetPWMStatus;
+	s->insn_write = i_APCI1710_InsnWritePWM;
+	s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt;
+
+	// Allocate and Initialise TTLIO Subdevice Structures
+	s = dev->subdevices + 4;
+	s->type = COMEDI_SUBD_TTLIO;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->len_chanlist = 8;
+	s->range_table = &range_apci1710_ttl;	// to pass arguments in range
+	s->insn_config = i_APCI1710_InsnConfigInitTTLIO;
+	s->insn_bits = i_APCI1710_InsnBitsReadTTLIO;
+	s->insn_write = i_APCI1710_InsnWriteSetTTLIOChlOnOff;
+	s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue;
+
+	// Allocate and Initialise TOR Subdevice Structures
+	s = dev->subdevices + 5;
+	s->type = COMEDI_SUBD_TOR;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 8;
+	s->maxdata = 1;
+	s->len_chanlist = 8;
+	s->range_table = &range_digital;
+	s->io_bits = 0;		//all bits input
+	s->insn_config = i_APCI1710_InsnConfigInitTorCounter;
+	s->insn_read = i_APCI1710_InsnReadGetTorCounterInitialisation;
+	s->insn_write = i_APCI1710_InsnWriteEnableDisableTorCounter;
+	s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue;
+
+	// Allocate and Initialise SSI Subdevice Structures
+	s = dev->subdevices + 6;
+	s->type = COMEDI_SUBD_SSI;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 4;
+	s->maxdata = 1;
+	s->len_chanlist = 4;
+	s->range_table = &range_apci1710_ssi;
+	s->insn_config = i_APCI1710_InsnConfigInitSSI;
+	s->insn_read = i_APCI1710_InsnReadSSIValue;
+	s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO;
+
+	// Allocate and Initialise PULSEENCODER Subdevice Structures
+	s = dev->subdevices + 7;
+	s->type = COMEDI_SUBD_PULSEENCODER;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 4;
+	s->maxdata = 1;
+	s->len_chanlist = 4;
+	s->range_table = &range_digital;
+	s->insn_config = i_APCI1710_InsnConfigInitPulseEncoder;
+	s->insn_write = i_APCI1710_InsnWriteEnableDisablePulseEncoder;
+	s->insn_bits = i_APCI1710_InsnBitsReadWritePulseEncoder;
+	s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder;
+
+	// Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures
+	s = dev->subdevices + 8;
+	s->type = COMEDI_SUBD_INCREMENTALCOUNTER;
+	s->subdev_flags =
+		SDF_WRITEABLE | SDF_READABLE | SDF_RT | SDF_GROUND | SDF_COMMON;
+	s->n_chan = 500;
+	s->maxdata = 1;
+	s->len_chanlist = 500;
+	s->range_table = &range_apci1710_inccpt;
+	s->insn_config = i_APCI1710_InsnConfigINCCPT;
+	s->insn_write = i_APCI1710_InsnWriteINCCPT;
+	s->insn_read = i_APCI1710_InsnReadINCCPT;
+	s->insn_bits = i_APCI1710_InsnBitsINCCPT;
+}
+
+int i_APCI1710_Reset(struct comedi_device * dev);
+void v_APCI1710_Interrupt(int irq, void *d);
+//for 1710
+
+int i_APCI1710_Reset(struct comedi_device * dev)
+{
+	int ret;
+	DWORD dw_Dummy;
+
+	/*********************************/
+	/* Read all module configuration */
+	/*********************************/
+	ret = inl(devpriv->s_BoardInfos.ui_Address + 60);
+	devpriv->s_BoardInfos.dw_MolduleConfiguration[0] = ret;
+
+	ret = inl(devpriv->s_BoardInfos.ui_Address + 124);
+	devpriv->s_BoardInfos.dw_MolduleConfiguration[1] = ret;
+
+	ret = inl(devpriv->s_BoardInfos.ui_Address + 188);
+	devpriv->s_BoardInfos.dw_MolduleConfiguration[2] = ret;
+
+	ret = inl(devpriv->s_BoardInfos.ui_Address + 252);
+	devpriv->s_BoardInfos.dw_MolduleConfiguration[3] = ret;
+
+	// outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60);
+	outl(0x83838383, devpriv->s_BoardInfos.ui_Address + 0x60);
+
+	devpriv->s_BoardInfos.b_BoardVersion = 1;
+
+	// Enable the interrupt for the controler
+	dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38);
+	outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38);
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function's Name   : __void__ v_APCI1710_InterruptFunction                  |
+|				(BYTE b_Interrupt, __CPPARGS)                |
++----------------------------------------------------------------------------+
+| Task              : APCI-1710 interrupt function                           |
++----------------------------------------------------------------------------+
+| Input Parameters  : BYTE b_Interrupt : Interrupt number                    |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0 : OK                                                 |
+|                    -1 : Error                                              |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI1710_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	BYTE b_ModuleCpt = 0;
+	BYTE b_InterruptFlag = 0;
+	BYTE b_PWMCpt = 0;
+	BYTE b_TorCounterCpt = 0;
+	BYTE b_PulseIncoderCpt = 0;
+	UINT ui_16BitValue;
+	ULONG ul_InterruptLatchReg = 0;
+	ULONG ul_LatchRegisterValue = 0;
+	ULONG ul_82X54InterruptStatus;
+	ULONG ul_StatusRegister;
+
+	str_ModuleInfo *ps_ModuleInfo;
+
+	printk("APCI1710 Interrupt\n");
+	for (b_ModuleCpt = 0; b_ModuleCpt < 4; b_ModuleCpt++, ps_ModuleInfo++) {
+
+		 /**************************/
+		/* 1199/0225 to 0100/0226 */
+		 /**************************/
+		ps_ModuleInfo = &devpriv->s_ModuleInfo[b_ModuleCpt];
+
+		 /***********************/
+		/* Test if 82X54 timer */
+		 /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_82X54_TIMER) {
+
+			//printk("TIMER Interrupt Occurred\n");
+			ul_82X54InterruptStatus = inl(devpriv->s_BoardInfos.
+				ui_Address + 12 + (64 * b_ModuleCpt));
+
+		    /***************************/
+			/* Test if interrupt occur */
+		    /***************************/
+
+			if ((ul_82X54InterruptStatus & ps_ModuleInfo->
+					s_82X54ModuleInfo.
+					b_InterruptMask) != 0) {
+				devpriv->
+					s_InterruptParameters.
+					s_FIFOInterruptParameters[devpriv->
+					s_InterruptParameters.
+					ui_Write].
+					ul_OldInterruptMask =
+					(ul_82X54InterruptStatus &
+					ps_ModuleInfo->s_82X54ModuleInfo.
+					b_InterruptMask) << 4;
+
+				devpriv->
+					s_InterruptParameters.
+					s_FIFOInterruptParameters[devpriv->
+					s_InterruptParameters.
+					ui_Write].
+					b_OldModuleMask = 1 << b_ModuleCpt;
+
+				devpriv->
+					s_InterruptParameters.
+					s_FIFOInterruptParameters[devpriv->
+					s_InterruptParameters.
+					ui_Write].ul_OldCounterLatchValue = 0;
+
+				devpriv->
+					s_InterruptParameters.
+					ul_InterruptOccur++;
+
+		       /****************************/
+				/* Increment the write FIFO */
+		       /****************************/
+
+				devpriv->
+					s_InterruptParameters.
+					ui_Write = (devpriv->
+					s_InterruptParameters.
+					ui_Write + 1) % APCI1710_SAVE_INTERRUPT;
+
+				b_InterruptFlag = 1;
+
+			     /**********************/
+				/* Call user function */
+			     /**********************/
+				//Send a signal to from kernel to user space
+				send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+			}	// if ((ul_82X54InterruptStatus & 0x7) != 0)
+		}		// 82X54 timer
+
+		 /***************************/
+		/* Test if increm. counter */
+		 /***************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
+
+			ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
+				ui_Address + (64 * b_ModuleCpt));
+
+		    /*********************/
+			/* Test if interrupt */
+		    /*********************/
+
+			if ((ul_InterruptLatchReg & 0x22) && (ps_ModuleInfo->
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister2 & 0x80)) {
+		       /************************************/
+				/* Test if strobe latch I interrupt */
+		       /************************************/
+
+				if (ul_InterruptLatchReg & 2) {
+					ul_LatchRegisterValue =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 4 +
+						(64 * b_ModuleCpt));
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].ul_OldInterruptMask =
+						1UL;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].b_OldModuleMask =
+						1 << b_ModuleCpt;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].
+						ul_OldCounterLatchValue =
+						ul_LatchRegisterValue;
+
+					devpriv->
+						s_InterruptParameters.
+						ul_InterruptOccur++;
+
+			  /****************************/
+					/* 0899/0224 to 1199/0225   */
+			  /****************************/
+					/* Increment the write FIFO */
+		      /****************************/
+
+					devpriv->
+						s_InterruptParameters.
+						ui_Write = (devpriv->
+						s_InterruptParameters.
+						ui_Write +
+						1) % APCI1710_SAVE_INTERRUPT;
+
+					b_InterruptFlag = 1;
+
+				/**********************/
+					/* Call user function */
+				/**********************/
+					//Send a signal to from kernel to user space
+					send_sig(SIGIO, devpriv->tsk_Current,
+						0);
+
+				}
+
+		       /*************************************/
+				/* Test if strobe latch II interrupt */
+		       /*************************************/
+
+				if (ul_InterruptLatchReg & 0x20) {
+
+					ul_LatchRegisterValue =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 8 +
+						(64 * b_ModuleCpt));
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].ul_OldInterruptMask =
+						2UL;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].b_OldModuleMask =
+						1 << b_ModuleCpt;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].
+						ul_OldCounterLatchValue =
+						ul_LatchRegisterValue;
+
+					devpriv->
+						s_InterruptParameters.
+						ul_InterruptOccur++;
+
+			  /****************************/
+					/* 0899/0224 to 1199/0225   */
+			  /****************************/
+					/* Increment the write FIFO */
+			  /****************************/
+
+					devpriv->
+						s_InterruptParameters.
+						ui_Write = (devpriv->
+						s_InterruptParameters.
+						ui_Write +
+						1) % APCI1710_SAVE_INTERRUPT;
+
+					b_InterruptFlag = 1;
+
+			    /**********************/
+					/* Call user function */
+				/**********************/
+					//Send a signal to from kernel to user space
+					send_sig(SIGIO, devpriv->tsk_Current,
+						0);
+
+				}
+			}
+
+			ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
+				ui_Address + 24 + (64 * b_ModuleCpt));
+
+		    /***************************/
+			/* Test if index interrupt */
+		    /***************************/
+
+			if (ul_InterruptLatchReg & 0x8) {
+				ps_ModuleInfo->
+					s_SiemensCounterInfo.
+					s_InitFlag.b_IndexInterruptOccur = 1;
+
+				if (ps_ModuleInfo->
+					s_SiemensCounterInfo.
+					s_ModeRegister.
+					s_ByteModeRegister.
+					b_ModeRegister2 &
+					APCI1710_INDEX_AUTO_MODE) {
+
+					outl(ps_ModuleInfo->
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						dw_ModeRegister1_2_3_4,
+						devpriv->s_BoardInfos.
+						ui_Address + 20 +
+						(64 * b_ModuleCpt));
+				}
+
+		       /*****************************/
+				/* Test if interrupt enabled */
+		       /*****************************/
+
+				if ((ps_ModuleInfo->
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister3 &
+						APCI1710_ENABLE_INDEX_INT) ==
+					APCI1710_ENABLE_INDEX_INT) {
+					devpriv->s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].ul_OldInterruptMask =
+						4UL;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].b_OldModuleMask =
+						1 << b_ModuleCpt;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].
+						ul_OldCounterLatchValue =
+						ul_LatchRegisterValue;
+
+					devpriv->
+						s_InterruptParameters.
+						ul_InterruptOccur++;
+
+			  /****************************/
+					/* 0899/0224 to 1199/0225   */
+			  /****************************/
+					/* Increment the write FIFO */
+			  /****************************/
+
+					devpriv->
+						s_InterruptParameters.
+						ui_Write = (devpriv->
+						s_InterruptParameters.
+						ui_Write +
+						1) % APCI1710_SAVE_INTERRUPT;
+
+					b_InterruptFlag = 1;
+
+				/**********************/
+					/* Call user function */
+				/**********************/
+					//Send a signal to from kernel to user space
+					send_sig(SIGIO, devpriv->tsk_Current,
+						0);
+
+				}
+			}
+
+		    /*****************************/
+			/* Test if compare interrupt */
+		    /*****************************/
+
+			if (ul_InterruptLatchReg & 0x10) {
+		       /*****************************/
+				/* Test if interrupt enabled */
+		       /*****************************/
+
+				if ((ps_ModuleInfo->
+						s_SiemensCounterInfo.
+						s_ModeRegister.
+						s_ByteModeRegister.
+						b_ModeRegister3 &
+						APCI1710_ENABLE_COMPARE_INT) ==
+					APCI1710_ENABLE_COMPARE_INT) {
+					devpriv->s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].ul_OldInterruptMask =
+						8UL;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].b_OldModuleMask =
+						1 << b_ModuleCpt;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].
+						ul_OldCounterLatchValue =
+						ul_LatchRegisterValue;
+
+					devpriv->
+						s_InterruptParameters.
+						ul_InterruptOccur++;
+
+			  /****************************/
+					/* 0899/0224 to 1199/0225   */
+			  /****************************/
+					/* Increment the write FIFO */
+		      /****************************/
+
+					devpriv->
+						s_InterruptParameters.
+						ui_Write = (devpriv->
+						s_InterruptParameters.
+						ui_Write +
+						1) % APCI1710_SAVE_INTERRUPT;
+
+					b_InterruptFlag = 1;
+
+				/**********************/
+					/* Call user function */
+				/**********************/
+					//Send a signal to from kernel to user space
+					send_sig(SIGIO, devpriv->tsk_Current,
+						0);
+
+				}
+			}
+
+		    /*******************************************/
+			/* Test if frequency measurement interrupt */
+		    /*******************************************/
+
+			if (ul_InterruptLatchReg & 0x20) {
+		       /*******************/
+				/* Read the status */
+		       /*******************/
+
+				ul_StatusRegister = inl(devpriv->s_BoardInfos.
+					ui_Address + 32 + (64 * b_ModuleCpt));
+
+		       /******************/
+				/* Read the value */
+		       /******************/
+
+				ul_LatchRegisterValue =
+					inl(devpriv->s_BoardInfos.ui_Address +
+					28 + (64 * b_ModuleCpt));
+
+				switch ((ul_StatusRegister >> 1) & 3) {
+				case 0:
+			       /*************************/
+					/* Test the counter mode */
+			       /*************************/
+
+					if ((devpriv->s_ModuleInfo[b_ModuleCpt].
+							s_SiemensCounterInfo.
+							s_ModeRegister.
+							s_ByteModeRegister.
+							b_ModeRegister1 &
+							APCI1710_16BIT_COUNTER)
+						== APCI1710_16BIT_COUNTER) {
+				  /****************************************/
+						/* Test if 16-bit counter 1 pulse occur */
+				  /****************************************/
+
+						if ((ul_LatchRegisterValue &
+								0xFFFFU) != 0) {
+							ui_16BitValue =
+								(UINT)
+								ul_LatchRegisterValue
+								& 0xFFFFU;
+							ul_LatchRegisterValue =
+								(ul_LatchRegisterValue
+								& 0xFFFF0000UL)
+								| (0xFFFFU -
+								ui_16BitValue);
+						}
+
+				  /****************************************/
+						/* Test if 16-bit counter 2 pulse occur */
+				  /****************************************/
+
+						if ((ul_LatchRegisterValue &
+								0xFFFF0000UL) !=
+							0) {
+							ui_16BitValue =
+								(UINT) (
+								(ul_LatchRegisterValue
+									>> 16) &
+								0xFFFFU);
+							ul_LatchRegisterValue =
+								(ul_LatchRegisterValue
+								& 0xFFFFUL) |
+								((0xFFFFU -
+									ui_16BitValue)
+								<< 16);
+						}
+					} else {
+						if (ul_LatchRegisterValue != 0) {
+							ul_LatchRegisterValue =
+								0xFFFFFFFFUL -
+								ul_LatchRegisterValue;
+						}
+					}
+					break;
+
+				case 1:
+			       /****************************************/
+					/* Test if 16-bit counter 2 pulse occur */
+			       /****************************************/
+
+					if ((ul_LatchRegisterValue &
+							0xFFFF0000UL) != 0) {
+						ui_16BitValue =
+							(UINT) (
+							(ul_LatchRegisterValue
+								>> 16) &
+							0xFFFFU);
+						ul_LatchRegisterValue =
+							(ul_LatchRegisterValue &
+							0xFFFFUL) | ((0xFFFFU -
+								ui_16BitValue)
+							<< 16);
+					}
+					break;
+
+				case 2:
+			       /****************************************/
+					/* Test if 16-bit counter 1 pulse occur */
+			       /****************************************/
+
+					if ((ul_LatchRegisterValue & 0xFFFFU) !=
+						0) {
+						ui_16BitValue =
+							(UINT)
+							ul_LatchRegisterValue &
+							0xFFFFU;
+						ul_LatchRegisterValue =
+							(ul_LatchRegisterValue &
+							0xFFFF0000UL) | (0xFFFFU
+							- ui_16BitValue);
+					}
+					break;
+				}
+
+				devpriv->
+					s_InterruptParameters.
+					s_FIFOInterruptParameters[devpriv->
+					s_InterruptParameters.
+					ui_Write].
+					ul_OldInterruptMask = 0x10000UL;
+
+				devpriv->
+					s_InterruptParameters.
+					s_FIFOInterruptParameters[devpriv->
+					s_InterruptParameters.
+					ui_Write].
+					b_OldModuleMask = 1 << b_ModuleCpt;
+
+				devpriv->
+					s_InterruptParameters.
+					s_FIFOInterruptParameters[devpriv->
+					s_InterruptParameters.
+					ui_Write].
+					ul_OldCounterLatchValue =
+					ul_LatchRegisterValue;
+
+				devpriv->
+					s_InterruptParameters.
+					ul_InterruptOccur++;
+
+		       /****************************/
+				/* 0899/0224 to 1199/0225   */
+		       /****************************/
+				/* Increment the write FIFO */
+		       /****************************/
+
+				devpriv->
+					s_InterruptParameters.
+					ui_Write = (devpriv->
+					s_InterruptParameters.
+					ui_Write + 1) % APCI1710_SAVE_INTERRUPT;
+
+				b_InterruptFlag = 1;
+
+			     /**********************/
+				/* Call user function */
+			     /**********************/
+				//Send a signal to from kernel to user space
+				send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+			}
+		}		// Incremental counter
+
+		 /***************/
+		/* Test if CDA */
+		 /***************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_CDA) {
+		    /******************************************/
+			/* Test if CDA enable and functionality 0 */
+		    /******************************************/
+
+			if ((devpriv->s_ModuleInfo[b_ModuleCpt].
+					s_CDAModuleInfo.
+					b_CDAEnable == APCI1710_ENABLE)
+				&& (devpriv->s_ModuleInfo[b_ModuleCpt].
+					s_CDAModuleInfo.b_FctSelection == 0)) {
+		       /****************************/
+				/* Get the interrupt status */
+		       /****************************/
+
+				ul_StatusRegister = inl(devpriv->s_BoardInfos.
+					ui_Address + 16 + (64 * b_ModuleCpt));
+		       /***************************/
+				/* Test if interrupt occur */
+		       /***************************/
+
+				if (ul_StatusRegister & 1) {
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].ul_OldInterruptMask =
+						0x80000UL;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].b_OldModuleMask =
+						1 << b_ModuleCpt;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].
+						ul_OldCounterLatchValue = 0;
+
+					devpriv->
+						s_InterruptParameters.
+						ul_InterruptOccur++;
+
+			  /****************************/
+					/* Increment the write FIFO */
+			  /****************************/
+
+					devpriv->
+						s_InterruptParameters.
+						ui_Write = (devpriv->
+						s_InterruptParameters.
+						ui_Write +
+						1) % APCI1710_SAVE_INTERRUPT;
+
+					b_InterruptFlag = 1;
+
+				/**********************/
+					/* Call user function */
+				/**********************/
+
+					//Send a signal to from kernel to user space
+					send_sig(SIGIO, devpriv->tsk_Current,
+						0);
+
+				}	// if (ul_StatusRegister & 1)
+
+			}
+		}		// CDA
+
+		 /***********************/
+		/* Test if PWM counter */
+		 /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_PWM) {
+			for (b_PWMCpt = 0; b_PWMCpt < 2; b_PWMCpt++) {
+		       /*************************************/
+				/* Test if PWM interrupt initialised */
+		       /*************************************/
+
+				if (devpriv->
+					s_ModuleInfo[b_ModuleCpt].
+					s_PWMModuleInfo.
+					s_PWMInfo[b_PWMCpt].
+					b_InterruptEnable == APCI1710_ENABLE) {
+			  /*****************************/
+					/* Read the interrupt status */
+			  /*****************************/
+
+					ul_StatusRegister =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 16 +
+						(20 * b_PWMCpt) +
+						(64 * b_ModuleCpt));
+
+			  /***************************/
+					/* Test if interrupt occur */
+			  /***************************/
+
+					if (ul_StatusRegister & 0x1) {
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							ul_OldInterruptMask =
+							0x4000UL << b_PWMCpt;
+
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							b_OldModuleMask =
+							1 << b_ModuleCpt;
+
+						devpriv->
+							s_InterruptParameters.
+							ul_InterruptOccur++;
+
+			     /****************************/
+						/* Increment the write FIFO */
+			     /****************************/
+
+						devpriv->
+							s_InterruptParameters.
+							ui_Write = (devpriv->
+							s_InterruptParameters.
+							ui_Write +
+							1) %
+							APCI1710_SAVE_INTERRUPT;
+
+						b_InterruptFlag = 1;
+
+				   /**********************/
+						/* Call user function */
+				   /**********************/
+						//Send a signal to from kernel to user space
+						send_sig(SIGIO,
+							devpriv->tsk_Current,
+							0);
+
+					}	// if (ul_StatusRegister & 0x1)
+				}	// if (APCI1710_ENABLE)
+			}	// for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++)
+		}		// PWM counter
+
+		 /***********************/
+		/* Test if tor counter */
+		 /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
+			for (b_TorCounterCpt = 0; b_TorCounterCpt < 2;
+				b_TorCounterCpt++) {
+		       /*************************************/
+				/* Test if tor interrupt initialised */
+		       /*************************************/
+
+				if (devpriv->
+					s_ModuleInfo[b_ModuleCpt].
+					s_TorCounterModuleInfo.
+					s_TorCounterInfo[b_TorCounterCpt].
+					b_InterruptEnable == APCI1710_ENABLE) {
+			  /*****************************/
+					/* Read the interrupt status */
+			  /*****************************/
+
+					ul_StatusRegister =
+						inl(devpriv->s_BoardInfos.
+						ui_Address + 12 +
+						(16 * b_TorCounterCpt) +
+						(64 * b_ModuleCpt));
+
+			  /***************************/
+					/* Test if interrupt occur */
+			  /***************************/
+
+					if (ul_StatusRegister & 0x1) {
+			     /******************************/
+						/* Read the tor counter value */
+			     /******************************/
+
+						ul_LatchRegisterValue =
+							inl(devpriv->
+							s_BoardInfos.
+							ui_Address + 0 +
+							(16 * b_TorCounterCpt) +
+							(64 * b_ModuleCpt));
+
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							ul_OldInterruptMask =
+							0x1000UL <<
+							b_TorCounterCpt;
+
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							b_OldModuleMask =
+							1 << b_ModuleCpt;
+
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							ul_OldCounterLatchValue
+							= ul_LatchRegisterValue;
+
+						devpriv->
+							s_InterruptParameters.
+							ul_InterruptOccur++;
+
+			     /****************************/
+						/* Increment the write FIFO */
+			     /****************************/
+
+						devpriv->
+							s_InterruptParameters.
+							ui_Write = (devpriv->
+							s_InterruptParameters.
+							ui_Write +
+							1) %
+							APCI1710_SAVE_INTERRUPT;
+
+						b_InterruptFlag = 1;
+
+				   /**********************/
+						/* Call user function */
+				   /**********************/
+
+						//Send a signal to from kernel to user space
+						send_sig(SIGIO,
+							devpriv->tsk_Current,
+							0);
+					}	// if (ul_StatusRegister & 0x1)
+				}	// if (APCI1710_ENABLE)
+			}	// for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++)
+		}		// Tor counter
+
+		 /***********************/
+		/* Test if chronometer */
+		 /***********************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
+
+			//printk("APCI1710 Chrono Interrupt\n");
+		    /*****************************/
+			/* Read the interrupt status */
+		    /*****************************/
+
+			ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
+				ui_Address + 12 + (64 * b_ModuleCpt));
+
+		    /***************************/
+			/* Test if interrupt occur */
+		    /***************************/
+
+			if ((ul_InterruptLatchReg & 0x8) == 0x8) {
+		       /****************************/
+				/* Clear the interrupt flag */
+		       /****************************/
+
+				outl(0, devpriv->s_BoardInfos.
+					ui_Address + 32 + (64 * b_ModuleCpt));
+
+		       /***************************/
+				/* Test if continuous mode */
+		       /***************************/
+
+				if (ps_ModuleInfo->
+					s_ChronoModuleInfo.
+					b_CycleMode == APCI1710_ENABLE) {
+			  /********************/
+					/* Clear the status */
+			  /********************/
+
+					outl(0, devpriv->s_BoardInfos.
+						ui_Address + 36 +
+						(64 * b_ModuleCpt));
+				}
+
+		       /*************************/
+				/* Read the timing value */
+		       /*************************/
+
+				ul_LatchRegisterValue =
+					inl(devpriv->s_BoardInfos.ui_Address +
+					4 + (64 * b_ModuleCpt));
+
+		       /*****************************/
+				/* Test if interrupt enabled */
+		       /*****************************/
+
+				if (ps_ModuleInfo->
+					s_ChronoModuleInfo.b_InterruptMask) {
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].ul_OldInterruptMask =
+						0x80;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].b_OldModuleMask =
+						1 << b_ModuleCpt;
+
+					devpriv->
+						s_InterruptParameters.
+						s_FIFOInterruptParameters
+						[devpriv->s_InterruptParameters.
+						ui_Write].
+						ul_OldCounterLatchValue =
+						ul_LatchRegisterValue;
+
+					devpriv->
+						s_InterruptParameters.
+						ul_InterruptOccur++;
+
+			  /****************************/
+					/* Increment the write FIFO */
+		      /****************************/
+
+					devpriv->
+						s_InterruptParameters.
+						ui_Write = (devpriv->
+						s_InterruptParameters.
+						ui_Write +
+						1) % APCI1710_SAVE_INTERRUPT;
+
+					b_InterruptFlag = 1;
+
+				/**********************/
+					/* Call user function */
+				/**********************/
+					//Send a signal to from kernel to user space
+					send_sig(SIGIO, devpriv->tsk_Current,
+						0);
+
+				}
+			}
+		}		// Chronometer
+
+		 /*************************/
+		/* Test if pulse encoder */
+		 /*************************/
+
+		if ((devpriv->s_BoardInfos.
+				dw_MolduleConfiguration[b_ModuleCpt] &
+				0xFFFF0000UL) == APCI1710_PULSE_ENCODER) {
+		    /****************************/
+			/* Read the status register */
+		    /****************************/
+
+			ul_StatusRegister = inl(devpriv->s_BoardInfos.
+				ui_Address + 20 + (64 * b_ModuleCpt));
+
+			if (ul_StatusRegister & 0xF) {
+				for (b_PulseIncoderCpt = 0;
+					b_PulseIncoderCpt < 4;
+					b_PulseIncoderCpt++) {
+			  /*************************************/
+					/* Test if pulse encoder initialised */
+			  /*************************************/
+
+					if ((ps_ModuleInfo->
+							s_PulseEncoderModuleInfo.
+							s_PulseEncoderInfo
+							[b_PulseIncoderCpt].
+							b_PulseEncoderInit == 1)
+						&& (((ps_ModuleInfo->s_PulseEncoderModuleInfo.dw_SetRegister >> b_PulseIncoderCpt) & 1) == 1) && (((ul_StatusRegister >> (b_PulseIncoderCpt)) & 1) == 1)) {
+						devpriv->s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							ul_OldInterruptMask =
+							0x100UL <<
+							b_PulseIncoderCpt;
+
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							b_OldModuleMask =
+							1 << b_ModuleCpt;
+
+						devpriv->
+							s_InterruptParameters.
+							s_FIFOInterruptParameters
+							[devpriv->
+							s_InterruptParameters.
+							ui_Write].
+							ul_OldCounterLatchValue
+							= ul_LatchRegisterValue;
+
+						devpriv->
+							s_InterruptParameters.
+							ul_InterruptOccur++;
+
+			     /****************************/
+						/* 0899/0224 to 1199/0225   */
+			     /****************************/
+						/* Increment the write FIFO */
+			     /****************************/
+
+						devpriv->
+							s_InterruptParameters.
+							ui_Write = (devpriv->
+							s_InterruptParameters.
+							ui_Write +
+							1) %
+							APCI1710_SAVE_INTERRUPT;
+
+						b_InterruptFlag = 1;
+
+				   /**********************/
+						/* Call user function */
+				   /**********************/
+						//Send a signal to from kernel to user space
+						send_sig(SIGIO,
+							devpriv->tsk_Current,
+							0);
+
+					}
+				}
+			}
+		}		//pulse encoder
+
+	}
+	return;
+
+}

+ 71 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#define COMEDI_SUBD_TTLIO		11	/* Digital Input Output But TTL */
+#define COMEDI_SUBD_PWM			12	/* Pulse width Measurement */
+#define COMEDI_SUBD_SSI			13	/* Synchronous serial interface */
+#define COMEDI_SUBD_TOR			14	/* Tor counter */
+#define COMEDI_SUBD_CHRONO		15	/* Chrono meter */
+#define COMEDI_SUBD_PULSEENCODER	16	/* Pulse Encoder INP CPT */
+#define COMEDI_SUBD_INCREMENTALCOUNTER	17	/* Incremental Counter */
+
+#define APCI1710_BOARD_NAME		"apci1710"
+#define APCI1710_BOARD_VENDOR_ID	0x10E8
+#define APCI1710_BOARD_DEVICE_ID	0x818F
+#define APCI1710_ADDRESS_RANGE		256
+#define APCI1710_CONFIG_ADDRESS_RANGE	8
+#define APCI1710_INCREMENTAL_COUNTER	0x53430000UL
+#define APCI1710_SSI_COUNTER		0x53490000UL
+#define APCI1710_TTL_IO			0x544C0000UL
+#define APCI1710_DIGITAL_IO		0x44490000UL
+#define APCI1710_82X54_TIMER		0x49430000UL
+#define APCI1710_CHRONOMETER		0x43480000UL
+#define APCI1710_PULSE_ENCODER		0x495A0000UL
+#define APCI1710_TOR_COUNTER		0x544F0000UL
+#define APCI1710_PWM			0x50570000UL
+#define APCI1710_ETM			0x45540000UL
+#define APCI1710_CDA			0x43440000UL
+#define APCI1710_DISABLE		0
+#define APCI1710_ENABLE			1
+#define APCI1710_SYNCHRONOUS_MODE	1
+#define APCI1710_ASYNCHRONOUS_MODE	0
+
+//MODULE INFO STRUCTURE
+
+static const struct comedi_lrange range_apci1710_ttl = { 4, {
+						      BIP_RANGE(10),
+						      BIP_RANGE(5),
+						      BIP_RANGE(2),
+						      BIP_RANGE(1)
+						      }
+};
+
+static const struct comedi_lrange range_apci1710_ssi = { 4, {
+						      BIP_RANGE(10),
+						      BIP_RANGE(5),
+						      BIP_RANGE(2),
+						      BIP_RANGE(1)
+						      }
+};
+
+static const struct comedi_lrange range_apci1710_inccpt = { 4, {
+							 BIP_RANGE(10),
+							 BIP_RANGE(5),
+							 BIP_RANGE(2),
+							 BIP_RANGE(1)
+							 }
+};

+ 600 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c

@@ -0,0 +1,600 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-035        | Compiler   : GCC                      |
+  | Module name : hwdrv_apci035.c | Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-035                     |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci035.h"
+INT i_WatchdogNbr = 0;
+INT i_Temp = 0;
+INT i_Flag = 1;
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI035_ConfigTimerWatchdog                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Timer , Counter or Watchdog             |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[0]            : 0 Configure As Timer      |
+|										   1 Configure As Watchdog   |
+                              data[1]            : Watchdog number
+|					  data[2]            : Time base Unit            |
+|					  data[3]			 : Reload Value			     |
+                              data[4]            : External Trigger          |
+                                                   1:Enable
+                                                   0:Disable
+                              data[5]            :External Trigger Level
+                                                  00 Trigger Disabled
+                                                  01 Trigger Enabled (Low level)
+                                                  10 Trigger Enabled (High Level)
+                                                  11 Trigger Enabled (High/Low level)
+                              data[6]            : External Gate            |
+                                                   1:Enable
+                                                   0:Disable
+                              data[7]            : External Gate level
+                                                  00 Gate Disabled
+                                                  01 Gate Enabled (Low level)
+                                                  10 Gate Enabled (High Level)
+                              data[8]            :Warning Relay
+                                                  1: ENABLE
+                                                  0: DISABLE
+                              data[9]            :Warning Delay available
+                              data[10]           :Warning Relay Time unit
+                              data[11]           :Warning Relay Time Reload value
+                              data[12]           :Reset Relay
+                                                  1 : ENABLE
+                                                  0 : DISABLE
+                              data[13]           :Interrupt
+                                                  1 : ENABLE
+                                                  0 : DISABLE
+
+|
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI035_ConfigTimerWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Status = 0;
+	UINT ui_Command = 0;
+	UINT ui_Mode = 0;
+	i_Temp = 0;
+	devpriv->tsk_Current = current;
+	devpriv->b_TimerSelectMode = data[0];
+	i_WatchdogNbr = data[1];
+	if (data[0] == 0) {
+		ui_Mode = 2;
+	} else {
+		ui_Mode = 0;
+	}
+//ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
+	ui_Command = 0;
+//ui_Command = ui_Command & 0xFFFFF9FEUL;
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	ui_Command = 0;
+	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+/************************/
+/* Set the reload value */
+/************************/
+	outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4);
+/*********************/
+/* Set the time unit */
+/*********************/
+	outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8);
+	if (data[0] == ADDIDATA_TIMER) {
+
+		 /******************************/
+		/* Set the mode :             */
+		/* - Disable the hardware     */
+		/* - Disable the counter mode */
+		/* - Disable the warning      */
+		/* - Disable the reset        */
+		/* - Enable the timer mode    */
+		/* - Set the timer mode       */
+		 /******************************/
+
+		ui_Command =
+			(ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL;
+
+	}			//if (data[0] == ADDIDATA_TIMER)
+	else {
+		if (data[0] == ADDIDATA_WATCHDOG) {
+
+		 /******************************/
+			/* Set the mode :             */
+			/* - Disable the hardware     */
+			/* - Disable the counter mode */
+			/* - Disable the warning      */
+			/* - Disable the reset        */
+			/* - Disable the timer mode   */
+		 /******************************/
+
+			ui_Command = ui_Command & 0xFFF819E2UL;
+
+		} else {
+			printk("\n The parameter for Timer/watchdog selection is in error\n");
+			return -EINVAL;
+		}
+	}
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	ui_Command = 0;
+	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+/********************************/
+/* Disable the hardware trigger */
+/********************************/
+	ui_Command = ui_Command & 0xFFFFF89FUL;
+	if (data[4] == ADDIDATA_ENABLE) {
+    /**********************************/
+		/* Set the hardware trigger level */
+    /**********************************/
+		ui_Command = ui_Command | (data[5] << 5);
+	}
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	ui_Command = 0;
+	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+/*****************************/
+/* Disable the hardware gate */
+/*****************************/
+	ui_Command = ui_Command & 0xFFFFF87FUL;
+	if (data[6] == ADDIDATA_ENABLE) {
+/*******************************/
+/* Set the hardware gate level */
+/*******************************/
+		ui_Command = ui_Command | (data[7] << 7);
+	}
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	ui_Command = 0;
+	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+/*******************************/
+/* Disable the hardware output */
+/*******************************/
+	ui_Command = ui_Command & 0xFFFFF9FBUL;
+/*********************************/
+/* Set the hardware output level */
+/*********************************/
+	ui_Command = ui_Command | (data[8] << 2);
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	if (data[9] == ADDIDATA_ENABLE) {
+   /************************/
+		/* Set the reload value */
+   /************************/
+		outl(data[11],
+			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24);
+   /**********************/
+		/* Set the time unite */
+   /**********************/
+		outl(data[10],
+			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28);
+	}
+
+	ui_Command = 0;
+	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+ /*******************************/
+	/* Disable the hardware output */
+ /*******************************/
+	ui_Command = ui_Command & 0xFFFFF9F7UL;
+   /*********************************/
+	/* Set the hardware output level */
+   /*********************************/
+	ui_Command = ui_Command | (data[12] << 3);
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+ /*************************************/
+ /**  Enable the watchdog interrupt  **/
+ /*************************************/
+	ui_Command = 0;
+	ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+/*******************************/
+/* Set the interrupt selection */
+/*******************************/
+	ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
+
+	ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1);
+	outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI035_StartStopWriteTimerWatchdog              |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Start / Stop The Selected Timer , or Watchdog  |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|					                                                 |
+|					  data[0] : 0 - Stop Selected Timer/Watchdog     |
+|					            1 - Start Selected Timer/Watchdog    |
+|					            2 - Trigger Selected Timer/Watchdog  |
+|					            3 - Stop All Timer/Watchdog          |
+|					            4 - Start All Timer/Watchdog         |
+|					            5 - Trigger All Timer/Watchdog       |
+|					                                                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error			 |
+|					                                                 |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Command = 0;
+	INT i_Count = 0;
+	if (data[0] == 1) {
+		ui_Command =
+			inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	 /**********************/
+		/* Start the hardware */
+	 /**********************/
+		ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL;
+		outl(ui_Command,
+			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	}			// if  (data[0]==1)
+	if (data[0] == 2) {
+		ui_Command =
+			inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	 /***************************/
+		/* Set the trigger command */
+	 /***************************/
+		ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL;
+		outl(ui_Command,
+			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	}
+
+	if (data[0] == 0)	//Stop The Watchdog
+	{
+		//Stop The Watchdog
+		ui_Command = 0;
+		//ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12);
+		//ui_Command = ui_Command & 0xFFFFF9FEUL;
+		outl(ui_Command,
+			devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12);
+	}			//  if (data[1]==0)
+	if (data[0] == 3)	//stop all Watchdogs
+	{
+		ui_Command = 0;
+		for (i_Count = 1; i_Count <= 4; i_Count++) {
+			if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+				ui_Command = 0x2UL;
+			} else {
+				ui_Command = 0x10UL;
+			}
+			i_WatchdogNbr = i_Count;
+			outl(ui_Command,
+				devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
+				0);
+		}
+
+	}
+	if (data[0] == 4)	//start all Watchdogs
+	{
+		ui_Command = 0;
+		for (i_Count = 1; i_Count <= 4; i_Count++) {
+			if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+				ui_Command = 0x1UL;
+			} else {
+				ui_Command = 0x8UL;
+			}
+			i_WatchdogNbr = i_Count;
+			outl(ui_Command,
+				devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
+				0);
+		}
+	}
+	if (data[0] == 5)	//trigger all Watchdogs
+	{
+		ui_Command = 0;
+		for (i_Count = 1; i_Count <= 4; i_Count++) {
+			if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+				ui_Command = 0x4UL;
+			} else {
+				ui_Command = 0x20UL;
+			}
+
+			i_WatchdogNbr = i_Count;
+			outl(ui_Command,
+				devpriv->iobase + ((i_WatchdogNbr - 1) * 32) +
+				0);
+		}
+		i_Temp = 1;
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI035_ReadTimerWatchdog                        |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Selected Timer , Counter or Watchdog          |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|     																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	data[0]            : software trigger status
+              data[1]            : hardware trigger status
+|     				data[2]            : Software clear status
+                        data[3]            : Overflow status
+                     data[4]            : Timer actual value
+
+
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI035_ReadTimerWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Status = 0;	// Status register
+	i_WatchdogNbr = insn->unused[0];
+	      /******************/
+	/* Get the status */
+	      /******************/
+	ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16);
+      /***********************************/
+	/* Get the software trigger status */
+      /***********************************/
+	data[0] = ((ui_Status >> 1) & 1);
+      /***********************************/
+	/* Get the hardware trigger status */
+      /***********************************/
+	data[1] = ((ui_Status >> 2) & 1);
+      /*********************************/
+	/* Get the software clear status */
+      /*********************************/
+	data[2] = ((ui_Status >> 3) & 1);
+      /***************************/
+	/* Get the overflow status */
+      /***************************/
+	data[3] = ((ui_Status >> 0) & 1);
+	if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+		data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);
+
+	}			//  if  (devpriv->b_TimerSelectMode==ADDIDATA_TIMER)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : INT i_APCI035_ConfigAnalogInput                        |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Analog Input Subdevice                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s     : Subdevice Pointer            |
+|                     struct comedi_insn *insn       : Insn Structure Pointer       |
+|                     unsigned int *data          : Data Pointer contains        |
+|                                          configuration parameters as below |
+|                     data[0]                  : Warning delay value
+|                                                                            |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI035_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	devpriv->tsk_Current = current;
+	outl(0x200 | 0, devpriv->iobase + 128 + 0x4);
+	outl(0, devpriv->iobase + 128 + 0);
+/********************************/
+/* Initialise the warning value */
+/********************************/
+	outl(0x300 | 0, devpriv->iobase + 128 + 0x4);
+	outl((data[0] << 8), devpriv->iobase + 128 + 0);
+	outl(0x200000UL, devpriv->iobase + 128 + 12);
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI035_ReadAnalogInput                          |
+|			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+|                     struct comedi_insn *insn,unsigned int *data)                      |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel			         |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To read       |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
+|			          data[0]  : Digital Value Of Input              |
+|			                                                         |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI035_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_CommandRegister = 0;
+/******************/
+/*  Set the start */
+/******************/
+	ui_CommandRegister = 0x80000;
+ /******************************/
+	/* Write the command register */
+ /******************************/
+	outl(ui_CommandRegister, devpriv->iobase + 128 + 8);
+
+/***************************************/
+/* Read the digital value of the input */
+/***************************************/
+	data[0] = inl(devpriv->iobase + 128 + 28);
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   :  int i_APCI035_Reset(struct comedi_device *dev)			     |
+|					                                                         |
++----------------------------------------------------------------------------+
+| Task              :Resets the registers of the card                        |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                                 |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI035_Reset(struct comedi_device * dev)
+{
+	INT i_Count = 0;
+	for (i_Count = 1; i_Count <= 4; i_Count++) {
+		i_WatchdogNbr = i_Count;
+		outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0);	//stop all timers
+	}
+	outl(0x0, devpriv->iobase + 128 + 12);	//Disable the warning delay
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : static void v_APCI035_Interrupt					     |
+|					  (int irq , void *d)      |
++----------------------------------------------------------------------------+
+| Task              : Interrupt processing Routine                           |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq                 : irq number                   |
+|                     void *d                 : void pointer                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+static void v_APCI035_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	UINT ui_StatusRegister1 = 0;
+	UINT ui_StatusRegister2 = 0;
+	UINT ui_ReadCommand = 0;
+	UINT ui_ChannelNumber = 0;
+	UINT ui_DigitalTemperature = 0;
+	if (i_Temp == 1) {
+		i_WatchdogNbr = i_Flag;
+		i_Flag = i_Flag + 1;
+	}
+  /**************************************/
+	/* Read the interrupt status register of temperature Warning */
+  /**************************************/
+	ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16);
+  /**************************************/
+	/* Read the interrupt status register for Watchdog/timer */
+   /**************************************/
+
+	ui_StatusRegister2 =
+		inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20);
+
+	if ((((ui_StatusRegister1) & 0x8) == 0x8))	//Test if warning relay interrupt
+	{
+	/**********************************/
+		/* Disable the temperature warning */
+	/**********************************/
+		ui_ReadCommand = inl(devpriv->iobase + 128 + 12);
+		ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL;
+		outl(ui_ReadCommand, devpriv->iobase + 128 + 12);
+      /***************************/
+		/* Read the channel number */
+      /***************************/
+		ui_ChannelNumber = inl(devpriv->iobase + 128 + 60);
+	/**************************************/
+		/* Read the digital temperature value */
+	/**************************************/
+		ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60);
+		send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+	}			//if (((ui_StatusRegister1 & 0x8) == 0x8))
+
+	else {
+		if ((ui_StatusRegister2 & 0x1) == 0x1) {
+			send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+		}
+	}			//else if (((ui_StatusRegister1 & 0x8) == 0x8))
+
+	return;
+}

+ 123 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h

@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/* Card Specific information */
+#define APCI035_BOARD_VENDOR_ID		0x15B8
+#define APCI035_ADDRESS_RANGE		255
+
+INT i_TW_Number;
+struct {
+	INT i_Gain;
+	INT i_Polarity;
+	INT i_OffsetRange;
+	INT i_Coupling;
+	INT i_SingleDiff;
+	INT i_AutoCalibration;
+	UINT ui_ReloadValue;
+	UINT ui_TimeUnitReloadVal;
+	INT i_Interrupt;
+	INT i_ModuleSelection;
+} Config_Parameters_Main;
+
+/* ANALOG INPUT RANGE */
+struct comedi_lrange range_apci035_ai = { 8, {
+				       BIP_RANGE(10),
+				       BIP_RANGE(5),
+				       BIP_RANGE(2),
+				       BIP_RANGE(1),
+				       UNI_RANGE(10),
+				       UNI_RANGE(5),
+				       UNI_RANGE(2),
+				       UNI_RANGE(1)
+				       }
+};
+
+/* Timer / Watchdog Related Defines */
+#define APCI035_TCW_SYNC_ENABLEDISABLE	0
+#define APCI035_TCW_RELOAD_VALUE	4
+#define APCI035_TCW_TIMEBASE		8
+#define APCI035_TCW_PROG		12
+#define APCI035_TCW_TRIG_STATUS		16
+#define APCI035_TCW_IRQ			20
+#define APCI035_TCW_WARN_TIMEVAL	24
+#define APCI035_TCW_WARN_TIMEBASE	28
+
+#define ADDIDATA_TIMER			0
+/* #define ADDIDATA_WATCHDOG		1 */
+
+#define APCI035_TW1                               0
+#define APCI035_TW2                               32
+#define APCI035_TW3                               64
+#define APCI035_TW4                               96
+
+#define APCI035_AI_OFFSET                        0
+#define APCI035_TEMP                             128
+#define APCI035_ALR_SEQ                          4
+#define APCI035_START_STOP_INDEX                 8
+#define APCI035_ALR_START_STOP                   12
+#define APCI035_ALR_IRQ                          16
+#define APCI035_EOS                              20
+#define APCI035_CHAN_NO                          24
+#define APCI035_CHAN_VAL                         28
+#define APCI035_CONV_TIME_TIME_BASE	36
+#define APCI035_RELOAD_CONV_TIME_VAL	32
+#define APCI035_DELAY_TIME_TIME_BASE	44
+#define APCI035_RELOAD_DELAY_TIME_VAL	40
+#define ENABLE_EXT_TRIG			1
+#define ENABLE_EXT_GATE			2
+#define ENABLE_EXT_TRIG_GATE		3
+
+#define ANALOG_INPUT			0
+#define TEMPERATURE			1
+#define RESISTANCE			2
+
+#define ADDIDATA_GREATER_THAN_TEST	0
+#define ADDIDATA_LESS_THAN_TEST		1
+
+#define APCI035_MAXVOLT                         2.5
+
+#define ADDIDATA_UNIPOLAR                        1
+#define ADDIDATA_BIPOLAR                         2
+
+/* ADDIDATA Enable Disable */
+#define ADDIDATA_ENABLE				1
+#define ADDIDATA_DISABLE			0
+
+/* Hardware Layer functions for Apci035 */
+
+/* TIMER */
+/* timer value is passed as u seconds */
+INT i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int *data);
+
+/* Temperature Related Defines (Analog Input Subdevice) */
+
+INT i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int *data);
+INT i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+
+/* Interrupt */
+static void v_APCI035_Interrupt(int irq, void *d);
+
+/* Reset functions */
+INT i_APCI035_Reset(struct comedi_device *dev);

+ 285 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c

@@ -0,0 +1,285 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-1032       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci1032.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-1032                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci1032.h"
+#include <linux/delay.h>
+//Global variables
+UINT ui_InterruptStatus = 0;
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1032_ConfigDigitalInput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures the digital input Subdevice                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     unsigned int *data         : Data Pointer contains         |
+|                                          configuration parameters as below |
+|                                                                            |
+|			  data[0]            : 1 Enable  Digital Input Interrupt |
+|								   0 Disable Digital Input Interrupt |
+|			  data[1]            : 0 ADDIDATA Interrupt OR LOGIC	 |
+|								 : 1 ADDIDATA Interrupt AND LOGIC    |
+|			  data[2]			 : Interrupt mask for the mode 1	 |
+|			  data[3]			 : Interrupt mask for the mode 2	 |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1032_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_TmpValue;
+
+	ULONG ul_Command1 = 0;
+	ULONG ul_Command2 = 0;
+	devpriv->tsk_Current = current;
+
+  /*******************************/
+	/* Set the digital input logic */
+  /*******************************/
+	if (data[0] == ADDIDATA_ENABLE) {
+		ul_Command1 = ul_Command1 | data[2];
+		ul_Command2 = ul_Command2 | data[3];
+		outl(ul_Command1,
+			devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1);
+		outl(ul_Command2,
+			devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2);
+		if (data[1] == ADDIDATA_OR) {
+			outl(0x4, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
+			ui_TmpValue =
+				inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
+		}		//if (data[1] == ADDIDATA_OR)
+		else {
+			outl(0x6, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
+		}		//else if(data[1] == ADDIDATA_OR)
+	}			// if( data[0] == ADDIDATA_ENABLE)
+	else {
+		ul_Command1 = ul_Command1 & 0xFFFF0000;
+		ul_Command2 = ul_Command2 & 0xFFFF0000;
+		outl(ul_Command1,
+			devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1);
+		outl(ul_Command2,
+			devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2);
+		outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
+	}			//else if  ( data[0] == ADDIDATA_ENABLE)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1032_Read1DigitalInput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the digital input                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|		              UINT ui_Channel : Channel number to read       |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1032_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_TmpValue = 0;
+	UINT ui_Channel;
+	ui_Channel = CR_CHAN(insn->chanspec);
+	if (ui_Channel >= 0 && ui_Channel <= 31) {
+		ui_TmpValue = (UINT) inl(devpriv->iobase + APCI1032_DIGITAL_IP);
+		//  since only 1 channel reqd  to bring it to last bit it is rotated
+		//  8 +(chan - 1) times then ANDed with 1 for last bit.
+		*data = (ui_TmpValue >> ui_Channel) & 0x1;
+	}			//if(ui_Channel >= 0 && ui_Channel <=31)
+	else {
+		//comedi_error(dev," \n chan spec wrong\n");
+		return -EINVAL;	// "sorry channel spec wrong "
+	}			//else if(ui_Channel >= 0 && ui_Channel <=31)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1032_ReadMoreDigitalInput                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                     struct comedi_insn *insn,unsigned int *data)                      |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the Requested digital inputs      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To be Read    |
+|                      UINT *data             : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1032_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_PortValue = data[0];
+	UINT ui_Mask = 0;
+	UINT ui_NoOfChannels;
+
+	ui_NoOfChannels = CR_CHAN(insn->chanspec);
+	if (data[1] == 0) {
+		*data = (UINT) inl(devpriv->iobase + APCI1032_DIGITAL_IP);
+		switch (ui_NoOfChannels) {
+		case 2:
+			ui_Mask = 3;
+			*data = (*data >> (2 * ui_PortValue)) & ui_Mask;
+			break;
+		case 4:
+			ui_Mask = 15;
+			*data = (*data >> (4 * ui_PortValue)) & ui_Mask;
+			break;
+		case 8:
+			ui_Mask = 255;
+			*data = (*data >> (8 * ui_PortValue)) & ui_Mask;
+			break;
+		case 16:
+			ui_Mask = 65535;
+			*data = (*data >> (16 * ui_PortValue)) & ui_Mask;
+			break;
+		case 31:
+			break;
+		default:
+			//comedi_error(dev," \nchan spec wrong\n");
+			return -EINVAL;	// "sorry channel spec wrong "
+			break;
+		}		//switch(ui_NoOfChannels)
+	}			//if(data[1]==0)
+	else {
+		if (data[1] == 1) {
+			*data = ui_InterruptStatus;
+		}		//if(data[1]==1)
+	}			//else if(data[1]==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : static void v_APCI1032_Interrupt					     |
+|					  (int irq , void *d)      |
++----------------------------------------------------------------------------+
+| Task              : Interrupt handler for the interruptible digital inputs |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq                 : irq number                   |
+|                     void *d                 : void pointer                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--						     |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                     |
++----------------------------------------------------------------------------+
+*/
+static void v_APCI1032_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+
+	UINT ui_Temp;
+	//disable the interrupt
+	ui_Temp = inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
+	outl(ui_Temp & APCI1032_DIGITAL_IP_INTERRUPT_DISABLE,
+		devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);
+	ui_InterruptStatus =
+		inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS);
+	ui_InterruptStatus = ui_InterruptStatus & 0X0000FFFF;
+	send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+	outl(ui_Temp, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);	//enable the interrupt
+	return;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1032_Reset(struct comedi_device *dev)               |                                                       |
++----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1032_Reset(struct comedi_device * dev)
+{
+	outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ);	//disable the interrupts
+	inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS);	//Reset the interrupt status register
+	outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1);	//Disable the and/or interrupt
+	outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2);
+	return 0;
+}

+ 63 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h

@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/*********      Definitions for APCI-1032 card  *****/
+
+#define APCI1032_BOARD_VENDOR_ID 0x15B8
+#define APCI1032_ADDRESS_RANGE  20
+//DIGITAL INPUT DEFINE
+
+#define APCI1032_DIGITAL_IP                     0
+#define APCI1032_DIGITAL_IP_INTERRUPT_MODE1     4
+#define APCI1032_DIGITAL_IP_INTERRUPT_MODE2     8
+#define APCI1032_DIGITAL_IP_IRQ                 16
+
+//Digital Input IRQ Function Selection
+#define ADDIDATA_OR                  0
+#define ADDIDATA_AND                 1
+
+//Digital Input Interrupt Status
+#define APCI1032_DIGITAL_IP_INTERRUPT_STATUS    12
+
+//Digital Input Interrupt Enable Disable.
+#define APCI1032_DIGITAL_IP_INTERRUPT_ENABLE    0x4
+#define APCI1032_DIGITAL_IP_INTERRUPT_DISABLE   0xFFFFFFFB
+
+//ADDIDATA Enable Disable
+
+#define ADDIDATA_ENABLE                            1
+#define ADDIDATA_DISABLE                           0
+
+// Hardware Layer  functions for Apci1032
+
+//DI
+// for di read
+
+INT i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+INT i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+
+// Interrupt functions.....
+
+static void v_APCI1032_Interrupt(int irq, void *d);
+//Reset
+INT i_APCI1032_Reset(struct comedi_device *dev);

+ 3045 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c

@@ -0,0 +1,3045 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-1500       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci1500.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-1500                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+#include "hwdrv_apci1500.h"
+
+int i_TimerCounter1Init = 0;
+int i_TimerCounter2Init = 0;
+int i_WatchdogCounter3Init = 0;
+int i_Event1Status = 0, i_Event2Status = 0;
+int i_TimerCounterWatchdogInterrupt = 0;
+int i_Logic = 0, i_CounterLogic = 0;
+int i_InterruptMask = 0;
+int i_InputChannel = 0;
+int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled =
+	0, i_WatchdogCounter3Enabled = 0;
+
+/*
+  +----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_ConfigDigitalInputEvent                 |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : An event can be generated for each port.               |
+|                     The first event is related to the first 8 channels     |
+|                     (port 1) and the second to the following 6 channels    |
+|                     (port 2). An interrupt is generated when one or both   |
+|                     events have occurred                                   |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     unsigned int *data     : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|			  data[0]            :Number of the input port on        |
+|                                         which the event will take place    |
+|                                         (1 or 2)
+                      data[1]            : The event logic for port 1 has    |
+|                                            three possibilities             |
+|                                        :0  APCI1500_AND       :This logic  |
+|                                                                links       |
+|                                                                the inputs  |
+|                                                                with an AND |
+|                                                                logic.      |
+|                                          1 APCI1500_OR        :This logic  |
+|                                                                links       |
+|                                                                the inputs  |
+|                                                                with a      |
+|                                                                OR logic.   |
+|                                          2    APCI1500_OR_PRIORITY        |
+|								:This logic                          |
+|                                                                links       |
+|                                                                the inputs  |
+|                                                                with a      |
+|                                                                priority    |
+|                                                                OR logic.   |
+|                                                                Input 1     |
+|                                                                has the     |
+|                                                                highest     |
+|                                                                priority    |
+|                                                                level and   |
+|                                                                input   8   |
+|                                                                the smallest|
+|                                            For the second port the user has|
+|                                            1 possibility:                  |
+|                                            APCI1500_OR        :This logic  |
+|                                                                links       |
+|                                                                the inputs  |
+|                                                                with a      |
+|                                                                polarity    |
+|                                                                OR logic    |
+|                     data[2]              : These 8-character word for port1|
+|                                            and 6-character word for port 2 |
+|                                            give the mask of the event.     |
+|                                            Each place gives the state      |
+|                                            of the input channels and can   |
+|                                            have one of these six characters|
+|                                                     |
+|                                       0  : This input must be on 0         |
+|                                       1  : This input must be on 1         |
+|                                       2  : This input reacts to            |
+|                                            a falling edge                  |
+|                                       3  : This input reacts to a          |
+|                                            rising edge                     |
+|                                       4  : This input reacts to both edges |
+|
+|								5  : This input is not               |
+|                                            used for event   				 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1500_ConfigDigitalInputEvent(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0;
+	int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0;
+	int i_PatternTransitionCount = 0, i_RegValue;
+	int i;
+
+      /*************************************************/
+	/* Selects the master interrupt control register */
+      /*************************************************/
+	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+      /**********************************************/
+	/* Disables  the main interrupt on the board */
+      /**********************************************/
+	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	if (data[0] == 1) {
+		i_MaxChannel = 8;
+	}			// if (data[0] == 1)
+	else {
+		if (data[0] == 2) {
+			i_MaxChannel = 6;
+		}		// if(data[0]==2)
+		else {
+			printk("\nThe specified port event  does not exist\n");
+			return -EINVAL;
+		}		//else if(data[0]==2)
+	}			//else  if (data[0] == 1)
+	switch (data[1]) {
+	case 0:
+		data[1] = APCI1500_AND;
+		break;
+	case 1:
+		data[1] = APCI1500_OR;
+		break;
+	case 2:
+		data[1] = APCI1500_OR_PRIORITY;
+		break;
+	default:
+		printk("\nThe specified interrupt logic does not exist\n");
+		return -EINVAL;
+	}			//switch(data[1]);
+
+	i_Logic = data[1];
+	for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) {
+		i_EventMask = data[2 + i];
+		switch (i_EventMask) {
+		case 0:
+			i_PatternMask =
+				i_PatternMask | (1 << (i_MaxChannel - i_Count));
+			break;
+		case 1:
+			i_PatternMask =
+				i_PatternMask | (1 << (i_MaxChannel - i_Count));
+			i_PatternPolarity =
+				i_PatternPolarity | (1 << (i_MaxChannel -
+					i_Count));
+			break;
+		case 2:
+			i_PatternMask =
+				i_PatternMask | (1 << (i_MaxChannel - i_Count));
+			i_PatternTransition =
+				i_PatternTransition | (1 << (i_MaxChannel -
+					i_Count));
+			break;
+		case 3:
+			i_PatternMask =
+				i_PatternMask | (1 << (i_MaxChannel - i_Count));
+			i_PatternPolarity =
+				i_PatternPolarity | (1 << (i_MaxChannel -
+					i_Count));
+			i_PatternTransition =
+				i_PatternTransition | (1 << (i_MaxChannel -
+					i_Count));
+			break;
+		case 4:
+			i_PatternTransition =
+				i_PatternTransition | (1 << (i_MaxChannel -
+					i_Count));
+			break;
+		case 5:
+			break;
+		default:
+			printk("\nThe option indicated in the event mask does not exist\n");
+			return -EINVAL;
+		}		// switch(i_EventMask)
+	}			//for (i_Count = i_MaxChannel; i_Count >0;i_Count --)
+
+	if (data[0] == 1) {
+		    /****************************/
+		/* Test the interrupt logic */
+		    /****************************/
+
+		if (data[1] == APCI1500_AND ||
+			data[1] == APCI1500_OR ||
+			data[1] == APCI1500_OR_PRIORITY) {
+		       /**************************************/
+			/* Tests if a transition was declared */
+			/* for a OR PRIORITY logic            */
+		       /**************************************/
+
+			if (data[1] == APCI1500_OR_PRIORITY
+				&& i_PatternTransition != 0) {
+			      /********************************************/
+				/* Transition error on an OR PRIORITY logic */
+			      /********************************************/
+				printk("\nTransition error on an OR PRIORITY logic\n");
+				return -EINVAL;
+			}	// if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0)
+
+		       /*************************************/
+			/* Tests if more than one transition */
+			/* was declared for an AND logic     */
+		       /*************************************/
+
+			if (data[1] == APCI1500_AND) {
+				for (i_Count = 0; i_Count < 8; i_Count++) {
+					i_PatternTransitionCount =
+						i_PatternTransitionCount +
+						((i_PatternTransition >>
+							i_Count) & 0x1);
+
+				}	//for (i_Count = 0; i_Count < 8; i_Count++)
+
+				if (i_PatternTransitionCount > 1) {
+				  /****************************************/
+					/* Transition error on an AND logic     */
+				  /****************************************/
+					printk("\n Transition error on an AND logic\n");
+					return -EINVAL;
+				}	// if (i_PatternTransitionCount > 1)
+			}	// if (data[1]== APCI1500_AND)
+
+			    /*****************************************************************/
+			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+			    /*****************************************************************/
+			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			/******************/
+			/* Disable Port A */
+			    /******************/
+			outb(0xF0,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			/**********************************************/
+			/* Selects the polarity register of port 1    */
+			    /**********************************************/
+			outb(APCI1500_RW_PORT_A_PATTERN_POLARITY,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_PatternPolarity,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+			/*********************************************/
+			/* Selects the pattern mask register of      */
+			/* port 1                                    */
+			    /*********************************************/
+			outb(APCI1500_RW_PORT_A_PATTERN_MASK,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_PatternMask,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			/********************************************/
+			/* Selects the pattern transition register  */
+			/* of port 1                                */
+			    /********************************************/
+			outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_PatternTransition,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		      /******************************************/
+			/* Selects the mode specification mask    */
+			/* register of port 1                     */
+			  /******************************************/
+			outb(APCI1500_RW_PORT_A_SPECIFICATION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_RegValue =
+				inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		      /******************************************/
+			/* Selects the mode specification mask    */
+			/* register of port 1                     */
+			  /******************************************/
+			outb(APCI1500_RW_PORT_A_SPECIFICATION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		      /**********************/
+			/* Port A new mode    */
+			  /**********************/
+
+			i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+			i_Event1Status = 1;
+
+		      /*****************************************************************/
+			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+			  /*****************************************************************/
+
+			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		      /*****************/
+			/* Enable Port A */
+			  /*****************/
+			outb(0xF4,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		}		// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY)
+		else {
+			printk("\nThe choice for interrupt logic does not exist\n");
+			return -EINVAL;
+		}		// else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY)
+	}			//   if (data[0]== 1)
+
+		 /************************************/
+	/* Test if event setting for port 2 */
+		 /************************************/
+
+	if (data[0] == 2) {
+		    /************************/
+		/* Test the event logic */
+		    /************************/
+
+		if (data[1] == APCI1500_OR) {
+		       /*****************************************************************/
+			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		       /******************/
+			/* Disable Port B */
+		       /******************/
+			outb(0x74,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		       /****************************************/
+			/* Selects the mode specification mask  */
+			/* register of port B                   */
+		       /****************************************/
+			outb(APCI1500_RW_PORT_B_SPECIFICATION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_RegValue =
+				inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		       /******************************************/
+			/* Selects the mode specification mask    */
+			/* register of port B                     */
+		       /******************************************/
+			outb(APCI1500_RW_PORT_B_SPECIFICATION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_RegValue = i_RegValue & 0xF9;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		       /**********************************/
+			/* Selects error channels 1 and 2 */
+		       /**********************************/
+
+			i_PatternMask = (i_PatternMask | 0xC0);
+			i_PatternPolarity = (i_PatternPolarity | 0xC0);
+			i_PatternTransition = (i_PatternTransition | 0xC0);
+
+		       /**********************************************/
+			/* Selects the polarity register of port 2    */
+		       /**********************************************/
+			outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_PatternPolarity,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		       /**********************************************/
+			/* Selects the pattern transition register    */
+			/* of port 2                                  */
+		       /**********************************************/
+			outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_PatternTransition,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		       /**********************************************/
+			/* Selects the pattern Mask register    */
+			/* of port 2                                  */
+		       /**********************************************/
+
+			outb(APCI1500_RW_PORT_B_PATTERN_MASK,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_PatternMask,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		       /******************************************/
+			/* Selects the mode specification mask    */
+			/* register of port 2                     */
+		       /******************************************/
+			outb(APCI1500_RW_PORT_B_SPECIFICATION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_RegValue =
+				inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		       /******************************************/
+			/* Selects the mode specification mask    */
+			/* register of port 2                     */
+		       /******************************************/
+			outb(APCI1500_RW_PORT_B_SPECIFICATION,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_RegValue = (i_RegValue & 0xF9) | 4;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+			i_Event2Status = 1;
+		       /*****************************************************************/
+			/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+
+			outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************/
+			/* Enable Port B */
+		       /*****************/
+
+			outb(0xF4,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		}		//  if (data[1] == APCI1500_OR)
+		else {
+			printk("\nThe choice for interrupt logic does not exist\n");
+			return -EINVAL;
+		}		//elseif (data[1] == APCI1500_OR)
+	}			//if(data[0]==2)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_StartStopInputEvent                     |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              :  Allows or disallows a port event                      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|		              UINT ui_Channel : Channel number to read       |
+|                     unsigned int *data          : Data Pointer to read status  |
+                      data[0]                 :0 Start input event
+                                               1 Stop input event
+                      data[1]                 :No of port (1 or 2)
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI1500_StartStopInputEvent(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	int i_Event1InterruptStatus = 0, i_Event2InterruptStatus =
+		0, i_RegValue;
+	switch (data[0]) {
+	case START:
+	      /*************************/
+		/* Tests the port number */
+	      /*************************/
+
+		if (data[1] == 1 || data[1] == 2) {
+		  /***************************/
+			/* Test if port 1 selected */
+		  /***************************/
+
+			if (data[1] == 1) {
+		    /*****************************/
+				/* Test if event initialised */
+		    /*****************************/
+				if (i_Event1Status == 1) {
+		       /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /******************/
+					/* Disable Port A */
+		       /******************/
+					outb(0xF0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /***************************************************/
+					/* Selects the command and status register of      */
+					/* port 1                                          */
+		       /***************************************************/
+					outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*************************************/
+					/* Allows the pattern interrupt      */
+		       /*************************************/
+					outb(0xC0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************/
+					/* Enable Port A */
+		       /*****************/
+					outb(0xF4,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					i_Event1InterruptStatus = 1;
+					outb(APCI1500_RW_PORT_A_SPECIFICATION,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					i_RegValue =
+						inb(devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+
+					/* Selects the master interrupt control register */
+		       /*************************************************/
+					outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /**********************************************/
+					/* Authorizes the main interrupt on the board */
+		       /**********************************************/
+					outb(0xD0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+
+				}	// if(i_Event1Status==1)
+				else {
+					printk("\nEvent 1 not initialised\n");
+					return -EINVAL;
+				}	//else if(i_Event1Status==1)
+			}	//if (data[1]==1)
+			if (data[1] == 2) {
+
+				if (i_Event2Status == 1) {
+			    /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+			    /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /******************/
+					/* Disable Port B */
+		       /******************/
+					outb(0x74,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /***************************************************/
+					/* Selects the command and status register of      */
+					/* port 2                                          */
+		       /***************************************************/
+					outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*************************************/
+					/* Allows the pattern interrupt      */
+		       /*************************************/
+					outb(0xC0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************/
+					/* Enable Port B */
+		       /*****************/
+					outb(0xF4,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+
+					/* Selects the master interrupt control register */
+		       /*************************************************/
+					outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /**********************************************/
+					/* Authorizes the main interrupt on the board */
+		       /**********************************************/
+					outb(0xD0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					i_Event2InterruptStatus = 1;
+				}	// if(i_Event2Status==1)
+				else {
+					printk("\nEvent 2 not initialised\n");
+					return -EINVAL;
+				}	//else if(i_Event2Status==1)
+			}	// if(data[1]==2)
+		}		// if (data[1] == 1 || data[0] == 2)
+		else {
+			printk("\nThe port parameter is in error\n");
+			return -EINVAL;
+		}		//else if (data[1] == 1 || data[0] == 2)
+
+		break;
+
+	case STOP:
+		  /*************************/
+		/* Tests the port number */
+		  /*************************/
+
+		if (data[1] == 1 || data[1] == 2) {
+		  /***************************/
+			/* Test if port 1 selected */
+		  /***************************/
+
+			if (data[1] == 1) {
+		    /*****************************/
+				/* Test if event initialised */
+		    /*****************************/
+				if (i_Event1Status == 1) {
+		       /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /******************/
+					/* Disable Port A */
+		       /******************/
+					outb(0xF0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /***************************************************/
+					/* Selects the command and status register of      */
+					/* port 1                                          */
+		       /***************************************************/
+					outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*************************************/
+					/* Inhibits the pattern interrupt      */
+		       /*************************************/
+					outb(0xE0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************/
+					/* Enable Port A */
+		       /*****************/
+					outb(0xF4,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					i_Event1InterruptStatus = 0;
+				}	// if(i_Event1Status==1)
+				else {
+					printk("\nEvent 1 not initialised\n");
+					return -EINVAL;
+				}	//else if(i_Event1Status==1)
+			}	//if (data[1]==1)
+			if (data[1] == 2) {
+			 /*****************************/
+				/* Test if event initialised */
+			 /*****************************/
+				if (i_Event2Status == 1) {
+			  /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+			  /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+			  /******************/
+					/* Disable Port B */
+			  /******************/
+					outb(0x74,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+			  /***************************************************/
+					/* Selects the command and status register of      */
+					/* port 2                                         */
+			  /***************************************************/
+					outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*************************************/
+					/* Inhibits the pattern interrupt      */
+		       /*************************************/
+					outb(0xE0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************************************************************/
+					/* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
+		       /*****************************************************************/
+					outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		       /*****************/
+					/* Enable Port B */
+		       /*****************/
+					outb(0xF4,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					i_Event2InterruptStatus = 0;
+				}	// if(i_Event2Status==1)
+				else {
+					printk("\nEvent 2 not initialised\n");
+					return -EINVAL;
+				}	//else if(i_Event2Status==1)
+			}	//if(data[1]==2)
+
+		}		// if (data[1] == 1 || data[1] == 2)
+		else {
+			printk("\nThe port parameter is in error\n");
+			return -EINVAL;
+		}		//else if (data[1] == 1 || data[1] == 2)
+		break;
+	default:
+		printk("\nThe option of START/STOP logic does not exist\n");
+		return -EINVAL;
+	}			//switch(data[0])
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_Initialisation                          |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the digital input                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|		              UINT ui_Channel : Channel number to read       |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1500_Initialisation(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	int i_DummyRead = 0;
+    /******************/
+	/* Software reset */
+    /******************/
+	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+ /*****************************************************/
+	/* Selects the master configuration control register */
+ /*****************************************************/
+	outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/*****************************************************/
+	/* Selects the mode specification register of port A */
+	/*****************************************************/
+	outb(APCI1500_RW_PORT_A_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/* Selects the data path polarity register of port A */
+	outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* High level of port A means 1 */
+	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/* Selects the data direction register of port A */
+	outb(APCI1500_RW_PORT_A_DATA_DIRECTION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* All bits used as inputs */
+	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of port A */
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/*  Selects the command and status register of port A */
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates the interrupt management of port A:  */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the handshake specification register of port A */
+	outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes the register */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	 /*****************************************************/
+	/* Selects the mode specification register of port B */
+	 /*****************************************************/
+	outb(APCI1500_RW_PORT_B_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the data path polarity register of port B */
+	outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* A high level of port B means 1 */
+	outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the data direction register of port B */
+	outb(APCI1500_RW_PORT_B_DATA_DIRECTION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* All bits used as inputs */
+	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of port B */
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of port B */
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates the interrupt management of port B:         */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the handshake specification register of port B */
+	outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes the register */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	   /*****************************************************/
+	/* Selects the data path polarity register of port C */
+	   /*****************************************************/
+	outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* High level of port C means 1 */
+	outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the data direction register of port C */
+	outb(APCI1500_RW_PORT_C_DATA_DIRECTION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* All bits used as inputs except channel 1 */
+	outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the special IO register of port C */
+	outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes it */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	   /******************************************************/
+	/* Selects the command and status register of timer 1 */
+	   /******************************************************/
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of timer 1 */
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates the interrupt management of timer 1         */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	   /******************************************************/
+	/* Selects the command and status register of timer 2 */
+	   /******************************************************/
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of timer 2 */
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates Timer 2 interrupt management:               */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	  /******************************************************/
+	/* Selects the command and status register of timer 3 */
+	  /******************************************************/
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of Timer 3 */
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates interrupt management of timer 3:            */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /*************************************************/
+	/* Selects the master interrupt control register */
+	 /*************************************************/
+	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes all interrupts */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_ReadMoreDigitalInput                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                     struct comedi_insn *insn,unsigned int *data)                      |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the Requested digital inputs      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To be Read    |
+|                      UINT *data             : Data Pointer
+                      data[0]                 : 0 Read a single channel
+                                                1 read a port value
+                      data[1]                 : port value
++----------------------------------------------------------------------------+
+| Output Parameters :	--	data[0]    :The read status value
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1500_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_PortValue = data[1];
+	UINT ui_Mask = 0;
+	UINT ui_Channel;
+	UINT ui_TmpValue = 0;
+	ui_Channel = CR_CHAN(insn->chanspec);
+
+	switch (data[0]) {
+	case 0:
+		if (ui_Channel >= 0 && ui_Channel <= 15) {
+			ui_TmpValue =
+				(UINT) inw(devpriv->i_IobaseAddon +
+				APCI1500_DIGITAL_IP);
+			*data = (ui_TmpValue >> ui_Channel) & 0x1;
+		}		//if(ui_Channel >= 0 && ui_Channel <=15)
+		else {
+			printk("\nThe channel specification are in error\n");
+			return -EINVAL;	// "sorry channel spec wrong "
+		}		//else if(ui_Channel >= 0 && ui_Channel <=15)
+		break;
+	case 1:
+
+		*data = (UINT) inw(devpriv->i_IobaseAddon +
+			APCI1500_DIGITAL_IP);
+		switch (ui_Channel) {
+		case 2:
+			ui_Mask = 3;
+			*data = (*data >> (2 * ui_PortValue)) & ui_Mask;
+			break;
+		case 4:
+			ui_Mask = 15;
+			*data = (*data >> (4 * ui_PortValue)) & ui_Mask;
+			break;
+		case 8:
+			ui_Mask = 255;
+			*data = (*data >> (8 * ui_PortValue)) & ui_Mask;
+			break;
+		case 15:
+			break;
+
+		default:
+			printk("\nSpecified channel cannot be read \n");
+			return -EINVAL;	// "sorry channel spec wrong "
+			break;
+		}		//switch(ui_Channel)
+		break;
+	default:
+		printk("\nThe specified functionality does not exist\n");
+		return -EINVAL;
+	}			//switch(data[0])
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_ConfigDigitalOutputErrorInterrupt
+                      (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn
+                      *insn,unsigned int *data)                                  |
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures the digital output memory and the digital
+                      output error interrupt                                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     unsigned int *data         : Data Pointer contains         |
+|                                          configuration parameters as below |
+|                      struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure                                                                                                                |
+|					  data[0]  :1:Memory on                          |
+|					            0:Memory off                         |
+                              data[1]  :1 Enable the voltage error interrupt
+|							   :0 Disable the voltage error interrupt 		                                                                                                    |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	devpriv->b_OutputMemoryStatus = data[0];
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_WriteDigitalOutput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To Write      |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1500_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	static UINT ui_Temp = 0;
+	UINT ui_Temp1;
+
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+
+	if (!devpriv->b_OutputMemoryStatus) {
+		ui_Temp = 0;
+
+	}			//if(!devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outw(data[0],
+				devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
+		}		//if(data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 4:
+					data[0] =
+						(data[0] << (4 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 8:
+					data[0] =
+						(data[0] << (8 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 15:
+					data[0] = data[0] | ui_Temp;
+					break;
+
+				default:
+					comedi_error(dev, " chan spec wrong");
+					return -EINVAL;	// "sorry channel spec wrong "
+
+				}	//switch(ui_NoOfChannels)
+
+				outw(data[0],
+					devpriv->i_IobaseAddon +
+					APCI1500_DIGITAL_OP);
+			}	// if(data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	//else if(data[1]==1)
+		}		//elseif(data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] =
+					(data[0] << ui_NoOfChannel) ^
+					0xffffffff;
+				data[0] = data[0] & ui_Temp;
+				outw(data[0],
+					devpriv->i_IobaseAddon +
+					APCI1500_DIGITAL_OP);
+			}	//if(data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 4:
+						data[0] = ~data[0] & 0xf;
+						ui_Temp1 = 15;
+						ui_Temp1 =
+							ui_Temp1 << 4 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (4 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 8:
+						data[0] = ~data[0] & 0xff;
+						ui_Temp1 = 255;
+						ui_Temp1 =
+							ui_Temp1 << 8 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (8 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 15:
+						break;
+
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+
+					}	//switch(ui_NoOfChannels)
+
+					outw(data[0],
+						devpriv->i_IobaseAddon +
+						APCI1500_DIGITAL_OP);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	ui_Temp = data[0];
+	return (insn->n);;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device
+                   *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Watchdog                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data         : Data Pointer to read status                                                       data[0]                : 2     APCI1500_1_8_KHZ
+|                                              1     APCI1500_3_6_KHZ        |
+|                                              0     APCI1500_115_KHZ
+                      data[1]                : 0     Counter1/Timer1
+                                               1     Counter2/Timer2
+                                               2     Counter3/Watchdog
+                      data[2]                : 0     Counter
+                                               1     Timer/Watchdog
+                      data[3]                :         This parameter has    |
+|                                                      two meanings.         |
+|                                                    - If the counter/timer  |
+|                                                      is used as a counter  |
+|                                                      the limit value of    |
+|                                                      the counter is given  |
+|                                                                            |
+|                                                    - If the counter/timer  |
+|                                                      is used as a timer,   |
+|                                                      the divider factor    |
+|                                                      for the output is     |
+|                                                      given.
+                       data[4]                 : 0    APCI1500_CONTINUOUS
+                                                 1    APCI1500_SINGLE
+                       data[5]                 : 0    Software Trigger
+                                                 1    Hardware Trigger
+
+                       data[6]                  :0    Software gate
+                                                 1    Hardware gate
+                       data[7]                  :0    Interrupt Disable
+                                                 1    Interrupt Enable
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	int i_TimerCounterMode, i_MasterConfiguration;
+
+	devpriv->tsk_Current = current;
+
+//Selection of the input clock
+	if (data[0] == 0 || data[0] == 1 || data[0] == 2) {
+		outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT);
+	}			// if(data[0]==0||data[0]==1||data[0]==2)
+	else {
+		if (data[0] != 3) {
+			printk("\nThe option for input clock selection does not exist\n");
+			return -EINVAL;
+		}		// if(data[0]!=3)
+	}			//elseif(data[0]==0||data[0]==1||data[0]==2)
+	//Select the counter/timer
+	switch (data[1]) {
+	case COUNTER1:
+		//selecting counter or timer
+		switch (data[2]) {
+		case 0:
+			data[2] = APCI1500_COUNTER;
+			break;
+		case 1:
+			data[2] = APCI1500_TIMER;
+			break;
+		default:
+			printk("\nThis choice is not a timer nor a counter\n");
+			return -EINVAL;
+		}		// switch(data[2])
+
+		//Selecting  single or continuous mode
+		switch (data[4]) {
+		case 0:
+			data[4] = APCI1500_CONTINUOUS;
+			break;
+		case 1:
+			data[4] = APCI1500_SINGLE;
+			break;
+		default:
+			printk("\nThis option for single/continuous mode does not exist\n");
+			return -EINVAL;
+		}		// switch(data[4])
+
+		i_TimerCounterMode = data[2] | data[4] | 7;
+			 /*************************/
+		/* Test the reload value */
+			 /*************************/
+
+		if ((data[3] >= 0) && (data[3] <= 65535)) {
+			if (data[7] == APCI1500_ENABLE
+				|| data[7] == APCI1500_DISABLE) {
+
+				/************************************************/
+				/* Selects the mode register of timer/counter 1 */
+				/************************************************/
+				outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				/***********************/
+				/* Writes the new mode */
+				/***********************/
+				outb(i_TimerCounterMode,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				/****************************************************/
+				/* Selects the constant register of timer/counter 1 */
+				/****************************************************/
+
+				outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				  /*************************/
+				/* Writes the low value  */
+				  /*************************/
+
+				outb(data[3],
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				   /****************************************************/
+				/* Selects the constant register of timer/counter 1 */
+				   /****************************************************/
+
+				outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				  /**************************/
+				/* Writes the high value  */
+				  /**************************/
+
+				data[3] = data[3] >> 8;
+				outb(data[3],
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				     /*********************************************/
+				/* Selects the master configuration register */
+				     /*********************************************/
+
+				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				     /**********************/
+				/* Reads the register */
+				     /**********************/
+
+				i_MasterConfiguration =
+					inb(devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				       /********************************************************/
+				/* Enables timer/counter 1 and triggers timer/counter 1 */
+				       /********************************************************/
+
+				i_MasterConfiguration =
+					i_MasterConfiguration | 0x40;
+
+				    /*********************************************/
+				/* Selects the master configuration register */
+				    /*********************************************/
+				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				      /********************************/
+				/* Writes the new configuration */
+				      /********************************/
+				outb(i_MasterConfiguration,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+					 /****************************************/
+				/* Selects the commands register of     */
+				/* timer/counter 1                      */
+					 /****************************************/
+
+				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				       /***************************/
+				/* Disable timer/counter 1 */
+				       /***************************/
+
+				outb(0x0,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+					  /****************************************/
+				/* Selects the commands register of     */
+				/* timer/counter 1                      */
+					  /****************************************/
+				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				      /***************************/
+				/* Trigger timer/counter 1 */
+				      /***************************/
+				outb(0x2,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+			}	//if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE)
+			else {
+				printk("\nError in selection of interrupt enable or disable\n");
+				return -EINVAL;
+			}	//elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE)
+		}		// if ((data[3]>= 0) && (data[3] <= 65535))
+		else {
+			printk("\nError in selection of reload value\n");
+			return -EINVAL;
+		}		//else if ((data[3]>= 0) && (data[3] <= 65535))
+		i_TimerCounterWatchdogInterrupt = data[7];
+		i_TimerCounter1Init = 1;
+		break;
+
+	case COUNTER2:		//selecting counter or timer
+		switch (data[2]) {
+		case 0:
+			data[2] = APCI1500_COUNTER;
+			break;
+		case 1:
+			data[2] = APCI1500_TIMER;
+			break;
+		default:
+			printk("\nThis choice is not a timer nor a counter\n");
+			return -EINVAL;
+		}		// switch(data[2])
+
+		//Selecting  single or continuous mode
+		switch (data[4]) {
+		case 0:
+			data[4] = APCI1500_CONTINUOUS;
+			break;
+		case 1:
+			data[4] = APCI1500_SINGLE;
+			break;
+		default:
+			printk("\nThis option for single/continuous mode does not exist\n");
+			return -EINVAL;
+		}		// switch(data[4])
+
+		//Selecting  software or hardware trigger
+		switch (data[5]) {
+		case 0:
+			data[5] = APCI1500_SOFTWARE_TRIGGER;
+			break;
+		case 1:
+			data[5] = APCI1500_HARDWARE_TRIGGER;
+			break;
+		default:
+			printk("\nThis choice for software or hardware trigger does not exist\n");
+			return -EINVAL;
+		}		// switch(data[5])
+
+		//Selecting  software or hardware gate
+		switch (data[6]) {
+		case 0:
+			data[6] = APCI1500_SOFTWARE_GATE;
+			break;
+		case 1:
+			data[6] = APCI1500_HARDWARE_GATE;
+			break;
+		default:
+			printk("\nThis choice for software or hardware gate does not exist\n");
+			return -EINVAL;
+		}		// switch(data[6])
+
+		i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7;
+
+			     /*************************/
+		/* Test the reload value */
+			     /*************************/
+
+		if ((data[3] >= 0) && (data[3] <= 65535)) {
+			if (data[7] == APCI1500_ENABLE
+				|| data[7] == APCI1500_DISABLE) {
+
+				/************************************************/
+				/* Selects the mode register of timer/counter 2 */
+				/************************************************/
+				outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				/***********************/
+				/* Writes the new mode */
+				/***********************/
+				outb(i_TimerCounterMode,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				/****************************************************/
+				/* Selects the constant register of timer/counter 2 */
+				/****************************************************/
+
+				outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				  /*************************/
+				/* Writes the low value  */
+				  /*************************/
+
+				outb(data[3],
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				   /****************************************************/
+				/* Selects the constant register of timer/counter 2 */
+				   /****************************************************/
+
+				outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				  /**************************/
+				/* Writes the high value  */
+				  /**************************/
+
+				data[3] = data[3] >> 8;
+				outb(data[3],
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				     /*********************************************/
+				/* Selects the master configuration register */
+				     /*********************************************/
+
+				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				     /**********************/
+				/* Reads the register */
+				     /**********************/
+
+				i_MasterConfiguration =
+					inb(devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				       /********************************************************/
+				/* Enables timer/counter 2 and triggers timer/counter 2 */
+				       /********************************************************/
+
+				i_MasterConfiguration =
+					i_MasterConfiguration | 0x20;
+
+				    /*********************************************/
+				/* Selects the master configuration register */
+				    /*********************************************/
+				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				      /********************************/
+				/* Writes the new configuration */
+				      /********************************/
+				outb(i_MasterConfiguration,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+					 /****************************************/
+				/* Selects the commands register of     */
+				/* timer/counter 2                      */
+					 /****************************************/
+
+				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				       /***************************/
+				/* Disable timer/counter 2 */
+				       /***************************/
+
+				outb(0x0,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+					  /****************************************/
+				/* Selects the commands register of     */
+				/* timer/counter 2                      */
+					  /****************************************/
+				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				      /***************************/
+				/* Trigger timer/counter 1 */
+				      /***************************/
+				outb(0x2,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+			}	//if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE)
+			else {
+				printk("\nError in selection of interrupt enable or disable\n");
+				return -EINVAL;
+			}	//elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE)
+		}		// if ((data[3]>= 0) && (data[3] <= 65535))
+		else {
+			printk("\nError in selection of reload value\n");
+			return -EINVAL;
+		}		//else if ((data[3]>= 0) && (data[3] <= 65535))
+		i_TimerCounterWatchdogInterrupt = data[7];
+		i_TimerCounter2Init = 1;
+		break;
+
+	case COUNTER3:		//selecting counter or watchdog
+		switch (data[2]) {
+		case 0:
+			data[2] = APCI1500_COUNTER;
+			break;
+		case 1:
+			data[2] = APCI1500_WATCHDOG;
+			break;
+		default:
+			printk("\nThis choice is not a watchdog nor a counter\n");
+			return -EINVAL;
+		}		// switch(data[2])
+
+		//Selecting  single or continuous mode
+		switch (data[4]) {
+		case 0:
+			data[4] = APCI1500_CONTINUOUS;
+			break;
+		case 1:
+			data[4] = APCI1500_SINGLE;
+			break;
+		default:
+			printk("\nThis option for single/continuous mode does not exist\n");
+			return -EINVAL;
+		}		// switch(data[4])
+
+		//Selecting  software or hardware gate
+		switch (data[6]) {
+		case 0:
+			data[6] = APCI1500_SOFTWARE_GATE;
+			break;
+		case 1:
+			data[6] = APCI1500_HARDWARE_GATE;
+			break;
+		default:
+			printk("\nThis choice for software or hardware gate does not exist\n");
+			return -EINVAL;
+		}		// switch(data[6])
+
+		      /*****************************/
+		/* Test if used for watchdog */
+			  /*****************************/
+
+		if (data[2] == APCI1500_WATCHDOG) {
+			     /*****************************/
+			/* - Enables the output line */
+			/* - Enables retrigger       */
+			/* - Pulses output           */
+			     /*****************************/
+			i_TimerCounterMode = data[2] | data[4] | 0x54;
+		}		//if (data[2] == APCI1500_WATCHDOG)
+		else {
+			i_TimerCounterMode = data[2] | data[4] | data[6] | 7;
+		}		//elseif (data[2] == APCI1500_WATCHDOG)
+				 /*************************/
+		/* Test the reload value */
+			     /*************************/
+
+		if ((data[3] >= 0) && (data[3] <= 65535)) {
+			if (data[7] == APCI1500_ENABLE
+				|| data[7] == APCI1500_DISABLE) {
+
+				/************************************************/
+				/* Selects the mode register of watchdog/counter 3 */
+				/************************************************/
+				outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				/***********************/
+				/* Writes the new mode */
+				/***********************/
+				outb(i_TimerCounterMode,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				/****************************************************/
+				/* Selects the constant register of watchdog/counter 3 */
+				/****************************************************/
+
+				outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				  /*************************/
+				/* Writes the low value  */
+				  /*************************/
+
+				outb(data[3],
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				   /****************************************************/
+				/* Selects the constant register of watchdog/counter 3 */
+				   /****************************************************/
+
+				outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				  /**************************/
+				/* Writes the high value  */
+				  /**************************/
+
+				data[3] = data[3] >> 8;
+				outb(data[3],
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				     /*********************************************/
+				/* Selects the master configuration register */
+				     /*********************************************/
+
+				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				     /**********************/
+				/* Reads the register */
+				     /**********************/
+
+				i_MasterConfiguration =
+					inb(devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				       /********************************************************/
+				/* Enables watchdog/counter 3 and triggers watchdog/counter 3 */
+				       /********************************************************/
+
+				i_MasterConfiguration =
+					i_MasterConfiguration | 0x10;
+
+				    /*********************************************/
+				/* Selects the master configuration register */
+				    /*********************************************/
+				outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				      /********************************/
+				/* Writes the new configuration */
+				      /********************************/
+				outb(i_MasterConfiguration,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				      /********************/
+				/* Test if COUNTER */
+					  /********************/
+				if (data[2] == APCI1500_COUNTER) {
+
+					    /*************************************/
+					/* Selects the command register of   */
+					/* watchdog/counter 3                */
+						 /*************************************/
+					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					      /*************************************************/
+					/* Disable the  watchdog/counter 3 and starts it */
+						  /*************************************************/
+					outb(0x0,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+
+					      /*************************************/
+					/* Selects the command register of   */
+					/* watchdog/counter 3                */
+						  /*************************************/
+
+					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					     /*************************************************/
+					/* Trigger the  watchdog/counter 3 and starts it */
+						 /*************************************************/
+					outb(0x2,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+
+				}	//elseif(data[2]==APCI1500_COUNTER)
+
+			}	//if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE)
+			else {
+				printk("\nError in selection of interrupt enable or disable\n");
+				return -EINVAL;
+			}	//elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE)
+		}		// if ((data[3]>= 0) && (data[3] <= 65535))
+		else {
+			printk("\nError in selection of reload value\n");
+			return -EINVAL;
+		}		//else if ((data[3]>= 0) && (data[3] <= 65535))
+		i_TimerCounterWatchdogInterrupt = data[7];
+		i_WatchdogCounter3Init = 1;
+		break;
+
+	default:
+		printk("\nThe specified counter\timer option does not exist\n");
+	}			//switch(data[1])
+	i_CounterLogic = data[2];
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_StartStopTriggerTimerCounterWatchdog      |
+|				(struct comedi_device *dev,struct comedi_subdevice *s,
+                         struct comedi_insn *insn,unsigned int *data);                  |
++----------------------------------------------------------------------------+
+| Task              : Start / Stop or trigger the timer counter or Watchdog  |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev     : Driver handle                 |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data         : Data Pointer to read status   |
+                      data[0]                : 0     Counter1/Timer1
+                                               1     Counter2/Timer2
+                                               2     Counter3/Watchdog
+                      data[1]                : 0     start
+                                               1     stop
+                                               2     Trigger
+                      data[2]                : 0     Counter
+                                               1     Timer/Watchdog
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	int i_CommandAndStatusValue;
+
+	switch (data[0]) {
+	case COUNTER1:
+		switch (data[1]) {
+		case START:
+			if (i_TimerCounter1Init == 1) {
+				if (i_TimerCounterWatchdogInterrupt == 1) {
+					i_CommandAndStatusValue = 0xC4;	//Enable the interrupt
+				}	// if(i_TimerCounterWatchdogInterrupt==1)
+				else {
+					i_CommandAndStatusValue = 0xE4;	//disable the interrupt
+				}	//elseif(i_TimerCounterWatchdogInterrupt==1)
+					      /**************************/
+				/* Starts timer/counter 1 */
+					      /**************************/
+				i_TimerCounter1Enabled = 1;
+						/********************************************/
+				/* Selects the commands and status register */
+						/********************************************/
+				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				outb(i_CommandAndStatusValue,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+			}	//if( i_TimerCounter1Init==1)
+			else {
+				printk("\nCounter/Timer1 not configured\n");
+				return -EINVAL;
+			}
+			break;
+
+		case STOP:
+
+					      /**************************/
+			/* Stop timer/counter 1 */
+					      /**************************/
+
+						/********************************************/
+			/* Selects the commands and status register */
+						/********************************************/
+			outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(0x00,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_TimerCounter1Enabled = 0;
+			break;
+
+		case TRIGGER:
+			if (i_TimerCounter1Init == 1) {
+				if (i_TimerCounter1Enabled == 1) {
+						 /************************/
+					/* Set Trigger and gate */
+						 /************************/
+
+					i_CommandAndStatusValue = 0x6;
+				}	//if( i_TimerCounter1Enabled==1)
+				else {
+						   /***************/
+					/* Set Trigger */
+						   /***************/
+
+					i_CommandAndStatusValue = 0x2;
+				}	//elseif(i_TimerCounter1Enabled==1)
+
+						/********************************************/
+				/* Selects the commands and status register */
+						/********************************************/
+				outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				outb(i_CommandAndStatusValue,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+			}	//if( i_TimerCounter1Init==1)
+			else {
+				printk("\nCounter/Timer1 not configured\n");
+				return -EINVAL;
+			}
+			break;
+
+		default:
+			printk("\nThe specified option for start/stop/trigger does not exist\n");
+			return -EINVAL;
+		}		//switch(data[1])
+		break;
+
+	case COUNTER2:
+		switch (data[1]) {
+		case START:
+			if (i_TimerCounter2Init == 1) {
+				if (i_TimerCounterWatchdogInterrupt == 1) {
+					i_CommandAndStatusValue = 0xC4;	//Enable the interrupt
+				}	// if(i_TimerCounterWatchdogInterrupt==1)
+				else {
+					i_CommandAndStatusValue = 0xE4;	//disable the interrupt
+				}	//elseif(i_TimerCounterWatchdogInterrupt==1)
+					      /**************************/
+				/* Starts timer/counter 2 */
+					      /**************************/
+				i_TimerCounter2Enabled = 1;
+						/********************************************/
+				/* Selects the commands and status register */
+						/********************************************/
+				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				outb(i_CommandAndStatusValue,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+			}	//if( i_TimerCounter2Init==1)
+			else {
+				printk("\nCounter/Timer2 not configured\n");
+				return -EINVAL;
+			}
+			break;
+
+		case STOP:
+
+					      /**************************/
+			/* Stop timer/counter 2 */
+					      /**************************/
+
+						/********************************************/
+			/* Selects the commands and status register */
+						/********************************************/
+			outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(0x00,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_TimerCounter2Enabled = 0;
+			break;
+		case TRIGGER:
+			if (i_TimerCounter2Init == 1) {
+				if (i_TimerCounter2Enabled == 1) {
+						 /************************/
+					/* Set Trigger and gate */
+						 /************************/
+
+					i_CommandAndStatusValue = 0x6;
+				}	//if( i_TimerCounter2Enabled==1)
+				else {
+						   /***************/
+					/* Set Trigger */
+						   /***************/
+
+					i_CommandAndStatusValue = 0x2;
+				}	//elseif(i_TimerCounter2Enabled==1)
+
+						/********************************************/
+				/* Selects the commands and status register */
+						/********************************************/
+				outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				outb(i_CommandAndStatusValue,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+			}	//if( i_TimerCounter2Init==1)
+			else {
+				printk("\nCounter/Timer2 not configured\n");
+				return -EINVAL;
+			}
+			break;
+		default:
+			printk("\nThe specified option for start/stop/trigger does not exist\n");
+			return -EINVAL;
+		}		//switch(data[1])
+		break;
+	case COUNTER3:
+		switch (data[1]) {
+		case START:
+			if (i_WatchdogCounter3Init == 1) {
+
+				if (i_TimerCounterWatchdogInterrupt == 1) {
+					i_CommandAndStatusValue = 0xC4;	//Enable the interrupt
+				}	// if(i_TimerCounterWatchdogInterrupt==1)
+				else {
+					i_CommandAndStatusValue = 0xE4;	//disable the interrupt
+				}	//elseif(i_TimerCounterWatchdogInterrupt==1)
+					      /**************************/
+				/* Starts Watchdog/counter 3 */
+					      /**************************/
+				i_WatchdogCounter3Enabled = 1;
+						/********************************************/
+				/* Selects the commands and status register */
+						/********************************************/
+				outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				outb(i_CommandAndStatusValue,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+			}	// if( i_WatchdogCounter3init==1)
+			else {
+				printk("\nWatchdog/Counter3 not configured\n");
+				return -EINVAL;
+			}
+			break;
+
+		case STOP:
+
+					      /**************************/
+			/* Stop Watchdog/counter 3 */
+					      /**************************/
+
+						/********************************************/
+			/* Selects the commands and status register */
+						/********************************************/
+			outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(0x00,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_WatchdogCounter3Enabled = 0;
+			break;
+
+		case TRIGGER:
+			switch (data[2]) {
+			case 0:	//triggering counter 3
+				if (i_WatchdogCounter3Init == 1) {
+					if (i_WatchdogCounter3Enabled == 1) {
+							       /************************/
+						/* Set Trigger and gate */
+							       /************************/
+
+						i_CommandAndStatusValue = 0x6;
+					}	//if( i_WatchdogCounter3Enabled==1)
+					else {
+							   /***************/
+						/* Set Trigger */
+							   /***************/
+
+						i_CommandAndStatusValue = 0x2;
+					}	//elseif(i_WatchdogCounter3Enabled==1)
+
+						/********************************************/
+					/* Selects the commands and status register */
+						/********************************************/
+					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					outb(i_CommandAndStatusValue,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+				}	//if( i_WatchdogCounter3Init==1)
+				else {
+					printk("\nCounter3 not configured\n");
+					return -EINVAL;
+				}
+				break;
+			case 1:
+				//triggering Watchdog 3
+				if (i_WatchdogCounter3Init == 1) {
+
+						/********************************************/
+					/* Selects the commands and status register */
+						/********************************************/
+					outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+					outb(0x6,
+						devpriv->iobase +
+						APCI1500_Z8536_CONTROL_REGISTER);
+				}	//if( i_WatchdogCounter3Init==1)
+				else {
+					printk("\nWatchdog 3 not configured\n");
+					return -EINVAL;
+				}
+				break;
+			default:
+				printk("\nWrong choice of watchdog/counter3\n");
+				return -EINVAL;
+			}	//switch(data[2])
+			break;
+		default:
+			printk("\nThe specified option for start/stop/trigger does not exist\n");
+			return -EINVAL;
+		}		//switch(data[1])
+		break;
+	default:
+		printk("\nThe specified choice for counter/watchdog/timer does not exist\n");
+		return -EINVAL;
+	}			//switch(data[0])
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_ReadCounterTimerWatchdog                |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data); 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Watchdog                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
+                      data[0]                : 0     Counter1/Timer1
+                                               1     Counter2/Timer2
+                                               2     Counter3/Watchdog
+
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	int i_CommandAndStatusValue;
+	switch (data[0]) {
+	case COUNTER1:
+		//Read counter/timer1
+		if (i_TimerCounter1Init == 1) {
+			if (i_TimerCounter1Enabled == 1) {
+		  /************************/
+				/* Set RCC and gate */
+		  /************************/
+
+				i_CommandAndStatusValue = 0xC;
+			}	//if( i_TimerCounter1Init==1)
+			else {
+		    /***************/
+				/* Set RCC */
+		    /***************/
+
+				i_CommandAndStatusValue = 0x8;
+			}	//elseif(i_TimerCounter1Init==1)
+
+		/********************************************/
+			/* Selects the commands and status register */
+		/********************************************/
+			outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_CommandAndStatusValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		 /***************************************/
+			/* Selects the counter register (high) */
+		 /***************************************/
+			outb(APCI1500_R_CPT_TMR1_VALUE_HIGH,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] =
+				inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] = data[0] << 8;
+			data[0] = data[0] & 0xff00;
+			outb(APCI1500_R_CPT_TMR1_VALUE_LOW,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] =
+				data[0] | inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		}		//if( i_TimerCounter1Init==1)
+		else {
+			printk("\nTimer/Counter1 not configured\n");
+			return -EINVAL;
+		}		//elseif( i_TimerCounter1Init==1)
+		break;
+	case COUNTER2:
+		//Read counter/timer2
+		if (i_TimerCounter2Init == 1) {
+			if (i_TimerCounter2Enabled == 1) {
+		  /************************/
+				/* Set RCC and gate */
+		  /************************/
+
+				i_CommandAndStatusValue = 0xC;
+			}	//if( i_TimerCounter2Init==1)
+			else {
+		    /***************/
+				/* Set RCC */
+		    /***************/
+
+				i_CommandAndStatusValue = 0x8;
+			}	//elseif(i_TimerCounter2Init==1)
+
+		/********************************************/
+			/* Selects the commands and status register */
+		/********************************************/
+			outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_CommandAndStatusValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		 /***************************************/
+			/* Selects the counter register (high) */
+		 /***************************************/
+			outb(APCI1500_R_CPT_TMR2_VALUE_HIGH,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] =
+				inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] = data[0] << 8;
+			data[0] = data[0] & 0xff00;
+			outb(APCI1500_R_CPT_TMR2_VALUE_LOW,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] =
+				data[0] | inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		}		//if( i_TimerCounter2Init==1)
+		else {
+			printk("\nTimer/Counter2 not configured\n");
+			return -EINVAL;
+		}		//elseif( i_TimerCounter2Init==1)
+		break;
+	case COUNTER3:
+		//Read counter/watchdog2
+		if (i_WatchdogCounter3Init == 1) {
+			if (i_WatchdogCounter3Enabled == 1) {
+		  /************************/
+				/* Set RCC and gate */
+		  /************************/
+
+				i_CommandAndStatusValue = 0xC;
+			}	//if( i_TimerCounter2Init==1)
+			else {
+		    /***************/
+				/* Set RCC */
+		    /***************/
+
+				i_CommandAndStatusValue = 0x8;
+			}	//elseif(i_WatchdogCounter3Init==1)
+
+		/********************************************/
+			/* Selects the commands and status register */
+		/********************************************/
+			outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			outb(i_CommandAndStatusValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+
+		 /***************************************/
+			/* Selects the counter register (high) */
+		 /***************************************/
+			outb(APCI1500_R_CPT_TMR3_VALUE_HIGH,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] =
+				inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] = data[0] << 8;
+			data[0] = data[0] & 0xff00;
+			outb(APCI1500_R_CPT_TMR3_VALUE_LOW,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			data[0] =
+				data[0] | inb(devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		}		//if( i_WatchdogCounter3Init==1)
+		else {
+			printk("\nWatchdogCounter3 not configured\n");
+			return -EINVAL;
+		}		//elseif( i_WatchdogCounter3Init==1)
+		break;
+	default:
+		printk("\nThe choice of timer/counter/watchdog does not exist\n");
+		return -EINVAL;
+	}			//switch(data[0])
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int  i_APCI1500_ReadInterruptMask                      |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data); 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read the interrupt mask                                |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
+
+
++----------------------------------------------------------------------------+
+| Output Parameters :	--	data[0]:The interrupt mask value												                           data[1]:Channel no
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI1500_ReadInterruptMask(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	data[0] = i_InterruptMask;
+	data[1] = i_InputChannel;
+	i_InterruptMask = 0;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int  i_APCI1500_ConfigureInterrupt                     |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data); 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures the interrupt registers                     |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer                 |
+
+
++----------------------------------------------------------------------------+
+| Output Parameters :	--
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI1500_ConfigureInterrupt(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Status;
+	int i_RegValue;
+	int i_Constant;
+	devpriv->tsk_Current = current;
+	outl(0x0, devpriv->i_IobaseAmcc + 0x38);
+	if (data[0] == 1) {
+		i_Constant = 0xC0;
+	}			//if(data[0]==1)
+	else {
+		if (data[0] == 0) {
+			i_Constant = 0x00;
+		}		//if{data[0]==0)
+		else {
+			printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n");
+			return -EINVAL;
+		}		//else if(data[0]==0)
+	}			//elseif(data[0]==1)
+
+	 /*****************************************************/
+	/* Selects the mode specification register of port B */
+	 /*****************************************************/
+	outb(APCI1500_RW_PORT_B_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(APCI1500_RW_PORT_B_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+      /*********************************************/
+	/* Writes the new configuration (APCI1500_OR) */
+      /*********************************************/
+	i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR;
+
+	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+       /*****************************************************/
+	/* Selects the command and status register of port B */
+       /*****************************************************/
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/*****************************************/
+	/* Authorises the interrupt on the board */
+	/*****************************************/
+	outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/***************************************************/
+	/* Selects the pattern polarity register of port B */
+	/***************************************************/
+	outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/*****************************************************/
+	/* Selects the pattern transition register of port B */
+	/*****************************************************/
+	outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/***********************************************/
+	/* Selects the pattern mask register of port B */
+	/***********************************************/
+	outb(APCI1500_RW_PORT_B_PATTERN_MASK,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/*****************************************************/
+	/* Selects the command and status register of port A */
+	/*****************************************************/
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /***********************************/
+	/* Deletes the interrupt of port A */
+	 /***********************************/
+
+	i_RegValue = (i_RegValue & 0x0F) | 0x20;
+	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/*****************************************************/
+	/* Selects the command and status register of port  B */
+	/*****************************************************/
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /***********************************/
+	/* Deletes the interrupt of port B */
+	 /***********************************/
+
+	i_RegValue = (i_RegValue & 0x0F) | 0x20;
+	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/*****************************************************/
+	/* Selects the command and status register of timer 1 */
+	/*****************************************************/
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /***********************************/
+	/* Deletes the interrupt of timer 1 */
+	 /***********************************/
+
+	i_RegValue = (i_RegValue & 0x0F) | 0x20;
+	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	 /*****************************************************/
+	/* Selects the command and status register of timer 2 */
+	/*****************************************************/
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /***********************************/
+	/* Deletes the interrupt of timer 2 */
+	 /***********************************/
+
+	i_RegValue = (i_RegValue & 0x0F) | 0x20;
+	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/*****************************************************/
+	/* Selects the command and status register of timer 3 */
+	/*****************************************************/
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /***********************************/
+	/* Deletes the interrupt of timer 3 */
+	 /***********************************/
+
+	i_RegValue = (i_RegValue & 0x0F) | 0x20;
+	outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	 /*************************************************/
+	/* Selects the master interrupt control register */
+	 /*************************************************/
+	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/**********************************************/
+	/* Authorizes the main interrupt on the board */
+	/**********************************************/
+	outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+      /***************************/
+	/* Enables the PCI interrupt */
+      /*****************************/
+	outl(0x3000, devpriv->i_IobaseAmcc + 0x38);
+	ui_Status = inl(devpriv->i_IobaseAmcc + 0x10);
+	ui_Status = inl(devpriv->i_IobaseAmcc + 0x38);
+	outl(0x23000, devpriv->i_IobaseAmcc + 0x38);
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : static void v_APCI1500_Interrupt					     |
+|					  (int irq , void *d)      |
++----------------------------------------------------------------------------+
+| Task              : Interrupt handler                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq                 : irq number                   |
+|                     void *d                 : void pointer                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+static void v_APCI1500_Interrupt(int irq, void *d)
+{
+
+	struct comedi_device *dev = d;
+	UINT ui_InterruptStatus = 0;
+	int i_RegValue = 0;
+	i_InterruptMask = 0;
+
+ /***********************************/
+	/* Read the board interrupt status */
+ /***********************************/
+	ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38);
+
+  /***************************************/
+	/* Test if board generated a interrupt */
+  /***************************************/
+	if ((ui_InterruptStatus & 0x800000) == 0x800000) {
+      /************************/
+		/* Disable all Interrupt */
+      /************************/
+      /*************************************************/
+		/* Selects the master interrupt control register */
+      /*************************************************/
+		//outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER);
+	/**********************************************/
+		/* Disables  the main interrupt on the board */
+	/**********************************************/
+		//outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER);
+
+   /*****************************************************/
+		/* Selects the command and status register of port A */
+   /*****************************************************/
+		outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		i_RegValue =
+			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		if ((i_RegValue & 0x60) == 0x60) {
+	   /*****************************************************/
+			/* Selects the command and status register of port A */
+	   /*****************************************************/
+			outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+	    /***********************************/
+			/* Deletes the interrupt of port A */
+	    /***********************************/
+			i_RegValue = (i_RegValue & 0x0F) | 0x20;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_InterruptMask = i_InterruptMask | 1;
+			if (i_Logic == APCI1500_OR_PRIORITY) {
+				outb(APCI1500_RW_PORT_A_SPECIFICATION,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				i_RegValue =
+					inb(devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+	      /***************************************************/
+				/* Selects the interrupt vector register of port A */
+	      /***************************************************/
+				outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
+					devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+				i_RegValue =
+					inb(devpriv->iobase +
+					APCI1500_Z8536_CONTROL_REGISTER);
+
+				i_InputChannel = 1 + (i_RegValue >> 1);
+
+			}	// if(i_Logic==APCI1500_OR_PRIORITY)
+			else {
+				i_InputChannel = 0;
+			}	//elseif(i_Logic==APCI1500_OR_PRIORITY)
+		}		// if ((i_RegValue & 0x60) == 0x60)
+
+	   /*****************************************************/
+		/* Selects the command and status register of port B */
+	   /*****************************************************/
+		outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		i_RegValue =
+			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		if ((i_RegValue & 0x60) == 0x60) {
+	     /*****************************************************/
+			/* Selects the command and status register of port B */
+	     /*****************************************************/
+			outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+	     /***********************************/
+			/* Deletes the interrupt of port B */
+	     /***********************************/
+			i_RegValue = (i_RegValue & 0x0F) | 0x20;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			printk("\n\n\n");
+	     /****************/
+			/* Reads port B */
+	     /****************/
+			i_RegValue =
+				inb((UINT) devpriv->iobase +
+				APCI1500_Z8536_PORT_B);
+
+			i_RegValue = i_RegValue & 0xC0;
+	      /**************************************/
+			/* Tests if this is an external error */
+	      /**************************************/
+
+			if (i_RegValue) {
+				//Disable the interrupt
+		     /*****************************************************/
+				/* Selects the command and status register of port B */
+		     /*****************************************************/
+				outl(0x0, devpriv->i_IobaseAmcc + 0x38);
+
+				if (i_RegValue & 0x80) {
+					i_InterruptMask =
+						i_InterruptMask | 0x40;
+				}	//if (i_RegValue & 0x80)
+
+				if (i_RegValue & 0x40) {
+					i_InterruptMask =
+						i_InterruptMask | 0x80;
+				}	//if (i_RegValue & 0x40)
+			}	// if (i_RegValue)
+			else {
+				i_InterruptMask = i_InterruptMask | 2;
+			}	// if (i_RegValue)
+		}		//if ((i_RegValue & 0x60) == 0x60)
+
+		/*****************************************************/
+		/* Selects the command and status register of timer 1 */
+		/*****************************************************/
+		outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		i_RegValue =
+			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		if ((i_RegValue & 0x60) == 0x60) {
+		   /*****************************************************/
+			/* Selects the command and status register of timer 1 */
+		   /*****************************************************/
+			outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		   /***********************************/
+			/* Deletes the interrupt of timer 1 */
+		   /***********************************/
+			i_RegValue = (i_RegValue & 0x0F) | 0x20;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_InterruptMask = i_InterruptMask | 4;
+		}		// if ((i_RegValue & 0x60) == 0x60)
+		/*****************************************************/
+		/* Selects the command and status register of timer 2 */
+		/*****************************************************/
+		outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		i_RegValue =
+			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		if ((i_RegValue & 0x60) == 0x60) {
+		   /*****************************************************/
+			/* Selects the command and status register of timer 2 */
+		   /*****************************************************/
+			outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		   /***********************************/
+			/* Deletes the interrupt of timer 2 */
+		   /***********************************/
+			i_RegValue = (i_RegValue & 0x0F) | 0x20;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			i_InterruptMask = i_InterruptMask | 8;
+		}		// if ((i_RegValue & 0x60) == 0x60)
+
+		/*****************************************************/
+		/* Selects the command and status register of timer 3 */
+		/*****************************************************/
+		outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		i_RegValue =
+			inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+		if ((i_RegValue & 0x60) == 0x60) {
+		   /*****************************************************/
+			/* Selects the command and status register of timer 3 */
+		   /*****************************************************/
+			outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+		   /***********************************/
+			/* Deletes the interrupt of timer 3 */
+		   /***********************************/
+			i_RegValue = (i_RegValue & 0x0F) | 0x20;
+			outb(i_RegValue,
+				devpriv->iobase +
+				APCI1500_Z8536_CONTROL_REGISTER);
+			if (i_CounterLogic == APCI1500_COUNTER) {
+				i_InterruptMask = i_InterruptMask | 0x10;
+			}	//if(i_CounterLogic==APCI1500_COUNTER)
+			else {
+				i_InterruptMask = i_InterruptMask | 0x20;
+			}
+		}		// if ((i_RegValue & 0x60) == 0x60)
+
+		send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+	       /***********************/
+		/* Enable all Interrupts */
+	       /***********************/
+
+	       /*************************************************/
+		/* Selects the master interrupt control register */
+	       /*************************************************/
+		outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+			devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	       /**********************************************/
+		/* Authorizes the main interrupt on the board */
+	       /**********************************************/
+		outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	}			//  if ((ui_InterruptStatus & 0x800000) == 0x800000)
+	else {
+		printk("\nInterrupt from unknown source\n");
+
+	}			//else if ((ui_InterruptStatus & 0x800000) == 0x800000)
+	return;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1500_Reset(struct comedi_device *dev)               |                                                       |
++----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1500_Reset(struct comedi_device * dev)
+{
+	int i_DummyRead = 0;
+	i_TimerCounter1Init = 0;
+	i_TimerCounter2Init = 0;
+	i_WatchdogCounter3Init = 0;
+	i_Event1Status = 0;
+	i_Event2Status = 0;
+	i_TimerCounterWatchdogInterrupt = 0;
+	i_Logic = 0;
+	i_CounterLogic = 0;
+	i_InterruptMask = 0;
+	i_InputChannel = 0;;
+	i_TimerCounter1Enabled = 0;
+	i_TimerCounter2Enabled = 0;
+	i_WatchdogCounter3Enabled = 0;
+
+    /******************/
+	/* Software reset */
+    /******************/
+	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+ /*****************************************************/
+	/* Selects the master configuration control register */
+ /*****************************************************/
+	outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/*****************************************************/
+	/* Selects the mode specification register of port A */
+	/*****************************************************/
+	outb(APCI1500_RW_PORT_A_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/* Selects the data path polarity register of port A */
+	outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* High level of port A means 1 */
+	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	/* Selects the data direction register of port A */
+	outb(APCI1500_RW_PORT_A_DATA_DIRECTION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* All bits used as inputs */
+	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of port A */
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/*  Selects the command and status register of port A */
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates the interrupt management of port A:  */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the handshake specification register of port A */
+	outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes the register */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	 /*****************************************************/
+	/* Selects the mode specification register of port B */
+	 /*****************************************************/
+	outb(APCI1500_RW_PORT_B_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the data path polarity register of port B */
+	outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* A high level of port B means 1 */
+	outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the data direction register of port B */
+	outb(APCI1500_RW_PORT_B_DATA_DIRECTION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* All bits used as inputs */
+	outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of port B */
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of port B */
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates the interrupt management of port B:         */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the handshake specification register of port B */
+	outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes the register */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+
+	   /*****************************************************/
+	/* Selects the data path polarity register of port C */
+	   /*****************************************************/
+	outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* High level of port C means 1 */
+	outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the data direction register of port C */
+	outb(APCI1500_RW_PORT_C_DATA_DIRECTION,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* All bits used as inputs except channel 1 */
+	outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the special IO register of port C */
+	outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes it */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	   /******************************************************/
+	/* Selects the command and status register of timer 1 */
+	   /******************************************************/
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of timer 1 */
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates the interrupt management of timer 1         */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	   /******************************************************/
+	/* Selects the command and status register of timer 2 */
+	   /******************************************************/
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of timer 2 */
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates Timer 2 interrupt management:               */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	  /******************************************************/
+	/* Selects the command and status register of timer 3 */
+	  /******************************************************/
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes IP and IUS */
+	outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Selects the command and status register of Timer 3 */
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deactivates interrupt management of timer 3:            */
+	outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	 /*************************************************/
+	/* Selects the master interrupt control register */
+	 /*************************************************/
+	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	/* Deletes all interrupts */
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	//reset all the digital outputs
+	outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
+/*******************************/
+/* Disable the board interrupt */
+/*******************************/
+ /*************************************************/
+	/* Selects the master interrupt control register */
+ /*************************************************/
+	outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/****************************/
+/* Deactivates all interrupts */
+/******************************/
+	outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+ /*****************************************************/
+	/* Selects the command and status register of port A */
+ /*****************************************************/
+	outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/****************************/
+/* Deactivates all interrupts */
+/******************************/
+	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/*****************************************************/
+	/* Selects the command and status register of port B */
+ /*****************************************************/
+	outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/****************************/
+/* Deactivates all interrupts */
+/******************************/
+	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/*****************************************************/
+	/* Selects the command and status register of timer 1 */
+ /*****************************************************/
+	outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/****************************/
+/* Deactivates all interrupts */
+/******************************/
+	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/*****************************************************/
+	/* Selects the command and status register of timer 2 */
+ /*****************************************************/
+	outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/****************************/
+/* Deactivates all interrupts */
+/******************************/
+	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/*****************************************************/
+/* Selects the command and status register of timer 3*/
+/*****************************************************/
+	outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
+		devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+/****************************/
+/* Deactivates all interrupts */
+/******************************/
+	outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
+	return 0;
+}

+ 165 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h

@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/*********      Definitions for APCI-1500 card  *****/
+
+// Card Specific information
+#define APCI1500_BOARD_VENDOR_ID           0x10e8
+#define APCI1500_ADDRESS_RANGE              4
+
+//DIGITAL INPUT-OUTPUT DEFINE
+
+#define  APCI1500_DIGITAL_OP                 	2
+#define  APCI1500_DIGITAL_IP                    0
+#define  APCI1500_AND               		    2
+#define  APCI1500_OR                		    4
+#define  APCI1500_OR_PRIORITY       		    6
+#define  APCI1500_CLK_SELECT                    0
+#define  COUNTER1                               0
+#define  COUNTER2                               1
+#define  COUNTER3                               2
+#define  APCI1500_COUNTER                		0x20
+#define  APCI1500_TIMER                  		0
+#define  APCI1500_WATCHDOG          		    0
+#define  APCI1500_SINGLE            		    0
+#define  APCI1500_CONTINUOUS        		    0x80
+#define  APCI1500_DISABLE                		0
+#define  APCI1500_ENABLE                		1
+#define  APCI1500_SOFTWARE_TRIGGER  		    0x4
+#define  APCI1500_HARDWARE_TRIGGER  		    0x10
+#define  APCI1500_SOFTWARE_GATE     		    0
+#define  APCI1500_HARDWARE_GATE     		    0x8
+#define  START                       		    0
+#define  STOP                       		    1
+#define  TRIGGER                       		    2
+
+/*
+ * Zillog I/O enumeration
+ */
+enum {
+	APCI1500_Z8536_PORT_C,
+	APCI1500_Z8536_PORT_B,
+	APCI1500_Z8536_PORT_A,
+	APCI1500_Z8536_CONTROL_REGISTER
+};
+
+/*
+ * Z8536 CIO Internal Address
+ */
+enum {
+	APCI1500_RW_MASTER_INTERRUPT_CONTROL,
+	APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
+	APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
+	APCI1500_RW_PORT_B_INTERRUPT_CONTROL,
+	APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR,
+	APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
+	APCI1500_RW_PORT_C_DATA_DIRECTION,
+	APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
+
+	APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
+	APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
+	APCI1500_RW_CPT_TMR1_CMD_STATUS,
+	APCI1500_RW_CPT_TMR2_CMD_STATUS,
+	APCI1500_RW_CPT_TMR3_CMD_STATUS,
+	APCI1500_RW_PORT_A_DATA,
+	APCI1500_RW_PORT_B_DATA,
+	APCI1500_RW_PORT_C_DATA,
+
+	APCI1500_R_CPT_TMR1_VALUE_HIGH,
+	APCI1500_R_CPT_TMR1_VALUE_LOW,
+	APCI1500_R_CPT_TMR2_VALUE_HIGH,
+	APCI1500_R_CPT_TMR2_VALUE_LOW,
+	APCI1500_R_CPT_TMR3_VALUE_HIGH,
+	APCI1500_R_CPT_TMR3_VALUE_LOW,
+	APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
+	APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
+	APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
+	APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
+	APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
+	APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
+	APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
+	APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
+	APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
+	APCI1500_R_CURRENT_VECTOR,
+
+	APCI1500_RW_PORT_A_SPECIFICATION,
+	APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
+	APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
+	APCI1500_RW_PORT_A_DATA_DIRECTION,
+	APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL,
+	APCI1500_RW_PORT_A_PATTERN_POLARITY,
+	APCI1500_RW_PORT_A_PATTERN_TRANSITION,
+	APCI1500_RW_PORT_A_PATTERN_MASK,
+
+	APCI1500_RW_PORT_B_SPECIFICATION,
+	APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
+	APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
+	APCI1500_RW_PORT_B_DATA_DIRECTION,
+	APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL,
+	APCI1500_RW_PORT_B_PATTERN_POLARITY,
+	APCI1500_RW_PORT_B_PATTERN_TRANSITION,
+	APCI1500_RW_PORT_B_PATTERN_MASK
+};
+
+ /*----------DIGITAL INPUT----------------*/
+static int i_APCI1500_Initialisation(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev,
+					      struct comedi_subdevice *s,
+					      struct comedi_insn *insn,
+					      unsigned int *data);
+
+static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);
+static int i_APCI1500_ReadMoreDigitalInput(struct comedi_device *dev,
+					   struct comedi_subdevice *s,
+					   struct comedi_insn *insn, unsigned int *data);
+
+/*----------	DIGITAL OUTPUT------------*/
+static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev,
+							struct comedi_subdevice *s,
+							struct comedi_insn *insn,
+							unsigned int *data);
+static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+
+/*----------TIMER----------------*/
+static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev,
+						 struct comedi_subdevice *s,
+						 struct comedi_insn *insn,
+						 unsigned int *data);
+static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev,
+							   struct comedi_subdevice *s,
+							   struct comedi_insn *insn,
+							   unsigned int *data);
+static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev,
+					       struct comedi_subdevice *s,
+					       struct comedi_insn *insn,
+					       unsigned int *data);
+static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev,
+					struct comedi_subdevice *s,
+					struct comedi_insn *insn, unsigned int *data);
+
+/*----------INTERRUPT HANDLER------*/
+static void v_APCI1500_Interrupt(int irq, void *d);
+static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+/*----------RESET---------------*/
+static int i_APCI1500_Reset(struct comedi_device *dev);

+ 542 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c

@@ -0,0 +1,542 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-1516       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci1516.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-1516                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci1516.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_Read1DigitalInput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the digital input                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|		       struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure     |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1516_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_TmpValue = 0;
+	UINT ui_Channel;
+	ui_Channel = CR_CHAN(insn->chanspec);
+	if (ui_Channel >= 0 && ui_Channel <= 7) {
+		ui_TmpValue = (UINT) inw(devpriv->iobase + APCI1516_DIGITAL_IP);
+		//  since only 1 channel reqd  to bring it to last bit it is rotated
+		//  8 +(chan - 1) times then ANDed with 1 for last bit.
+		*data = (ui_TmpValue >> ui_Channel) & 0x1;
+	}			//if(ui_Channel >= 0 && ui_Channel <=7)
+	else {
+		//comedi_error(dev," \n chan spec wrong\n");
+		return -EINVAL;	// "sorry channel spec wrong "
+	}			//else if(ui_Channel >= 0 && ui_Channel <=7)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_ReadMoreDigitalInput                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                     struct comedi_insn *insn,unsigned int *data)                      |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the Requested digital inputs      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                      struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure     |
+|                      unsigned int *data         : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ui_PortValue = data[0];
+	UINT ui_Mask = 0;
+	UINT ui_NoOfChannels;
+
+	ui_NoOfChannels = CR_CHAN(insn->chanspec);
+
+	*data = (UINT) inw(devpriv->iobase + APCI1516_DIGITAL_IP);
+	switch (ui_NoOfChannels) {
+	case 2:
+		ui_Mask = 3;
+		*data = (*data >> (2 * ui_PortValue)) & ui_Mask;
+		break;
+	case 4:
+		ui_Mask = 15;
+		*data = (*data >> (4 * ui_PortValue)) & ui_Mask;
+		break;
+	case 7:
+		break;
+
+	default:
+		printk("\nWrong parameters\n");
+		return -EINVAL;	// "sorry channel spec wrong "
+		break;
+	}			//switch(ui_NoOfChannels)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_ConfigDigitalOutput (struct comedi_device *dev,
+                    struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data)    |
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Digital Output Subdevice.               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     unsigned int *data         : Data Pointer contains         |
+|                                          configuration parameters as below |
+|                      struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure                                                           |
+|					  data[0]  :1:Memory on                          |
+|					            0:Memory off                         |
+|										                             |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI1516_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	devpriv->b_OutputMemoryStatus = data[0];
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_WriteDigitalOutput                      |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                     unsigned int *data)                                         |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                    unsigned int *data           : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1516_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp, ui_Temp1;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+
+	printk("EL311003 : @=%x\n", devpriv->iobase + APCI1516_DIGITAL_OP);
+
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp = inw(devpriv->iobase + APCI1516_DIGITAL_OP);
+
+	}			//if(devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			//if(devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outw(data[0], devpriv->iobase + APCI1516_DIGITAL_OP);
+
+			printk("EL311003 : d=%d @=%x\n", data[0],
+				devpriv->iobase + APCI1516_DIGITAL_OP);
+
+		}		//if(data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 4:
+					data[0] =
+						(data[0] << (4 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 7:
+					data[0] = data[0] | ui_Temp;
+					break;
+
+				default:
+					comedi_error(dev, " chan spec wrong");
+					return -EINVAL;	// "sorry channel spec wrong "
+
+				}	//switch(ui_NoOfChannels)
+
+				outw(data[0],
+					devpriv->iobase + APCI1516_DIGITAL_OP);
+
+				printk("EL311003 : d=%d @=%x\n", data[0],
+					devpriv->iobase + APCI1516_DIGITAL_OP);
+			}	// if(data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	//else if(data[1]==1)
+		}		//elseif(data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] = (data[0] << ui_NoOfChannel) ^ 0xff;
+				data[0] = data[0] & ui_Temp;
+				outw(data[0],
+					devpriv->iobase + APCI1516_DIGITAL_OP);
+
+				printk("EL311003 : d=%d @=%x\n", data[0],
+					devpriv->iobase + APCI1516_DIGITAL_OP);
+
+			}	//if(data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xff) & ui_Temp;
+						break;
+
+					case 4:
+						data[0] = ~data[0] & 0xf;
+						ui_Temp1 = 15;
+						ui_Temp1 =
+							ui_Temp1 << 4 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (4 *
+									data
+									[2])) ^
+							0xff) & ui_Temp;
+						break;
+
+					case 7:
+						break;
+
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+
+					}	//switch(ui_NoOfChannels)
+
+					outw(data[0],
+						devpriv->iobase +
+						APCI1516_DIGITAL_OP);
+
+					printk("EL311003 : d=%d @=%x\n",
+						data[0],
+						devpriv->iobase +
+						APCI1516_DIGITAL_OP);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	return (insn->n);;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_ReadDigitalOutput                       |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data) 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1516_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ui_Temp;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+	ui_Temp = data[0];
+	*data = inw(devpriv->iobase + APCI1516_DIGITAL_OP_RW);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			//if(ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			switch (ui_NoOfChannel) {
+
+			case 2:
+				*data = (*data >> (2 * data[1])) & 3;
+				break;
+
+			case 4:
+				*data = (*data >> (4 * data[1])) & 15;
+				break;
+
+			case 7:
+				break;
+
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+
+			}	//switch(ui_NoOfChannels)
+		}		//if(ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		//elseif(ui_Temp==1)
+	}			//elseif(ui_Temp==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_ConfigWatchdog(struct comedi_device *dev,
+                      struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)  |
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Watchdog                                |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status                                                     |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI1516_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if (data[0] == 0) {
+		//Disable the watchdog
+		outw(0x0,
+			devpriv->i_IobaseAddon +
+			APCI1516_WATCHDOG_ENABLEDISABLE);
+		//Loading the Reload value
+		outw(data[1],
+			devpriv->i_IobaseAddon +
+			APCI1516_WATCHDOG_RELOAD_VALUE);
+		data[1] = data[1] >> 16;
+		outw(data[1],
+			devpriv->i_IobaseAddon +
+			APCI1516_WATCHDOG_RELOAD_VALUE + 2);
+	}			//if(data[0]==0)
+	else {
+		printk("\nThe input parameters are wrong\n");
+		return -EINVAL;
+	}			//elseif(data[0]==0)
+
+	return insn->n;
+}
+
+ /*
+    +----------------------------------------------------------------------------+
+    | Function   Name   : int i_APCI1516_StartStopWriteWatchdog                  |
+    |                           (struct comedi_device *dev,struct comedi_subdevice *s,
+    struct comedi_insn *insn,unsigned int *data);                      |
+    +----------------------------------------------------------------------------+
+    | Task              : Start / Stop The Watchdog                              |
+    +----------------------------------------------------------------------------+
+    | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+    |                     struct comedi_subdevice *s,   :pointer to subdevice structure
+    struct comedi_insn *insn      :pointer to insn structure      |
+    |                     unsigned int *data          : Data Pointer to read status  |
+    +----------------------------------------------------------------------------+
+    | Output Parameters :       --                                                                                                       |
+    +----------------------------------------------------------------------------+
+    | Return Value      : TRUE  : No error occur                                 |
+    |                       : FALSE : Error occur. Return the error          |
+    |                                                                            |
+    +----------------------------------------------------------------------------+
+  */
+
+int i_APCI1516_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	switch (data[0]) {
+	case 0:		//stop the watchdog
+		outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE);	//disable the watchdog
+		break;
+	case 1:		//start the watchdog
+		outw(0x0001,
+			devpriv->i_IobaseAddon +
+			APCI1516_WATCHDOG_ENABLEDISABLE);
+		break;
+	case 2:		//Software trigger
+		outw(0x0201,
+			devpriv->i_IobaseAddon +
+			APCI1516_WATCHDOG_ENABLEDISABLE);
+		break;
+	default:
+		printk("\nSpecified functionality does not exist\n");
+		return -EINVAL;
+	}			// switch(data[0])
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_ReadWatchdog                            |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data); 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Watchdog                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI1516_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	data[0] = inw(devpriv->i_IobaseAddon + APCI1516_WATCHDOG_STATUS) & 0x1;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1516_Reset(struct comedi_device *dev)               |                                                                                                          |
++----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1516_Reset(struct comedi_device * dev)
+{
+	outw(0x0, devpriv->iobase + APCI1516_DIGITAL_OP);	//RESETS THE DIGITAL OUTPUTS
+	outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE);
+	outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE);
+	outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE + 2);
+	return 0;
+}

+ 64 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h

@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/*********      Definitions for APCI-1516 card  *****/
+
+// Card Specific information
+#define APCI1516_BOARD_VENDOR_ID                 0x15B8
+#define APCI1516_ADDRESS_RANGE                   8
+
+//DIGITAL INPUT-OUTPUT DEFINE
+
+#define APCI1516_DIGITAL_OP                 	4
+#define APCI1516_DIGITAL_OP_RW                 	4
+#define APCI1516_DIGITAL_IP                     0
+
+// TIMER COUNTER WATCHDOG DEFINES
+
+#define ADDIDATA_WATCHDOG                          2
+#define APCI1516_DIGITAL_OP_WATCHDOG               0
+#define APCI1516_WATCHDOG_ENABLEDISABLE            12
+#define APCI1516_WATCHDOG_RELOAD_VALUE             4
+#define APCI1516_WATCHDOG_STATUS                   16
+
+// Hardware Layer  functions for Apci1516
+
+//Digital Input
+INT i_APCI1516_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+//Digital Output
+int i_APCI1516_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1516_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+// TIMER
+// timer value is passed as u seconds
+int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+int i_APCI1516_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_insn *insn, unsigned int *data);
+int i_APCI1516_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data);
+
+//reset
+INT i_APCI1516_Reset(struct comedi_device *dev);

+ 1105 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c

@@ -0,0 +1,1105 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-1564       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci1564.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-1564                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include <linux/delay.h>
+#include "hwdrv_apci1564.h"
+
+//Global variables
+UINT ui_InterruptStatus_1564 = 0;
+UINT ui_InterruptData, ui_Type;
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_ConfigDigitalInput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures the digital input Subdevice                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     unsigned int *data         : Data Pointer contains         |
+|                                          configuration parameters as below |
+|                                                                            |
+|			  data[0]            : 1 Enable  Digital Input Interrupt |
+|								   0 Disable Digital Input Interrupt |
+|			  data[1]            : 0 ADDIDATA Interrupt OR LOGIC	 |
+|								 : 1 ADDIDATA Interrupt AND LOGIC    |
+|			  data[2]			 : Interrupt mask for the mode 1	 |
+|			  data[3]			 : Interrupt mask for the mode 2	 |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_ConfigDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	devpriv->tsk_Current = current;
+   /*******************************/
+	/* Set the digital input logic */
+   /*******************************/
+	if (data[0] == ADDIDATA_ENABLE) {
+		data[2] = data[2] << 4;
+		data[3] = data[3] << 4;
+		outl(data[2],
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_INTERRUPT_MODE1);
+		outl(data[3],
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
+		if (data[1] == ADDIDATA_OR) {
+			outl(0x4,
+				devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+				APCI1564_DIGITAL_IP_IRQ);
+		}		// if  (data[1] == ADDIDATA_OR)
+		else {
+			outl(0x6,
+				devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+				APCI1564_DIGITAL_IP_IRQ);
+		}		// else if  (data[1] == ADDIDATA_OR)
+	}			// if  (data[0] == ADDIDATA_ENABLE)
+	else {
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_INTERRUPT_MODE1);
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_IRQ);
+	}			// else if  (data[0] == ADDIDATA_ENABLE)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_Read1DigitalInput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the digital input                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|		              UINT ui_Channel : Channel number to read       |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_TmpValue = 0;
+	UINT ui_Channel;
+
+	ui_Channel = CR_CHAN(insn->chanspec);
+	if (ui_Channel >= 0 && ui_Channel <= 31) {
+		ui_TmpValue =
+			(UINT) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP);
+		//  since only 1 channel reqd  to bring it to last bit it is rotated
+		//  8 +(chan - 1) times then ANDed with 1 for last bit.
+		*data = (ui_TmpValue >> ui_Channel) & 0x1;
+	}			// if  (ui_Channel >= 0 && ui_Channel <=31)
+	else {
+		comedi_error(dev, "Not a valid channel number !!! \n");
+		return -EINVAL;	// "sorry channel spec wrong "
+	}			//else if  (ui_Channel >= 0 && ui_Channel <=31)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_ReadMoreDigitalInput                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                     struct comedi_insn *insn,unsigned int *data)                      |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the Requested digital inputs      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To be Read    |
+|                      UINT *data             : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_PortValue = data[0];
+	UINT ui_Mask = 0;
+	UINT ui_NoOfChannels;
+
+	ui_NoOfChannels = CR_CHAN(insn->chanspec);
+	if (data[1] == 0) {
+		*data = (UINT) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP);
+		switch (ui_NoOfChannels) {
+		case 2:
+			ui_Mask = 3;
+			*data = (*data >> (2 * ui_PortValue)) & ui_Mask;
+			break;
+		case 4:
+			ui_Mask = 15;
+			*data = (*data >> (4 * ui_PortValue)) & ui_Mask;
+			break;
+		case 8:
+			ui_Mask = 255;
+			*data = (*data >> (8 * ui_PortValue)) & ui_Mask;
+			break;
+		case 16:
+			ui_Mask = 65535;
+			*data = (*data >> (16 * ui_PortValue)) & ui_Mask;
+			break;
+		case 31:
+			break;
+		default:
+			comedi_error(dev, "Not a valid Channel number !!!\n");
+			return -EINVAL;	// "sorry channel spec wrong "
+			break;
+		}		// switch  (ui_NoOfChannels)
+	}			// if  (data[1]==0)
+	else {
+		if (data[1] == 1) {
+			*data = ui_InterruptStatus_1564;
+		}		// if  (data[1]==1)
+	}			// else if  (data[1]==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_ConfigDigitalOutput                     |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Digital Output Subdevice.               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[1]            : 1 Enable  VCC  Interrupt  |
+|										   0 Disable VCC  Interrupt  |
+|					  data[2]            : 1 Enable  CC  Interrupt   |
+|										   0 Disable CC  Interrupt   |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command = 0;
+
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}			// if  ((data[0]!=0) && (data[0]!=1))
+	if (data[0]) {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
+	}			// if  (data[0])
+	else {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
+	}			// else if  (data[0])
+	if (data[1] == ADDIDATA_ENABLE) {
+		ul_Command = ul_Command | 0x1;
+	}			// if  (data[1] == ADDIDATA_ENABLE)
+	else {
+		ul_Command = ul_Command & 0xFFFFFFFE;
+	}			// else if  (data[1] == ADDIDATA_ENABLE)
+	if (data[2] == ADDIDATA_ENABLE) {
+		ul_Command = ul_Command | 0x2;
+	}			// if  (data[2] == ADDIDATA_ENABLE)
+	else {
+		ul_Command = ul_Command & 0xFFFFFFFD;
+	}			// else if  (data[2] == ADDIDATA_ENABLE)
+	outl(ul_Command,
+		devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+		APCI1564_DIGITAL_OP_INTERRUPT);
+	ui_InterruptData =
+		inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+		APCI1564_DIGITAL_OP_INTERRUPT);
+	devpriv->tsk_Current = current;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_WriteDigitalOutput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To Write      |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp, ui_Temp1;
+	UINT ui_NoOfChannel;
+
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp =
+			inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+			APCI1564_DIGITAL_OP_RW);
+	}			// if  (devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			// else if  (devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outl(data[0],
+				devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+				APCI1564_DIGITAL_OP_RW);
+		}		// if  (data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+				case 4:
+					data[0] =
+						(data[0] << (4 *
+							data[2])) | ui_Temp;
+					break;
+				case 8:
+					data[0] =
+						(data[0] << (8 *
+							data[2])) | ui_Temp;
+					break;
+				case 16:
+					data[0] =
+						(data[0] << (16 *
+							data[2])) | ui_Temp;
+					break;
+				case 31:
+					data[0] = data[0] | ui_Temp;
+					break;
+				default:
+					comedi_error(dev, " chan spec wrong");
+					return -EINVAL;	// "sorry channel spec wrong "
+				}	// switch (ui_NoOfChannels)
+				outl(data[0],
+					devpriv->i_IobaseAmcc +
+					APCI1564_DIGITAL_OP +
+					APCI1564_DIGITAL_OP_RW);
+			}	// if  (data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	// else if  (data[1]==1)
+		}		// else if (data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] =
+					(data[0] << ui_NoOfChannel) ^
+					0xffffffff;
+				data[0] = data[0] & ui_Temp;
+				outl(data[0],
+					devpriv->i_IobaseAmcc +
+					APCI1564_DIGITAL_OP +
+					APCI1564_DIGITAL_OP_RW);
+			}	// if  (data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+					case 4:
+						data[0] = ~data[0] & 0xf;
+						ui_Temp1 = 15;
+						ui_Temp1 =
+							ui_Temp1 << 4 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (4 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+					case 8:
+						data[0] = ~data[0] & 0xff;
+						ui_Temp1 = 255;
+						ui_Temp1 =
+							ui_Temp1 << 8 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (8 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+					case 16:
+						data[0] = ~data[0] & 0xffff;
+						ui_Temp1 = 65535;
+						ui_Temp1 =
+							ui_Temp1 << 16 *
+							data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (16 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+					case 31:
+						break;
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+					}	//switch(ui_NoOfChannels)
+					outl(data[0],
+						devpriv->i_IobaseAmcc +
+						APCI1564_DIGITAL_OP +
+						APCI1564_DIGITAL_OP_RW);
+				}	// if  (data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	// else if  (data[1]==1)
+			}	// else if  (data[1]==0)
+		}		// if  (data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		// else if (data[3]==1)
+	}			// else if (data[3]==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_ReadDigitalOutput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To read       |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp;
+	UINT ui_NoOfChannel;
+
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	ui_Temp = data[0];
+	*data = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+		APCI1564_DIGITAL_OP_RW);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			// if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			switch (ui_NoOfChannel) {
+			case 2:
+				*data = (*data >> (2 * data[1])) & 3;
+				break;
+
+			case 4:
+				*data = (*data >> (4 * data[1])) & 15;
+				break;
+
+			case 8:
+				*data = (*data >> (8 * data[1])) & 255;
+				break;
+
+			case 16:
+				*data = (*data >> (16 * data[1])) & 65535;
+				break;
+
+			case 31:
+				break;
+
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+				break;
+			}	// switch(ui_NoOfChannels)
+		}		// if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		// else if (ui_Temp==1)
+	}			// else if  (ui_Temp==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_ConfigTimerCounterWatchdog              |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Timer , Counter or Watchdog             |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[0]            : 0 Configure As Timer      |
+|										   1 Configure As Counter    |
+|										   2 Configure As Watchdog   |
+|					  data[1]            : 1 Enable  Interrupt       |
+|										   0 Disable Interrupt 	     |
+|					  data[2]            : Time Unit                 |
+|					  data[3]			 : Reload Value			     |
+|					  data[4]            : Timer Mode             	 |
+|					  data[5]			 : Timer Counter Watchdog Number|
+                              data[6]            :  Counter Direction
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command1 = 0;
+	devpriv->tsk_Current = current;
+	if (data[0] == ADDIDATA_WATCHDOG) {
+		devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG;
+
+		//Disable the watchdog
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
+			APCI1564_TCW_PROG);
+		//Loading the Reload value
+		outl(data[3],
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
+			APCI1564_TCW_RELOAD_VALUE);
+	}			// if  (data[0]==ADDIDATA_WATCHDOG)
+	else if (data[0] == ADDIDATA_TIMER) {
+		//First Stop The Timer
+		ul_Command1 =
+			inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_PROG);
+		ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
+		outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);	//Stop The Timer
+
+		devpriv->b_TimerSelectMode = ADDIDATA_TIMER;
+		if (data[1] == 1) {
+			outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);	//Enable TIMER int & DISABLE ALL THE OTHER int SOURCES
+			outl(0x0,
+				devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+				APCI1564_DIGITAL_IP_IRQ);
+			outl(0x0,
+				devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+				APCI1564_DIGITAL_OP_IRQ);
+			outl(0x0,
+				devpriv->i_IobaseAmcc +
+				APCI1564_DIGITAL_OP_WATCHDOG +
+				APCI1564_TCW_IRQ);
+			outl(0x0,
+				devpriv->iobase + APCI1564_COUNTER1 +
+				APCI1564_TCW_IRQ);
+			outl(0x0,
+				devpriv->iobase + APCI1564_COUNTER2 +
+				APCI1564_TCW_IRQ);
+			outl(0x0,
+				devpriv->iobase + APCI1564_COUNTER3 +
+				APCI1564_TCW_IRQ);
+			outl(0x0,
+				devpriv->iobase + APCI1564_COUNTER4 +
+				APCI1564_TCW_IRQ);
+		}		// if  (data[1]==1)
+		else {
+			outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);	//disable Timer interrupt
+		}		// else if  (data[1]==1)
+
+		// Loading Timebase
+
+		outl(data[2],
+			devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_TIMEBASE);
+
+		//Loading the Reload value
+		outl(data[3],
+			devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_RELOAD_VALUE);
+
+		ul_Command1 =
+			inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_PROG);
+		ul_Command1 =
+			(ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
+		outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);	//mode 2
+	}			// else if  (data[0]==ADDIDATA_TIMER)
+	else if (data[0] == ADDIDATA_COUNTER) {
+		devpriv->b_TimerSelectMode = ADDIDATA_COUNTER;
+		devpriv->b_ModeSelectRegister = data[5];
+
+		//First Stop The Counter
+		ul_Command1 =
+			inl(devpriv->iobase + ((data[5] - 1) * 0x20) +
+			APCI1564_TCW_PROG);
+		ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
+		outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG);	//Stop The Timer
+
+      /************************/
+		/* Set the reload value */
+      /************************/
+		outl(data[3],
+			devpriv->iobase + ((data[5] - 1) * 0x20) +
+			APCI1564_TCW_RELOAD_VALUE);
+
+      /******************************/
+		/* Set the mode :             */
+		/* - Disable the hardware     */
+		/* - Disable the counter mode */
+		/* - Disable the warning      */
+		/* - Disable the reset        */
+		/* - Disable the timer mode   */
+		/* - Enable the counter mode  */
+      /******************************/
+		ul_Command1 =
+			(ul_Command1 & 0xFFFC19E2UL) | 0x80000UL |
+			(ULONG) ((ULONG) data[4] << 16UL);
+		outl(ul_Command1,
+			devpriv->iobase + ((data[5] - 1) * 0x20) +
+			APCI1564_TCW_PROG);
+
+		// Enable or Disable Interrupt
+		ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1);
+		outl(ul_Command1,
+			devpriv->iobase + ((data[5] - 1) * 0x20) +
+			APCI1564_TCW_PROG);
+
+      /*****************************/
+		/* Set the Up/Down selection */
+      /*****************************/
+		ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18);
+		outl(ul_Command1,
+			devpriv->iobase + ((data[5] - 1) * 0x20) +
+			APCI1564_TCW_PROG);
+	}			// else if  (data[0]==ADDIDATA_COUNTER)
+	else {
+		printk(" Invalid subdevice.");
+	}			// else if  (data[0]==ADDIDATA_WATCHDOG)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_StartStopWriteTimerCounterWatchdog      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Start / Stop The Selected Timer , Counter or Watchdog  |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[0]            : 0 Timer                   |
+|										   1 Counter                 |
+|										   2 Watchdog        		 |                             |					         data[1]            : 1 Start                   |
+|										   0 Stop                    |
+|                                                  2 Trigger             	 |
+|                                                    Clear (Only Counter)    |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command1 = 0;
+	if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+		switch (data[1]) {
+		case 0:	//stop the watchdog
+			outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG);	//disable the watchdog
+			break;
+		case 1:	//start the watchdog
+			outl(0x0001,
+				devpriv->i_IobaseAmcc +
+				APCI1564_DIGITAL_OP_WATCHDOG +
+				APCI1564_TCW_PROG);
+			break;
+		case 2:	//Software trigger
+			outl(0x0201,
+				devpriv->i_IobaseAmcc +
+				APCI1564_DIGITAL_OP_WATCHDOG +
+				APCI1564_TCW_PROG);
+			break;
+		default:
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		// switch (data[1])
+	}			// if  (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG)
+	if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+		if (data[1] == 1) {
+			ul_Command1 =
+				inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+				APCI1564_TCW_PROG);
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
+
+			//Enable the Timer
+			outl(ul_Command1,
+				devpriv->i_IobaseAmcc + APCI1564_TIMER +
+				APCI1564_TCW_PROG);
+		}		// if  (data[1]==1)
+		else if (data[1] == 0) {
+			//Stop The Timer
+
+			ul_Command1 =
+				inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+				APCI1564_TCW_PROG);
+			ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
+			outl(ul_Command1,
+				devpriv->i_IobaseAmcc + APCI1564_TIMER +
+				APCI1564_TCW_PROG);
+		}		// else if(data[1]==0)
+	}			// if  (devpriv->b_TimerSelectMode==ADDIDATA_TIMER)
+	if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
+		ul_Command1 =
+			inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
+					1) * 0x20) + APCI1564_TCW_PROG);
+		if (data[1] == 1) {
+			//Start the Counter subdevice
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
+		}		// if  (data[1] == 1)
+		else if (data[1] == 0) {
+			// Stops the Counter subdevice
+			ul_Command1 = 0;
+
+		}		// else if  (data[1] == 0)
+		else if (data[1] == 2) {
+			// Clears the Counter subdevice
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400;
+		}		// else if  (data[1] == 3)
+		outl(ul_Command1,
+			devpriv->iobase + ((devpriv->b_ModeSelectRegister -
+					1) * 0x20) + APCI1564_TCW_PROG);
+	}			// if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_ReadTimerCounterWatchdog                |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Selected Timer , Counter or Watchdog          |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command1 = 0;
+
+	if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+		// Stores the status of the Watchdog
+		data[0] =
+			inl(devpriv->i_IobaseAmcc +
+			APCI1564_DIGITAL_OP_WATCHDOG +
+			APCI1564_TCW_TRIG_STATUS) & 0x1;
+		data[1] =
+			inl(devpriv->i_IobaseAmcc +
+			APCI1564_DIGITAL_OP_WATCHDOG);
+	}			// if  (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG)
+	else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+		// Stores the status of the Timer
+		data[0] =
+			inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_TRIG_STATUS) & 0x1;
+
+		// Stores the Actual value of the Timer
+		data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER);
+	}			// else if  (devpriv->b_TimerSelectMode==ADDIDATA_TIMER)
+	else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) {
+		// Read the Counter Actual Value.
+		data[0] =
+			inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
+					1) * 0x20) +
+			APCI1564_TCW_SYNC_ENABLEDISABLE);
+		ul_Command1 =
+			inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister -
+					1) * 0x20) + APCI1564_TCW_TRIG_STATUS);
+
+      /***********************************/
+		/* Get the software trigger status */
+      /***********************************/
+		data[1] = (BYTE) ((ul_Command1 >> 1) & 1);
+
+      /***********************************/
+		/* Get the hardware trigger status */
+      /***********************************/
+		data[2] = (BYTE) ((ul_Command1 >> 2) & 1);
+
+      /*********************************/
+		/* Get the software clear status */
+      /*********************************/
+		data[3] = (BYTE) ((ul_Command1 >> 3) & 1);
+
+      /***************************/
+		/* Get the overflow status */
+      /***************************/
+		data[4] = (BYTE) ((ul_Command1 >> 0) & 1);
+	}			// else  if  (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER)
+	else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
+		&& (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)
+		&& (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) {
+		printk("\n Invalid Subdevice !!!\n");
+	}			// else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER))
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   :  int i_APCI1564_ReadInterruptStatus                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              :Reads the interrupt status register                     |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI1564_ReadInterruptStatus(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	*data = ui_Type;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : static void v_APCI1564_Interrupt					     |
+|					  (int irq , void *d)      |
++----------------------------------------------------------------------------+
+| Task              : Interrupt handler for the interruptible digital inputs |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq                 : irq number                   |
+|                     void *d                 : void pointer                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+static void v_APCI1564_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	UINT ui_DO, ui_DI;
+	UINT ui_Timer;
+	UINT ui_C1, ui_C2, ui_C3, ui_C4;
+	ULONG ul_Command2 = 0;
+	ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+		APCI1564_DIGITAL_IP_IRQ) & 0x01;
+	ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+		APCI1564_DIGITAL_OP_IRQ) & 0x01;
+	ui_Timer =
+		inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+		APCI1564_TCW_IRQ) & 0x01;
+	ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 +
+		APCI1564_TCW_IRQ) & 0x1;
+	ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 +
+		APCI1564_TCW_IRQ) & 0x1;
+	ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 +
+		APCI1564_TCW_IRQ) & 0x1;
+	ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 +
+		APCI1564_TCW_IRQ) & 0x1;
+	if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0
+		&& ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) {
+		printk("\nInterrupt from unknown source\n");
+	}			// if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0)
+
+	if (ui_DI == 1) {
+		ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_IRQ);
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_IRQ);
+		ui_InterruptStatus_1564 =
+			inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP +
+			APCI1564_DIGITAL_IP_INTERRUPT_STATUS);
+		ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0;
+		send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+		outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ);	//enable the interrupt
+		return;
+	}
+
+	if (ui_DO == 1) {
+		// Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt.
+		ui_Type =
+			inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+			APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3;
+		//Disable the  Interrupt
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP +
+			APCI1564_DIGITAL_OP_INTERRUPT);
+
+		//Sends signal to user space
+		send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+	}			// if  (ui_DO)
+
+	if ((ui_Timer == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_TIMER)) {
+		// Disable Timer Interrupt
+		ul_Command2 =
+			inl(devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_PROG);
+		outl(0x0,
+			devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_PROG);
+
+		//Send a signal to from kernel to user space
+		send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+		// Enable Timer Interrupt
+
+		outl(ul_Command2,
+			devpriv->i_IobaseAmcc + APCI1564_TIMER +
+			APCI1564_TCW_PROG);
+	}			// if  ((ui_Timer == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_TIMER))
+
+	if ((ui_C1 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) {
+		// Disable Counter Interrupt
+		ul_Command2 =
+			inl(devpriv->iobase + APCI1564_COUNTER1 +
+			APCI1564_TCW_PROG);
+		outl(0x0,
+			devpriv->iobase + APCI1564_COUNTER1 +
+			APCI1564_TCW_PROG);
+
+		//Send a signal to from kernel to user space
+		send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+		// Enable Counter Interrupt
+		outl(ul_Command2,
+			devpriv->iobase + APCI1564_COUNTER1 +
+			APCI1564_TCW_PROG);
+	}			// if  ((ui_C1 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER))
+
+	if ((ui_C2 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) {
+		// Disable Counter Interrupt
+		ul_Command2 =
+			inl(devpriv->iobase + APCI1564_COUNTER2 +
+			APCI1564_TCW_PROG);
+		outl(0x0,
+			devpriv->iobase + APCI1564_COUNTER2 +
+			APCI1564_TCW_PROG);
+
+		//Send a signal to from kernel to user space
+		send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+		// Enable Counter Interrupt
+		outl(ul_Command2,
+			devpriv->iobase + APCI1564_COUNTER2 +
+			APCI1564_TCW_PROG);
+	}			// if  ((ui_C2 == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_COUNTER))
+
+	if ((ui_C3 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) {
+		// Disable Counter Interrupt
+		ul_Command2 =
+			inl(devpriv->iobase + APCI1564_COUNTER3 +
+			APCI1564_TCW_PROG);
+		outl(0x0,
+			devpriv->iobase + APCI1564_COUNTER3 +
+			APCI1564_TCW_PROG);
+
+		//Send a signal to from kernel to user space
+		send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+		// Enable Counter Interrupt
+		outl(ul_Command2,
+			devpriv->iobase + APCI1564_COUNTER3 +
+			APCI1564_TCW_PROG);
+	}			// if ((ui_C3 == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_COUNTER))
+
+	if ((ui_C4 == 1) && (devpriv->b_TimerSelectMode = ADDIDATA_COUNTER)) {
+		// Disable Counter Interrupt
+		ul_Command2 =
+			inl(devpriv->iobase + APCI1564_COUNTER4 +
+			APCI1564_TCW_PROG);
+		outl(0x0,
+			devpriv->iobase + APCI1564_COUNTER4 +
+			APCI1564_TCW_PROG);
+
+		//Send a signal to from kernel to user space
+		send_sig(SIGIO, devpriv->tsk_Current, 0);
+
+		// Enable Counter Interrupt
+		outl(ul_Command2,
+			devpriv->iobase + APCI1564_COUNTER4 +
+			APCI1564_TCW_PROG);
+	}			// if ((ui_C4 == 1) && (devpriv->b_TimerSelectMode =ADDIDATA_COUNTER))
+	return;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI1564_Reset(struct comedi_device *dev)               |                                                       |
++----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI1564_Reset(struct comedi_device * dev)
+{
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ);	//disable the interrupts
+	inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS);	//Reset the interrupt status register
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1);	//Disable the and/or interrupt
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2);
+	devpriv->b_DigitalOutputRegister = 0;
+	ui_Type = 0;
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP);	//Resets the output channels
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT);	//Disables the interrupt.
+	outl(0x0,
+		devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG +
+		APCI1564_TCW_RELOAD_VALUE);
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER);
+	outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG);
+
+	outl(0x0, devpriv->iobase + APCI1564_COUNTER1 + APCI1564_TCW_PROG);
+	outl(0x0, devpriv->iobase + APCI1564_COUNTER2 + APCI1564_TCW_PROG);
+	outl(0x0, devpriv->iobase + APCI1564_COUNTER3 + APCI1564_TCW_PROG);
+	outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_PROG);
+	return 0;
+}

+ 119 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h

@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/*********      Definitions for APCI-1564 card  *****/
+
+#define APCI1564_BOARD_VENDOR_ID                0x15B8
+#define APCI1564_ADDRESS_RANGE                  128
+
+//DIGITAL INPUT-OUTPUT DEFINE
+// Input defines
+#define APCI1564_DIGITAL_IP                     0x04
+#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1     4
+#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2     8
+#define APCI1564_DIGITAL_IP_IRQ                 16
+
+// Output defines
+#define APCI1564_DIGITAL_OP                 	0x18
+#define APCI1564_DIGITAL_OP_RW               	0
+#define APCI1564_DIGITAL_OP_INTERRUPT           4
+#define APCI1564_DIGITAL_OP_IRQ                 12
+
+//Digital Input IRQ Function Selection
+#define ADDIDATA_OR                             0
+#define ADDIDATA_AND                            1
+
+//Digital Input Interrupt Status
+#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS    12
+
+//Digital Output Interrupt Status
+#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS    8
+
+//Digital Input Interrupt Enable Disable.
+#define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE    0x4
+#define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE   0xFFFFFFFB
+
+//Digital Output Interrupt Enable Disable.
+#define APCI1564_DIGITAL_OP_VCC_INTERRUPT_ENABLE   0x1
+#define APCI1564_DIGITAL_OP_VCC_INTERRUPT_DISABLE  0xFFFFFFFE
+#define APCI1564_DIGITAL_OP_CC_INTERRUPT_ENABLE    0x2
+#define APCI1564_DIGITAL_OP_CC_INTERRUPT_DISABLE   0xFFFFFFFD
+
+//ADDIDATA Enable Disable
+
+#define ADDIDATA_ENABLE                            1
+#define ADDIDATA_DISABLE                           0
+
+// TIMER COUNTER WATCHDOG DEFINES
+
+#define ADDIDATA_TIMER                             0
+#define ADDIDATA_COUNTER                           1
+#define ADDIDATA_WATCHDOG                          2
+#define APCI1564_DIGITAL_OP_WATCHDOG               0x28
+#define APCI1564_TIMER                             0x48
+#define APCI1564_COUNTER1                          0x0
+#define APCI1564_COUNTER2                          0x20
+#define APCI1564_COUNTER3                          0x40
+#define APCI1564_COUNTER4                          0x60
+#define APCI1564_TCW_SYNC_ENABLEDISABLE            0
+#define APCI1564_TCW_RELOAD_VALUE                  4
+#define APCI1564_TCW_TIMEBASE                      8
+#define APCI1564_TCW_PROG                          12
+#define APCI1564_TCW_TRIG_STATUS                   16
+#define APCI1564_TCW_IRQ                           20
+#define APCI1564_TCW_WARN_TIMEVAL                  24
+#define APCI1564_TCW_WARN_TIMEBASE                 28
+
+// Hardware Layer  functions for Apci1564
+
+//DI
+// for di read
+INT i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1564_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+
+//DO
+int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1564_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI1564_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+
+// TIMER
+// timer value is passed as u seconds
+INT i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);
+int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev,
+						  struct comedi_subdevice *s,
+						  struct comedi_insn *insn,
+						  unsigned int *data);
+int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev,
+					struct comedi_subdevice *s,
+					struct comedi_insn *insn, unsigned int *data);
+
+// INTERRUPT
+static void v_APCI1564_Interrupt(int irq, void *d);
+
+// RESET
+INT i_APCI1564_Reset(struct comedi_device *dev);

+ 780 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c

@@ -0,0 +1,780 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : API APCI1648    | Compiler : gcc                        |
+  | Module name : TTL.C           | Version  : 2.96                       |
+  +-------------------------------+---------------------------------------+
+  | Project manager: S. Weber     | Date     :  25/05/2005                |
+  +-----------------------------------------------------------------------+
+  | Description :   APCI-16XX TTL I/O module                              |
+  |                                                                       |
+  |                                                                       |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |25.05.2005| S.Weber   | Creation                                       |
+  |          |           |                                                |
+  +-----------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "hwdrv_apci16xx.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI16XX_InsnConfigInitTTLIO                   |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           APCI16XX_TTL_INIT (using defaults)   :                      |
+|                Configure the TTL I/O operating mode from all ports         |
+|                You must calling this function be                           |
+|                for you call any other function witch access of TTL.        |
+|                APCI16XX_TTL_INITDIRECTION(user inputs for direction)       |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_InitType    = (BYTE) data[0];                        |
+|                     b_Port0Mode   = (BYTE) data[1];                        |
+|                     b_Port1Mode   = (BYTE) data[2];                        |
+|                     b_Port2Mode   = (BYTE) data[3];                        |
+|                     b_Port3Mode   = (BYTE) data[4];                        |
+|                     ........                                               |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -1: Port 0 mode selection is wrong                      |
+|                    -2: Port 1 mode selection is wrong                      |
+|                    -3: Port 2 mode selection is wrong                      |
+|                    -4: Port 3 mode selection is wrong                      |
+|                    -X: Port X-1 mode selection is wrong                    |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Command = 0;
+	BYTE b_Cpt = 0;
+	BYTE b_NumberOfPort =
+		(BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8);
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /*******************/
+		/* Get the command */
+		/* **************** */
+
+		b_Command = (BYTE) data[0];
+
+	   /********************/
+		/* Test the command */
+	   /********************/
+
+		if ((b_Command == APCI16XX_TTL_INIT) ||
+			(b_Command == APCI16XX_TTL_INITDIRECTION) ||
+			(b_Command == APCI16XX_TTL_OUTPUTMEMORY)) {
+	      /***************************************/
+			/* Test the initialisation buffer size */
+	      /***************************************/
+
+			if ((b_Command == APCI16XX_TTL_INITDIRECTION)
+				&& ((BYTE) (insn->n - 1) != b_NumberOfPort)) {
+		 /*******************/
+				/* Data size error */
+		 /*******************/
+
+				printk("\nBuffer size error");
+				i_ReturnValue = -101;
+			}
+
+			if ((b_Command == APCI16XX_TTL_OUTPUTMEMORY)
+				&& ((BYTE) (insn->n) != 2)) {
+		 /*******************/
+				/* Data size error */
+		 /*******************/
+
+				printk("\nBuffer size error");
+				i_ReturnValue = -101;
+			}
+		} else {
+	      /************************/
+			/* Config command error */
+	      /************************/
+
+			printk("\nCommand selection error");
+			i_ReturnValue = -100;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("\nBuffer size error");
+		i_ReturnValue = -101;
+	}
+
+	/**************************************************************************/
+	/* Test if no error occur and APCI16XX_TTL_INITDIRECTION command selected */
+	/**************************************************************************/
+
+	if ((i_ReturnValue >= 0) && (b_Command == APCI16XX_TTL_INITDIRECTION)) {
+		memset(devpriv->ul_TTLPortConfiguration, 0,
+			sizeof(devpriv->ul_TTLPortConfiguration));
+
+	   /*************************************/
+		/* Test the port direction selection */
+	   /*************************************/
+
+		for (b_Cpt = 1;
+			(b_Cpt <= b_NumberOfPort) && (i_ReturnValue >= 0);
+			b_Cpt++) {
+	      /**********************/
+			/* Test the direction */
+	      /**********************/
+
+			if ((data[b_Cpt] != 0) && (data[b_Cpt] != 0xFF)) {
+		 /************************/
+				/* Port direction error */
+		 /************************/
+
+				printk("\nPort %d direction selection error",
+					(INT) b_Cpt);
+				i_ReturnValue = -(INT) b_Cpt;
+			}
+
+	      /**************************/
+			/* Save the configuration */
+	      /**************************/
+
+			devpriv->ul_TTLPortConfiguration[(b_Cpt - 1) / 4] =
+				devpriv->ul_TTLPortConfiguration[(b_Cpt -
+					1) / 4] | (data[b_Cpt] << (8 * ((b_Cpt -
+							1) % 4)));
+		}
+	}
+
+	/**************************/
+	/* Test if no error occur */
+	/**************************/
+
+	if (i_ReturnValue >= 0) {
+	   /***********************************/
+		/* Test if TTL port initilaisation */
+	   /***********************************/
+
+		if ((b_Command == APCI16XX_TTL_INIT)
+			|| (b_Command == APCI16XX_TTL_INITDIRECTION)) {
+	      /******************************/
+			/* Set all port configuration */
+	      /******************************/
+
+			for (b_Cpt = 0; b_Cpt <= b_NumberOfPort; b_Cpt++) {
+				if ((b_Cpt % 4) == 0) {
+		    /*************************/
+					/* Set the configuration */
+		    /*************************/
+
+					outl(devpriv->
+						ul_TTLPortConfiguration[b_Cpt /
+							4],
+						devpriv->iobase + 32 + b_Cpt);
+				}
+			}
+		}
+	}
+
+	/************************************************/
+	/* Test if output memory initialisation command */
+	/************************************************/
+
+	if (b_Command == APCI16XX_TTL_OUTPUTMEMORY) {
+		if (data[1]) {
+			devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
+		} else {
+			devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
+		}
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            INPUT FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT     i_APCI16XX_InsnBitsReadTTLIO                   |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Read the status from selected TTL digital input        |
+|                     (b_InputChannel)                                       |
++----------------------------------------------------------------------------+
+| Task              : Read the status from digital input port                |
+|                     (b_SelectedPort)                                       |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
+|              APCI16XX_TTL_READCHANNEL                                      |
+|                    b_SelectedPort= CR_RANGE(insn->chanspec);               |
+|                    b_InputChannel= CR_CHAN(insn->chanspec);                |
+|                    b_ReadType	  = (BYTE) data[0];                          |
+|                                                                            |
+|              APCI16XX_TTL_READPORT                                         |
+|                    b_SelectedPort= CR_RANGE(insn->chanspec);               |
+|                    b_ReadType	  = (BYTE) data[0];                          |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0]    0 : Channle is not active                   |
+|                                1 : Channle is active                       |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
+|                    -102 : The selected TTL input port is wrong             |
+|                    -103 : The selected TTL digital input is wrong          |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Command = 0;
+	BYTE b_NumberOfPort =
+		(BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8);
+	BYTE b_SelectedPort = CR_RANGE(insn->chanspec);
+	BYTE b_InputChannel = CR_CHAN(insn->chanspec);
+	BYTE *pb_Status;
+	DWORD dw_Status;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /*******************/
+		/* Get the command */
+		/* **************** */
+
+		b_Command = (BYTE) data[0];
+
+	   /********************/
+		/* Test the command */
+	   /********************/
+
+		if ((b_Command == APCI16XX_TTL_READCHANNEL)
+			|| (b_Command == APCI16XX_TTL_READPORT)) {
+	      /**************************/
+			/* Test the selected port */
+	      /**************************/
+
+			if (b_SelectedPort < b_NumberOfPort) {
+		 /**********************/
+				/* Test if input port */
+		 /**********************/
+
+				if (((devpriv->ul_TTLPortConfiguration
+							[b_SelectedPort /
+								4] >> (8 *
+								(b_SelectedPort
+									%
+									4))) &
+						0xFF) == 0) {
+		    /***************************/
+					/* Test the channel number */
+		    /***************************/
+
+					if ((b_Command ==
+							APCI16XX_TTL_READCHANNEL)
+						&& (b_InputChannel > 7)) {
+		       /*******************************************/
+						/* The selected TTL digital input is wrong */
+		       /*******************************************/
+
+						printk("\nChannel selection error");
+						i_ReturnValue = -103;
+					}
+				} else {
+		    /****************************************/
+					/* The selected TTL input port is wrong */
+		    /****************************************/
+
+					printk("\nPort selection error");
+					i_ReturnValue = -102;
+				}
+			} else {
+		 /****************************************/
+				/* The selected TTL input port is wrong */
+		 /****************************************/
+
+				printk("\nPort selection error");
+				i_ReturnValue = -102;
+			}
+		} else {
+	      /************************/
+			/* Config command error */
+	      /************************/
+
+			printk("\nCommand selection error");
+			i_ReturnValue = -100;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("\nBuffer size error");
+		i_ReturnValue = -101;
+	}
+
+	/**************************/
+	/* Test if no error occur */
+	/**************************/
+
+	if (i_ReturnValue >= 0) {
+		pb_Status = (PBYTE) & data[0];
+
+	   /*******************************/
+		/* Get the digital inpu status */
+	   /*******************************/
+
+		dw_Status =
+			inl(devpriv->iobase + 8 + ((b_SelectedPort / 4) * 4));
+		dw_Status = (dw_Status >> (8 * (b_SelectedPort % 4))) & 0xFF;
+
+	   /***********************/
+		/* Save the port value */
+	   /***********************/
+
+		*pb_Status = (BYTE) dw_Status;
+
+	   /***************************************/
+		/* Test if read channel status command */
+	   /***************************************/
+
+		if (b_Command == APCI16XX_TTL_READCHANNEL) {
+			*pb_Status = (*pb_Status >> b_InputChannel) & 1;
+		}
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI16XX_InsnReadTTLIOAllPortValue               |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Read the status from all digital input ports           |
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Port 0 to 3 data                             |
+|                     data[1] : Port 4 to 7 data                             |
+|                     ....                                                   |
++----------------------------------------------------------------------------+
+| Return Value      : 0: No error                                            |
+|                    -100 : Read command error                               |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_Command = (BYTE) CR_AREF(insn->chanspec);
+	INT i_ReturnValue = insn->n;
+	BYTE b_Cpt = 0;
+	BYTE b_NumberOfPort = 0;
+	unsigned int *pls_ReadData = data;
+
+	/********************/
+	/* Test the command */
+	/********************/
+
+	if ((b_Command == APCI16XX_TTL_READ_ALL_INPUTS)
+		|| (b_Command == APCI16XX_TTL_READ_ALL_OUTPUTS)) {
+	   /**********************************/
+		/* Get the number of 32-Bit ports */
+	   /**********************************/
+
+		b_NumberOfPort =
+			(BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 32);
+		if ((b_NumberOfPort * 32) <
+			devpriv->ps_BoardInfo->i_NbrTTLChannel) {
+			b_NumberOfPort = b_NumberOfPort + 1;
+		}
+
+	   /************************/
+		/* Test the buffer size */
+	   /************************/
+
+		if (insn->n >= b_NumberOfPort) {
+			if (b_Command == APCI16XX_TTL_READ_ALL_INPUTS) {
+		 /**************************/
+				/* Read all digital input */
+		 /**************************/
+
+				for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) {
+		    /************************/
+					/* Read the 32-Bit port */
+		    /************************/
+
+					pls_ReadData[b_Cpt] =
+						inl(devpriv->iobase + 8 +
+						(b_Cpt * 4));
+
+		    /**************************************/
+					/* Mask all channels used als outputs */
+		    /**************************************/
+
+					pls_ReadData[b_Cpt] =
+						pls_ReadData[b_Cpt] &
+						(~devpriv->
+						ul_TTLPortConfiguration[b_Cpt]);
+				}
+			} else {
+		 /****************************/
+				/* Read all digital outputs */
+		 /****************************/
+
+				for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) {
+		    /************************/
+					/* Read the 32-Bit port */
+		    /************************/
+
+					pls_ReadData[b_Cpt] =
+						inl(devpriv->iobase + 20 +
+						(b_Cpt * 4));
+
+		    /**************************************/
+					/* Mask all channels used als outputs */
+		    /**************************************/
+
+					pls_ReadData[b_Cpt] =
+						pls_ReadData[b_Cpt] & devpriv->
+						ul_TTLPortConfiguration[b_Cpt];
+				}
+			}
+		} else {
+	      /*******************/
+			/* Data size error */
+	      /*******************/
+
+			printk("\nBuffer size error");
+			i_ReturnValue = -101;
+		}
+	} else {
+	   /*****************/
+		/* Command error */
+	   /*****************/
+
+		printk("\nCommand selection error");
+		i_ReturnValue = -100;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            OUTPUT FUNCTIONS                                |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT     i_APCI16XX_InsnBitsWriteTTLIO                  |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Set the state from selected TTL digital output         |
+|                     (b_OutputChannel)                                      |
++----------------------------------------------------------------------------+
+| Task              : Set the state from digital output port                 |
+|                     (b_SelectedPort)                                       |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
+|              APCI16XX_TTL_WRITECHANNEL_ON | APCI16XX_TTL_WRITECHANNEL_OFF  |
+|                    b_SelectedPort = CR_RANGE(insn->chanspec);              |
+|                    b_OutputChannel= CR_CHAN(insn->chanspec);               |
+|                    b_Command      = (BYTE) data[0];                        |
+|                                                                            |
+|              APCI16XX_TTL_WRITEPORT_ON | APCI16XX_TTL_WRITEPORT_OFF        |
+|                    b_SelectedPort = CR_RANGE(insn->chanspec);              |
+|                    b_Command      = (BYTE) data[0];                        |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : TTL output port 0 to 3 data                  |
+|                     data[1] : TTL output port 4 to 7 data                  |
+|                     ....                                                   |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -100 : Command error                                    |
+|                    -101 : Data size error                                  |
+|                    -102 : The selected TTL output port is wrong            |
+|                    -103 : The selected TTL digital output is wrong         |
+|                    -104 : Output memory disabled                           |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Command = 0;
+	BYTE b_NumberOfPort =
+		(BYTE) (devpriv->ps_BoardInfo->i_NbrTTLChannel / 8);
+	BYTE b_SelectedPort = CR_RANGE(insn->chanspec);
+	BYTE b_OutputChannel = CR_CHAN(insn->chanspec);
+	DWORD dw_Status = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /*******************/
+		/* Get the command */
+		/* **************** */
+
+		b_Command = (BYTE) data[0];
+
+	   /********************/
+		/* Test the command */
+	   /********************/
+
+		if ((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) ||
+			(b_Command == APCI16XX_TTL_WRITEPORT_ON) ||
+			(b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) ||
+			(b_Command == APCI16XX_TTL_WRITEPORT_OFF)) {
+	      /**************************/
+			/* Test the selected port */
+	      /**************************/
+
+			if (b_SelectedPort < b_NumberOfPort) {
+		 /***********************/
+				/* Test if output port */
+		 /***********************/
+
+				if (((devpriv->ul_TTLPortConfiguration
+							[b_SelectedPort /
+								4] >> (8 *
+								(b_SelectedPort
+									%
+									4))) &
+						0xFF) == 0xFF) {
+		    /***************************/
+					/* Test the channel number */
+		    /***************************/
+
+					if (((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) || (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF)) && (b_OutputChannel > 7)) {
+		       /********************************************/
+						/* The selected TTL digital output is wrong */
+		       /********************************************/
+
+						printk("\nChannel selection error");
+						i_ReturnValue = -103;
+					}
+
+					if (((b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE)) {
+		       /********************************************/
+						/* The selected TTL digital output is wrong */
+		       /********************************************/
+
+						printk("\nOutput memory disabled");
+						i_ReturnValue = -104;
+					}
+
+		    /************************/
+					/* Test the buffer size */
+		    /************************/
+
+					if (((b_Command == APCI16XX_TTL_WRITEPORT_ON) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (insn->n < 2)) {
+		       /*******************/
+						/* Data size error */
+		       /*******************/
+
+						printk("\nBuffer size error");
+						i_ReturnValue = -101;
+					}
+				} else {
+		    /*****************************************/
+					/* The selected TTL output port is wrong */
+		    /*****************************************/
+
+					printk("\nPort selection error %lX",
+						(unsigned long)devpriv->
+						ul_TTLPortConfiguration[0]);
+					i_ReturnValue = -102;
+				}
+			} else {
+		 /****************************************/
+				/* The selected TTL output port is wrong */
+		 /****************************************/
+
+				printk("\nPort selection error %d %d",
+					b_SelectedPort, b_NumberOfPort);
+				i_ReturnValue = -102;
+			}
+		} else {
+	      /************************/
+			/* Config command error */
+	      /************************/
+
+			printk("\nCommand selection error");
+			i_ReturnValue = -100;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("\nBuffer size error");
+		i_ReturnValue = -101;
+	}
+
+	/**************************/
+	/* Test if no error occur */
+	/**************************/
+
+	if (i_ReturnValue >= 0) {
+	   /********************************/
+		/* Get the digital output state */
+	   /********************************/
+
+		dw_Status =
+			inl(devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4));
+
+	   /**********************************/
+		/* Test if output memory not used */
+	   /**********************************/
+
+		if (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE) {
+	      /*********************************/
+			/* Clear the selected port value */
+	      /*********************************/
+
+			dw_Status =
+				dw_Status & (0xFFFFFFFFUL -
+				(0xFFUL << (8 * (b_SelectedPort % 4))));
+		}
+
+	   /******************************/
+		/* Test if setting channel ON */
+	   /******************************/
+
+		if (b_Command == APCI16XX_TTL_WRITECHANNEL_ON) {
+			dw_Status =
+				dw_Status | (1UL << ((8 * (b_SelectedPort %
+							4)) + b_OutputChannel));
+		}
+
+	   /***************************/
+		/* Test if setting port ON */
+	   /***************************/
+
+		if (b_Command == APCI16XX_TTL_WRITEPORT_ON) {
+			dw_Status =
+				dw_Status | ((data[1] & 0xFF) << (8 *
+					(b_SelectedPort % 4)));
+		}
+
+	   /*******************************/
+		/* Test if setting channel OFF */
+	   /*******************************/
+
+		if (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) {
+			dw_Status =
+				dw_Status & (0xFFFFFFFFUL -
+				(1UL << ((8 * (b_SelectedPort % 4)) +
+						b_OutputChannel)));
+		}
+
+	   /****************************/
+		/* Test if setting port OFF */
+	   /****************************/
+
+		if (b_Command == APCI16XX_TTL_WRITEPORT_OFF) {
+			dw_Status =
+				dw_Status & (0xFFFFFFFFUL -
+				((data[1] & 0xFF) << (8 * (b_SelectedPort %
+							4))));
+		}
+
+		outl(dw_Status,
+			devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4));
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_Reset(struct comedi_device *dev)               |                                                         +----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : -                                                      |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_Reset(struct comedi_device * dev)
+{
+	return 0;
+}

+ 94 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.h

@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#ifndef COMEDI_SUBD_TTLIO
+#define COMEDI_SUBD_TTLIO   11	/* Digital Input Output But TTL */
+#endif
+
+#ifndef ADDIDATA_ENABLE
+#define ADDIDATA_ENABLE  1
+#define ADDIDATA_DISABLE 0
+#endif
+
+#define APCI16XX_TTL_INIT           0
+#define APCI16XX_TTL_INITDIRECTION  1
+#define APCI16XX_TTL_OUTPUTMEMORY   2
+
+#define APCI16XX_TTL_READCHANNEL            0
+#define APCI16XX_TTL_READPORT               1
+
+#define APCI16XX_TTL_WRITECHANNEL_ON        0
+#define APCI16XX_TTL_WRITECHANNEL_OFF       1
+#define APCI16XX_TTL_WRITEPORT_ON           2
+#define APCI16XX_TTL_WRITEPORT_OFF          3
+
+#define APCI16XX_TTL_READ_ALL_INPUTS        0
+#define APCI16XX_TTL_READ_ALL_OUTPUTS       1
+
+#ifdef __KERNEL__
+
+static const struct comedi_lrange range_apci16xx_ttl = { 12,
+	{BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1),
+	 BIP_RANGE(1)}
+};
+
+/*
++----------------------------------------------------------------------------+
+|                       TTL INISIALISATION FUNCTION                          |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device *dev,
+				   struct comedi_subdevice *s, struct comedi_insn *insn,
+				   unsigned int *data);
+
+/*
++----------------------------------------------------------------------------+
+|                       TTL INPUT FUNCTION                                   |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device *dev,
+				 struct comedi_subdevice *s, struct comedi_insn *insn,
+				 unsigned int *data);
+
+int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+
+/*
++----------------------------------------------------------------------------+
+|                            TTL OUTPUT FUNCTIONS                            |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device *dev,
+				  struct comedi_subdevice *s, struct comedi_insn *insn,
+				  unsigned int *data);
+
+int i_APCI16XX_Reset(struct comedi_device *dev);
+#endif

+ 460 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c

@@ -0,0 +1,460 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-2016       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci2016.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-2016                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci2016.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_ConfigDigitalOutput                     |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Digital Output Subdevice.               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|			  data[0]            : 1 Digital Memory On               |
+|				     			   0 Digital Memory Off              |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2016_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}			// if  ((data[0]!=0) && (data[0]!=1))
+	if (data[0]) {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
+	}			// if  (data[0]
+	else {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
+	}			// else if  (data[0]
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_WriteDigitalOutput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To Write      |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2016_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_NoOfChannel;
+	UINT ui_Temp, ui_Temp1;
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	if ((ui_NoOfChannel < 0) || (ui_NoOfChannel > 15)) {
+		comedi_error(dev,
+			"Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
+		return -EINVAL;
+	}			// if  ((ui_NoOfChannel<0) || (ui_NoOfChannel>15))
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp = inw(devpriv->iobase + APCI2016_DIGITAL_OP);
+	}			// if  (devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			// else if  (devpriv->b_OutputMemoryStatus )
+	if ((data[1] != 0) && (data[1] != 1)) {
+		comedi_error(dev,
+			"Invalid Data[1] value !!!, Data[1] should be 0 or 1\n");
+		return -EINVAL;
+	}			// if  ((data[1]!=0) && (data[1]!=1))
+
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP);
+		}		// if (data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+				case 4:
+					data[0] =
+						(data[0] << (4 *
+							data[2])) | ui_Temp;
+					break;
+				case 8:
+					data[0] =
+						(data[0] << (8 *
+							data[2])) | ui_Temp;
+					break;
+				case 15:
+					data[0] = data[0] | ui_Temp;
+					break;
+				default:
+					comedi_error(dev, " chan spec wrong");
+					return -EINVAL;	// "sorry channel spec wrong "
+				}	//switch(ui_NoOfChannels)
+				outw(data[0],
+					devpriv->iobase + APCI2016_DIGITAL_OP);
+			}	// if  (data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	// else if  (data[1]==1)
+		}		// else if (data[1]==0)
+	}			// if (data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] = (data[0] << ui_NoOfChannel) ^ 0xffff;
+				data[0] = data[0] & ui_Temp;
+				outw(data[0],
+					devpriv->iobase + APCI2016_DIGITAL_OP);
+			}	// if  (data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xffff) & ui_Temp;
+						break;
+					case 4:
+						data[0] = ~data[0] & 0xf;
+						ui_Temp1 = 15;
+						ui_Temp1 =
+							ui_Temp1 << 4 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (4 *
+									data
+									[2])) ^
+							0xffff) & ui_Temp;
+						break;
+					case 8:
+						data[0] = ~data[0] & 0xff;
+						ui_Temp1 = 255;
+						ui_Temp1 =
+							ui_Temp1 << 8 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (8 *
+									data
+									[2])) ^
+							0xffff) & ui_Temp;
+						break;
+					case 15:
+						break;
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+					}	//switch(ui_NoOfChannels)
+					outw(data[0],
+						devpriv->iobase +
+						APCI2016_DIGITAL_OP);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_BitsDigitalOutput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To read       |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2016_BitsDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp;
+	UINT ui_NoOfChannel;
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	if ((ui_NoOfChannel < 0) || (ui_NoOfChannel > 15)) {
+		comedi_error(dev,
+			"Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
+		return -EINVAL;
+	}			// if  ((ui_NoOfChannel<0) || (ui_NoOfChannel>15))
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Invalid Data[0] value !!!, Data[0] should be 0 or 1\n");
+		return -EINVAL;
+	}			// if  ((data[0]!=0) && (data[0]!=1))
+	ui_Temp = data[0];
+	*data = inw(devpriv->iobase + APCI2016_DIGITAL_OP_RW);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			// if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			switch (ui_NoOfChannel) {
+			case 2:
+				*data = (*data >> (2 * data[1])) & 3;
+				break;
+
+			case 4:
+				*data = (*data >> (4 * data[1])) & 15;
+				break;
+
+			case 8:
+				*data = (*data >> (8 * data[1])) & 255;
+				break;
+
+			case 15:
+				break;
+
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+			}	//switch(ui_NoOfChannel)
+		}		// if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		// else if  (ui_Temp==1)
+	}			// if  (ui_Temp==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_ConfigWatchdog                          |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Watchdog                                |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure |
+|                     struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2016_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	if (data[0] == 0) {
+		//Disable the watchdog
+		outw(0x0,
+			devpriv->i_IobaseAddon +
+			APCI2016_WATCHDOG_ENABLEDISABLE);
+		//Loading the Reload value
+		outw(data[1],
+			devpriv->i_IobaseAddon +
+			APCI2016_WATCHDOG_RELOAD_VALUE);
+		data[1] = data[1] >> 16;
+		outw(data[1],
+			devpriv->i_IobaseAddon +
+			APCI2016_WATCHDOG_RELOAD_VALUE + 2);
+	} else {
+		printk("\nThe input parameters are wrong\n");
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_StartStopWriteWatchdog                  |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Start / Stop The Watchdog                              |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure |
+|                     struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2016_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	switch (data[0]) {
+	case 0:		//stop the watchdog
+		outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE);	//disable the watchdog
+		break;
+	case 1:		//start the watchdog
+		outw(0x0001,
+			devpriv->i_IobaseAddon +
+			APCI2016_WATCHDOG_ENABLEDISABLE);
+		break;
+	case 2:		//Software trigger
+		outw(0x0201,
+			devpriv->i_IobaseAddon +
+			APCI2016_WATCHDOG_ENABLEDISABLE);
+		break;
+	default:
+		printk("\nSpecified functionality does not exist\n");
+		return -EINVAL;
+	}			// switch(data[0])
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_ReadWatchdog                            |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Watchdog                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure |
+|                     struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI2016_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	udelay(5);
+	data[0] = inw(devpriv->i_IobaseAddon + APCI2016_WATCHDOG_STATUS) & 0x1;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2016_Reset(struct comedi_device *dev)               |                                                       |
++----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2016_Reset(struct comedi_device * dev)
+{
+	outw(0x0, devpriv->iobase + APCI2016_DIGITAL_OP);	// Resets the digital output channels
+	outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE);
+	outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE);
+	outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE + 2);
+	return 0;
+}

+ 70 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+/*********      Definitions for APCI-2016 card  *****/
+
+#define APCI2016_BOARD_VENDOR_ID 0x15B8
+#define APCI2016_ADDRESS_RANGE   8
+
+//DIGITAL INPUT-OUTPUT DEFINE
+
+#define APCI2016_DIGITAL_OP                 	0x04
+#define APCI2016_DIGITAL_OP_RW                 	4
+
+//ADDIDATA Enable Disable
+
+#define ADDIDATA_ENABLE                            1
+#define ADDIDATA_DISABLE                           0
+
+// TIMER COUNTER WATCHDOG DEFINES
+
+#define ADDIDATA_WATCHDOG                          2
+#define APCI2016_DIGITAL_OP_WATCHDOG               0
+#define APCI2016_WATCHDOG_ENABLEDISABLE            12
+#define APCI2016_WATCHDOG_RELOAD_VALUE             4
+#define APCI2016_WATCHDOG_STATUS                   16
+
+// Hardware Layer  functions for Apci2016
+
+//DO
+int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+
+int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+
+int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+// TIMER
+// timer value is passed as u seconds
+
+int i_APCI2016_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+
+int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_insn *insn, unsigned int *data);
+
+int i_APCI2016_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data);
+
+// Interrupt functions.....
+
+// void v_APCI2016_Interrupt(int irq, void *d) ;
+
+ //void v_APCI2016_Interrupt(int irq, void *d);
+// RESET
+INT i_APCI2016_Reset(struct comedi_device *dev);

+ 579 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c

@@ -0,0 +1,579 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-2032       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci2032.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-2032                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+
+#include "hwdrv_apci2032.h"
+UINT ui_InterruptData, ui_Type;
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2032_ConfigDigitalOutput                     |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Digital Output Subdevice.               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[1]            : 1 Enable  VCC  Interrupt  |
+|										   0 Disable VCC  Interrupt  |
+|					  data[2]            : 1 Enable  CC  Interrupt   |
+|										   0 Disable CC  Interrupt   |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2032_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command = 0;
+	devpriv->tsk_Current = current;
+
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}			//if  ( (data[0]!=0) && (data[0]!=1) )
+	if (data[0]) {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
+	}			// if  (data[0])
+	else {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
+	}			//else if  (data[0])
+
+	if (data[1] == ADDIDATA_ENABLE) {
+		ul_Command = ul_Command | 0x1;
+	}			//if  (data[1] == ADDIDATA_ENABLE)
+	else {
+		ul_Command = ul_Command & 0xFFFFFFFE;
+	}			//elseif  (data[1] == ADDIDATA_ENABLE)
+	if (data[2] == ADDIDATA_ENABLE) {
+		ul_Command = ul_Command | 0x2;
+	}			//if  (data[2] == ADDIDATA_ENABLE)
+	else {
+		ul_Command = ul_Command & 0xFFFFFFFD;
+	}			//elseif  (data[2] == ADDIDATA_ENABLE)
+	outl(ul_Command, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT);
+	ui_InterruptData = inl(devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT);
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2032_WriteDigitalOutput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To Write      |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2032_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp, ui_Temp1;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp = inl(devpriv->iobase + APCI2032_DIGITAL_OP);
+
+	}			//if(devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			//if(devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP);
+		}		//if(data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 4:
+					data[0] =
+						(data[0] << (4 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 8:
+					data[0] =
+						(data[0] << (8 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 16:
+					data[0] =
+						(data[0] << (16 *
+							data[2])) | ui_Temp;
+					break;
+				case 31:
+					data[0] = data[0] | ui_Temp;
+					break;
+
+				default:
+					comedi_error(dev, " chan spec wrong");
+					return -EINVAL;	// "sorry channel spec wrong "
+
+				}	//switch(ui_NoOfChannels)
+
+				outl(data[0],
+					devpriv->iobase + APCI2032_DIGITAL_OP);
+			}	// if(data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	//else if(data[1]==1)
+		}		//elseif(data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] =
+					(data[0] << ui_NoOfChannel) ^
+					0xffffffff;
+				data[0] = data[0] & ui_Temp;
+				outl(data[0],
+					devpriv->iobase + APCI2032_DIGITAL_OP);
+			}	//if(data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 4:
+						data[0] = ~data[0] & 0xf;
+						ui_Temp1 = 15;
+						ui_Temp1 =
+							ui_Temp1 << 4 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (4 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 8:
+						data[0] = ~data[0] & 0xff;
+						ui_Temp1 = 255;
+						ui_Temp1 =
+							ui_Temp1 << 8 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (8 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 16:
+						data[0] = ~data[0] & 0xffff;
+						ui_Temp1 = 65535;
+						ui_Temp1 =
+							ui_Temp1 << 16 *
+							data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (16 *
+									data
+									[2])) ^
+							0xffffffff) & ui_Temp;
+						break;
+
+					case 31:
+						break;
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+
+					}	//switch(ui_NoOfChannels)
+
+					outl(data[0],
+						devpriv->iobase +
+						APCI2032_DIGITAL_OP);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	return (insn->n);;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2032_ReadDigitalOutput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To read       |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2032_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp;
+	UINT ui_NoOfChannel;
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	ui_Temp = data[0];
+	*data = inl(devpriv->iobase + APCI2032_DIGITAL_OP_RW);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			//if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			switch (ui_NoOfChannel) {
+
+			case 2:
+				*data = (*data >> (2 * data[1])) & 3;
+				break;
+
+			case 4:
+				*data = (*data >> (4 * data[1])) & 15;
+				break;
+
+			case 8:
+				*data = (*data >> (8 * data[1])) & 255;
+				break;
+
+			case 16:
+				*data = (*data >> (16 * data[1])) & 65535;
+				break;
+
+			case 31:
+				break;
+
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+
+			}	//switch(ui_NoOfChannels)
+		}		//if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		//elseif  (ui_Temp==1)
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : INT i_APCI2032_ConfigWatchdog(comedi_device
+                   *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Watchdog                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status                                                                                                             |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI2032_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if (data[0] == 0) {
+		//Disable the watchdog
+		outl(0x0,
+			devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG +
+			APCI2032_TCW_PROG);
+		//Loading the Reload value
+		outl(data[1],
+			devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG +
+			APCI2032_TCW_RELOAD_VALUE);
+	} else {
+		printk("\nThe input parameters are wrong\n");
+		return -EINVAL;
+	}
+
+	return insn->n;
+}
+
+ /*
+    +----------------------------------------------------------------------------+
+    | Function   Name   : int i_APCI2032_StartStopWriteWatchdog                  |
+    |                           (struct comedi_device *dev,struct comedi_subdevice *s,
+    struct comedi_insn *insn,unsigned int *data);                      |
+    +----------------------------------------------------------------------------+
+    | Task              : Start / Stop The Watchdog                              |
+    +----------------------------------------------------------------------------+
+    | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+    |                     struct comedi_subdevice *s,   :pointer to subdevice structure
+    struct comedi_insn *insn      :pointer to insn structure      |
+    |                     unsigned int *data          : Data Pointer to read status  |
+    +----------------------------------------------------------------------------+
+    | Output Parameters :       --                                                                                                       |
+    +----------------------------------------------------------------------------+
+    | Return Value      : TRUE  : No error occur                                 |
+    |                       : FALSE : Error occur. Return the error          |
+    |                                                                            |
+    +----------------------------------------------------------------------------+
+  */
+
+int i_APCI2032_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	switch (data[0]) {
+	case 0:		//stop the watchdog
+		outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG);	//disable the watchdog
+		break;
+	case 1:		//start the watchdog
+		outl(0x0001,
+			devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG +
+			APCI2032_TCW_PROG);
+		break;
+	case 2:		//Software trigger
+		outl(0x0201,
+			devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG +
+			APCI2032_TCW_PROG);
+		break;
+	default:
+		printk("\nSpecified functionality does not exist\n");
+		return -EINVAL;
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2032_ReadWatchdog                            |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data); 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Watchdog                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI2032_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	data[0] =
+		inl(devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG +
+		APCI2032_TCW_TRIG_STATUS) & 0x1;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   :  void v_APCI2032_Interrupt					         |
+|					  (int irq , void *d)      |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq                 : irq number                   |
+|                     void *d                 : void pointer                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+void v_APCI2032_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	unsigned int ui_DO;
+
+	ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1;	//Check if VCC OR CC interrupt has occured.
+
+	if (ui_DO == 0) {
+		printk("\nInterrupt from unKnown source\n");
+	}			// if(ui_DO==0)
+	if (ui_DO) {
+		// Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt.
+		ui_Type =
+			inl(devpriv->iobase +
+			APCI2032_DIGITAL_OP_INTERRUPT_STATUS) & 0x3;
+		outl(0x0,
+			devpriv->iobase + APCI2032_DIGITAL_OP +
+			APCI2032_DIGITAL_OP_INTERRUPT);
+		if (ui_Type == 1) {
+			//Sends signal to user space
+			send_sig(SIGIO, devpriv->tsk_Current, 0);
+		}		// if (ui_Type==1)
+		else {
+			if (ui_Type == 2) {
+				// Sends signal to user space
+				send_sig(SIGIO, devpriv->tsk_Current, 0);
+			}	//if (ui_Type==2)
+		}		//else if (ui_Type==1)
+	}			//if(ui_DO)
+
+	return;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   :  int i_APCI2032_ReadInterruptStatus                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              :Reads the interrupt status register                     |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI2032_ReadInterruptStatus(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	*data = ui_Type;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   :  int i_APCI2032_Reset(struct comedi_device *dev)			     |
+|					                                                 |
++----------------------------------------------------------------------------+
+| Task              :Resets the registers of the card                        |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI2032_Reset(struct comedi_device * dev)
+{
+	devpriv->b_DigitalOutputRegister = 0;
+	ui_Type = 0;
+	outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP);	//Resets the output channels
+	outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT);	//Disables the interrupt.
+	outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG);	//disable the watchdog
+	outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_RELOAD_VALUE);	//reload=0
+	return 0;
+}

+ 81 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h

@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/*********      Definitions for APCI-2032 card  *****/
+
+// Card Specific information
+#define APCI2032_BOARD_VENDOR_ID                 0x15B8
+#define APCI2032_ADDRESS_RANGE                   63
+
+//DIGITAL INPUT-OUTPUT DEFINE
+
+#define APCI2032_DIGITAL_OP                 	0
+#define APCI2032_DIGITAL_OP_RW                 	0
+#define APCI2032_DIGITAL_OP_INTERRUPT           4
+#define APCI2032_DIGITAL_OP_IRQ                 12
+
+//Digital Output Interrupt Status
+#define APCI2032_DIGITAL_OP_INTERRUPT_STATUS    8
+
+//Digital Output Interrupt Enable Disable.
+#define APCI2032_DIGITAL_OP_VCC_INTERRUPT_ENABLE   0x1
+#define APCI2032_DIGITAL_OP_VCC_INTERRUPT_DISABLE  0xFFFFFFFE
+#define APCI2032_DIGITAL_OP_CC_INTERRUPT_ENABLE    0x2
+#define APCI2032_DIGITAL_OP_CC_INTERRUPT_DISABLE   0xFFFFFFFD
+
+//ADDIDATA Enable Disable
+
+#define ADDIDATA_ENABLE                            1
+#define ADDIDATA_DISABLE                           0
+
+// TIMER COUNTER WATCHDOG DEFINES
+
+#define ADDIDATA_WATCHDOG                          2
+#define APCI2032_DIGITAL_OP_WATCHDOG               16
+#define APCI2032_TCW_RELOAD_VALUE                  4
+#define APCI2032_TCW_TIMEBASE                      8
+#define APCI2032_TCW_PROG                          12
+#define APCI2032_TCW_TRIG_STATUS                   16
+#define APCI2032_TCW_IRQ                           20
+
+// Hardware Layer  functions for Apci2032
+
+//DO
+int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+INT i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+
+// TIMER
+// timer value is passed as u seconds
+INT i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_insn *insn, unsigned int *data);
+int i_APCI2032_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data);
+
+// Interrupt functions.....
+
+void v_APCI2032_Interrupt(int irq, void *d);
+
+//Reset functions
+int i_APCI2032_Reset(struct comedi_device *dev);

+ 549 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c

@@ -0,0 +1,549 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-2200       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci2200.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-2200                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci2200.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_Read1DigitalInput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the digital input                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|		       struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure     |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI2200_Read1DigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_TmpValue = 0;
+	UINT ui_Channel;
+	ui_Channel = CR_CHAN(insn->chanspec);
+	if (ui_Channel >= 0 && ui_Channel <= 7) {
+		ui_TmpValue = (UINT) inw(devpriv->iobase + APCI2200_DIGITAL_IP);
+		*data = (ui_TmpValue >> ui_Channel) & 0x1;
+	}			//if(ui_Channel >= 0 && ui_Channel <=7)
+	else {
+		printk("\nThe specified channel does not exist\n");
+		return -EINVAL;	// "sorry channel spec wrong "
+	}			//else if(ui_Channel >= 0 && ui_Channel <=7)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_ReadMoreDigitalInput                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                     struct comedi_insn *insn,unsigned int *data)                      |
++----------------------------------------------------------------------------+
+| Task              : Return the status of the Requested digital inputs      |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                      struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure     |
+|                      unsigned int *data         : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ui_PortValue = data[0];
+	UINT ui_Mask = 0;
+	UINT ui_NoOfChannels;
+
+	ui_NoOfChannels = CR_CHAN(insn->chanspec);
+
+	*data = (UINT) inw(devpriv->iobase + APCI2200_DIGITAL_IP);
+	switch (ui_NoOfChannels) {
+	case 2:
+		ui_Mask = 3;
+		*data = (*data >> (2 * ui_PortValue)) & ui_Mask;
+		break;
+	case 4:
+		ui_Mask = 15;
+		*data = (*data >> (4 * ui_PortValue)) & ui_Mask;
+		break;
+	case 7:
+		break;
+
+	default:
+		printk("\nWrong parameters\n");
+		return -EINVAL;	// "sorry channel spec wrong "
+		break;
+	}			//switch(ui_NoOfChannels)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_ConfigDigitalOutput (struct comedi_device *dev,
+                    struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data)    |
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Digital Output Subdevice.               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     unsigned int *data         : Data Pointer contains         |
+|                                          configuration parameters as below |
+|                      struct comedi_subdevice *s,   :pointer to subdevice structure
+                       struct comedi_insn *insn      :pointer to insn structure                                                           |
+|					  data[0]  :1:Memory on                          |
+|					            0:Memory off                         |
+|										                             |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI2200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	devpriv->b_OutputMemoryStatus = data[0];
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_WriteDigitalOutput                      |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                     unsigned int *data)                                         |
++----------------------------------------------------------------------------+
+| Task              : Writes port value  To the selected port                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                    unsigned int *data           : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp, ui_Temp1;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp = inw(devpriv->iobase + APCI2200_DIGITAL_OP);
+
+	}			//if(devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			//if(devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outw(data[0], devpriv->iobase + APCI2200_DIGITAL_OP);
+		}		//if(data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 4:
+					data[0] =
+						(data[0] << (4 *
+							data[2])) | ui_Temp;
+					break;
+
+				case 8:
+					data[0] =
+						(data[0] << (8 *
+							data[2])) | ui_Temp;
+					break;
+				case 15:
+					data[0] = data[0] | ui_Temp;
+					break;
+				default:
+					comedi_error(dev, " chan spec wrong");
+					return -EINVAL;	// "sorry channel spec wrong "
+
+				}	//switch(ui_NoOfChannels)
+
+				outw(data[0],
+					devpriv->iobase + APCI2200_DIGITAL_OP);
+			}	// if(data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	//else if(data[1]==1)
+		}		//elseif(data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] = (data[0] << ui_NoOfChannel) ^ 0xffff;
+				data[0] = data[0] & ui_Temp;
+				outw(data[0],
+					devpriv->iobase + APCI2200_DIGITAL_OP);
+			}	//if(data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xffff) & ui_Temp;
+						break;
+
+					case 4:
+						data[0] = ~data[0] & 0xf;
+						ui_Temp1 = 15;
+						ui_Temp1 =
+							ui_Temp1 << 4 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (4 *
+									data
+									[2])) ^
+							0xffff) & ui_Temp;
+						break;
+
+					case 8:
+						data[0] = ~data[0] & 0xff;
+						ui_Temp1 = 255;
+						ui_Temp1 =
+							ui_Temp1 << 8 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (8 *
+									data
+									[2])) ^
+							0xffff) & ui_Temp;
+						break;
+					case 15:
+						break;
+
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+
+					}	//switch(ui_NoOfChannels)
+
+					outw(data[0],
+						devpriv->iobase +
+						APCI2200_DIGITAL_OP);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	return (insn->n);;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_ReadDigitalOutput                       |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data) 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ui_Temp;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+	ui_Temp = data[0];
+	*data = inw(devpriv->iobase + APCI2200_DIGITAL_OP);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			//if(ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			switch (ui_NoOfChannel) {
+
+			case 2:
+				*data = (*data >> (2 * data[1])) & 3;
+				break;
+
+			case 4:
+				*data = (*data >> (4 * data[1])) & 15;
+				break;
+
+			case 8:
+				*data = (*data >> (8 * data[1])) & 255;
+				break;
+
+			case 15:
+				break;
+
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+
+			}	//switch(ui_NoOfChannels)
+		}		//if(ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		//elseif(ui_Temp==1)
+	}			//elseif(ui_Temp==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_ConfigWatchdog(struct comedi_device *dev,
+                      struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)  |
+|				                                                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Watchdog                                |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status                                                                                                             |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI2200_ConfigWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	if (data[0] == 0) {
+		//Disable the watchdog
+		outw(0x0,
+			devpriv->iobase + APCI2200_WATCHDOG +
+			APCI2200_WATCHDOG_ENABLEDISABLE);
+		//Loading the Reload value
+		outw(data[1],
+			devpriv->iobase + APCI2200_WATCHDOG +
+			APCI2200_WATCHDOG_RELOAD_VALUE);
+		data[1] = data[1] >> 16;
+		outw(data[1],
+			devpriv->iobase + APCI2200_WATCHDOG +
+			APCI2200_WATCHDOG_RELOAD_VALUE + 2);
+	}			//if(data[0]==0)
+	else {
+		printk("\nThe input parameters are wrong\n");
+		return -EINVAL;
+	}			//elseif(data[0]==0)
+
+	return insn->n;
+}
+
+ /*
+    +----------------------------------------------------------------------------+
+    | Function   Name   : int i_APCI2200_StartStopWriteWatchdog                  |
+    |                           (struct comedi_device *dev,struct comedi_subdevice *s,
+    struct comedi_insn *insn,unsigned int *data);                      |
+    +----------------------------------------------------------------------------+
+    | Task              : Start / Stop The Watchdog                              |
+    +----------------------------------------------------------------------------+
+    | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+    |                     struct comedi_subdevice *s,   :pointer to subdevice structure
+    struct comedi_insn *insn      :pointer to insn structure      |
+    |                     unsigned int *data          : Data Pointer to read status  |
+    +----------------------------------------------------------------------------+
+    | Output Parameters :       --                                                                                                       |
+    +----------------------------------------------------------------------------+
+    | Return Value      : TRUE  : No error occur                                 |
+    |                       : FALSE : Error occur. Return the error          |
+    |                                                                            |
+    +----------------------------------------------------------------------------+
+  */
+
+int i_APCI2200_StartStopWriteWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	switch (data[0]) {
+	case 0:		//stop the watchdog
+		outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE);	//disable the watchdog
+		break;
+	case 1:		//start the watchdog
+		outw(0x0001,
+			devpriv->iobase + APCI2200_WATCHDOG +
+			APCI2200_WATCHDOG_ENABLEDISABLE);
+		break;
+	case 2:		//Software trigger
+		outw(0x0201,
+			devpriv->iobase + APCI2200_WATCHDOG +
+			APCI2200_WATCHDOG_ENABLEDISABLE);
+		break;
+	default:
+		printk("\nSpecified functionality does not exist\n");
+		return -EINVAL;
+	}			// switch(data[0])
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_ReadWatchdog                            |
+|			(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,
+                    unsigned int *data); 	                                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Watchdog                                      |
++----------------------------------------------------------------------------+
+| Input Parameters  :   struct comedi_device *dev      : Driver handle              |
+|                     struct comedi_subdevice *s,   :pointer to subdevice structure
+                      struct comedi_insn *insn      :pointer to insn structure      |
+|                     unsigned int *data          : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI2200_ReadWatchdog(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	data[0] =
+		inw(devpriv->iobase + APCI2200_WATCHDOG +
+		APCI2200_WATCHDOG_STATUS) & 0x1;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI2200_Reset(struct comedi_device *dev)               |                                                                                                          |
++----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI2200_Reset(struct comedi_device * dev)
+{
+	outw(0x0, devpriv->iobase + APCI2200_DIGITAL_OP);	//RESETS THE DIGITAL OUTPUTS
+	outw(0x0,
+		devpriv->iobase + APCI2200_WATCHDOG +
+		APCI2200_WATCHDOG_ENABLEDISABLE);
+	outw(0x0,
+		devpriv->iobase + APCI2200_WATCHDOG +
+		APCI2200_WATCHDOG_RELOAD_VALUE);
+	outw(0x0,
+		devpriv->iobase + APCI2200_WATCHDOG +
+		APCI2200_WATCHDOG_RELOAD_VALUE + 2);
+	return 0;
+}

+ 61 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h

@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+/*********      Definitions for APCI-2200 card  *****/
+
+// Card Specific information
+#define APCI2200_BOARD_VENDOR_ID                 0x15b8
+#define APCI2200_ADDRESS_RANGE                   64
+
+//DIGITAL INPUT-OUTPUT DEFINE
+
+#define APCI2200_DIGITAL_OP                 	4
+#define APCI2200_DIGITAL_IP                     0
+
+// TIMER COUNTER WATCHDOG DEFINES
+
+#define APCI2200_WATCHDOG                          0x08
+#define APCI2200_WATCHDOG_ENABLEDISABLE            12
+#define APCI2200_WATCHDOG_RELOAD_VALUE             4
+#define APCI2200_WATCHDOG_STATUS                   16
+
+// Hardware Layer  functions for Apci2200
+
+//Digital Input
+INT i_APCI2200_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+INT i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+//Digital Output
+int i_APCI2200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+INT i_APCI2200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI2200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+// TIMER
+int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_insn *insn, unsigned int *data);
+int i_APCI2200_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
+			    struct comedi_insn *insn, unsigned int *data);
+
+//reset
+INT i_APCI2200_Reset(struct comedi_device *dev);

+ 2697 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c

@@ -0,0 +1,2697 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : APCI-3120       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-----------------------------------------------------------------------+
+  | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
+  +-----------------------------------------------------------------------+
+  |                             UPDATE'S                                  |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          | 		 | 						  |
+  |          |           |						  |
+  +----------+-----------+------------------------------------------------+
+*/
+
+#include "hwdrv_apci3120.h"
+static UINT ui_Temp = 0;
+
+// FUNCTION DEFINITIONS
+
+/*
++----------------------------------------------------------------------------+
+|                           ANALOG INPUT SUBDEVICE   		                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,|
+|  struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)					 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : Calls card specific function  					     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data      					         		 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT i;
+
+	if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE))
+		return -1;
+
+	// Check for Conversion time to be added ??
+	devpriv->ui_EocEosConversionTime = data[2];
+
+	if (data[0] == APCI3120_EOS_MODE) {
+
+		//Test the number of the channel
+		for (i = 0; i < data[3]; i++) {
+
+			if (CR_CHAN(data[4 + i]) >= this_board->i_NbrAiChannel) {
+				printk("bad channel list\n");
+				return -2;
+			}
+		}
+
+		devpriv->b_InterruptMode = APCI3120_EOS_MODE;
+
+		if (data[1]) {
+			devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
+		} else
+			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+		// Copy channel list and Range List to devpriv
+
+		devpriv->ui_AiNbrofChannels = data[3];
+		for (i = 0; i < devpriv->ui_AiNbrofChannels; i++) {
+			devpriv->ui_AiChannelList[i] = data[4 + i];
+		}
+
+	} else			// EOC
+	{
+		devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+		if (data[1]) {
+			devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
+		} else {
+			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+		}
+	}
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev,  |
+|			struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data)	 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              :  card specific function								 |
+|				Reads analog input in synchronous mode               |
+|			  EOC and EOS is selected as per configured              |
+|                     if no conversion time is set uses default conversion   |
+|			  time 10 microsec.					      				 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data     									 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	USHORT us_ConvertTiming, us_TmpValue, i;
+	BYTE b_Tmp;
+
+	// fix convertion time to 10 us
+	if (!devpriv->ui_EocEosConversionTime) {
+		printk("No timer0 Value using 10 us\n");
+		us_ConvertTiming = 10;
+	} else
+		us_ConvertTiming = (USHORT) (devpriv->ui_EocEosConversionTime / 1000);	// nano to useconds
+
+	// this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]);
+
+	// Clear software registers
+	devpriv->b_TimerSelectMode = 0;
+	devpriv->b_ModeSelectRegister = 0;
+	devpriv->us_OutputRegister = 0;
+//        devpriv->b_DigitalOutputRegister=0;
+
+	if (insn->unused[0] == 222)	// second insn read
+	{
+
+		for (i = 0; i < insn->n; i++) {
+			data[i] = devpriv->ui_AiReadData[i];
+		}
+
+	} else {
+		devpriv->tsk_Current = current;	// Save the current process task structure
+		//Testing if board have the new Quartz and calculate the time value
+		//to set in the timer
+
+		us_TmpValue =
+			(USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+		//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+		if ((us_TmpValue & 0x00B0) == 0x00B0
+			|| !strcmp(this_board->pc_DriverName, "apci3001")) {
+			us_ConvertTiming = (us_ConvertTiming * 2) - 2;
+		} else {
+			us_ConvertTiming =
+				((us_ConvertTiming * 12926) / 10000) - 1;
+		}
+
+		us_TmpValue = (USHORT) devpriv->b_InterruptMode;
+
+		switch (us_TmpValue) {
+
+		case APCI3120_EOC_MODE:
+
+			// Testing the interrupt flag and set the EOC bit
+			// Clears the FIFO
+			inw(devpriv->iobase + APCI3120_RESET_FIFO);
+
+			// Initialize the sequence array
+
+			//if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0))  return -EINVAL;
+
+			if (!i_APCI3120_SetupChannelList(dev, s, 1,
+					&insn->chanspec, 0))
+				return -EINVAL;
+
+			//Initialize Timer 0 mode 4
+			devpriv->b_TimerSelectMode =
+				(devpriv->
+				b_TimerSelectMode & 0xFC) |
+				APCI3120_TIMER_0_MODE_4;
+			outb(devpriv->b_TimerSelectMode,
+				devpriv->iobase + APCI3120_TIMER_CRT1);
+
+			// Reset the scan bit and Disables the  EOS, DMA, EOC interrupt
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister & APCI3120_DISABLE_SCAN;
+
+			if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
+
+				//Disables the EOS,DMA and enables the EOC interrupt
+				devpriv->b_ModeSelectRegister =
+					(devpriv->
+					b_ModeSelectRegister &
+					APCI3120_DISABLE_EOS_INT) |
+					APCI3120_ENABLE_EOC_INT;
+				inw(devpriv->iobase);
+
+			} else {
+				devpriv->b_ModeSelectRegister =
+					devpriv->
+					b_ModeSelectRegister &
+					APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
+			}
+
+			outb(devpriv->b_ModeSelectRegister,
+				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+			// Sets gate 0
+			devpriv->us_OutputRegister =
+				(devpriv->
+				us_OutputRegister & APCI3120_CLEAR_PA_PR) |
+				APCI3120_ENABLE_TIMER0;
+			outw(devpriv->us_OutputRegister,
+				devpriv->iobase + APCI3120_WR_ADDRESS);
+
+			// Select Timer 0
+			b_Tmp = ((devpriv->
+					b_DigitalOutputRegister) & 0xF0) |
+				APCI3120_SELECT_TIMER_0_WORD;
+			outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+			//Set the convertion time
+			outw(us_ConvertTiming,
+				devpriv->iobase + APCI3120_TIMER_VALUE);
+
+			us_TmpValue =
+				(USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
+
+			if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
+
+				do {
+					// Waiting for the end of conversion
+					us_TmpValue =
+						inw(devpriv->iobase +
+						APCI3120_RD_STATUS);
+				} while ((us_TmpValue & APCI3120_EOC) ==
+					APCI3120_EOC);
+
+				//Read the result in FIFO  and put it in insn data pointer
+				us_TmpValue = inw(devpriv->iobase + 0);
+				*data = us_TmpValue;
+
+				inw(devpriv->iobase + APCI3120_RESET_FIFO);
+			}
+
+			break;
+
+		case APCI3120_EOS_MODE:
+
+			inw(devpriv->iobase);
+			// Clears the FIFO
+			inw(devpriv->iobase + APCI3120_RESET_FIFO);
+			// clear PA PR  and disable timer 0
+
+			devpriv->us_OutputRegister =
+				(devpriv->
+				us_OutputRegister & APCI3120_CLEAR_PA_PR) |
+				APCI3120_DISABLE_TIMER0;
+
+			outw(devpriv->us_OutputRegister,
+				devpriv->iobase + APCI3120_WR_ADDRESS);
+
+			if (!i_APCI3120_SetupChannelList(dev, s,
+					devpriv->ui_AiNbrofChannels,
+					devpriv->ui_AiChannelList, 0))
+				return -EINVAL;
+
+			//Initialize Timer 0 mode 2
+			devpriv->b_TimerSelectMode =
+				(devpriv->
+				b_TimerSelectMode & 0xFC) |
+				APCI3120_TIMER_0_MODE_2;
+			outb(devpriv->b_TimerSelectMode,
+				devpriv->iobase + APCI3120_TIMER_CRT1);
+
+			//Select Timer 0
+			b_Tmp = ((devpriv->
+					b_DigitalOutputRegister) & 0xF0) |
+				APCI3120_SELECT_TIMER_0_WORD;
+			outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+			//Set the convertion time
+			outw(us_ConvertTiming,
+				devpriv->iobase + APCI3120_TIMER_VALUE);
+
+			//Set the scan bit
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister | APCI3120_ENABLE_SCAN;
+			outb(devpriv->b_ModeSelectRegister,
+				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+			//If Interrupt function is loaded
+			if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
+				//Disables the EOC,DMA and enables the EOS interrupt
+				devpriv->b_ModeSelectRegister =
+					(devpriv->
+					b_ModeSelectRegister &
+					APCI3120_DISABLE_EOC_INT) |
+					APCI3120_ENABLE_EOS_INT;
+				inw(devpriv->iobase);
+
+			} else
+				devpriv->b_ModeSelectRegister =
+					devpriv->
+					b_ModeSelectRegister &
+					APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER;
+
+			outb(devpriv->b_ModeSelectRegister,
+				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+			inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+			//Sets gate 0
+
+			devpriv->us_OutputRegister =
+				devpriv->
+				us_OutputRegister | APCI3120_ENABLE_TIMER0;
+			outw(devpriv->us_OutputRegister,
+				devpriv->iobase + APCI3120_WR_ADDRESS);
+
+			//Start conversion
+			outw(0, devpriv->iobase + APCI3120_START_CONVERSION);
+
+			//Waiting of end of convertion if interrupt is not installed
+			if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) {
+				//Waiting the end of convertion
+				do {
+					us_TmpValue =
+						inw(devpriv->iobase +
+						APCI3120_RD_STATUS);
+				}
+				while ((us_TmpValue & APCI3120_EOS) !=
+					APCI3120_EOS);
+
+				for (i = 0; i < devpriv->ui_AiNbrofChannels;
+					i++) {
+					//Read the result in FIFO and write them in shared memory
+					us_TmpValue = inw(devpriv->iobase);
+					data[i] = (UINT) us_TmpValue;
+				}
+
+				devpriv->b_InterruptMode = APCI3120_EOC_MODE;	// Restore defaults.
+			}
+			break;
+
+		default:
+			printk("inputs wrong\n");
+
+		}
+		devpriv->ui_EocEosConversionTime = 0;	// re initializing the variable;
+	}
+
+	return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,|
+| 											     struct comedi_subdevice *s)|
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Stops Cyclic acquisition  						     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :0              					                     |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s)
+{
+	// Disable A2P Fifo write and AMWEN signal
+	outw(0, devpriv->i_IobaseAddon + 4);
+
+	//Disable Bus Master ADD ON
+	outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+	outw(0, devpriv->i_IobaseAddon + 2);
+	outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+	outw(0, devpriv->i_IobaseAddon + 2);
+
+	//Disable BUS Master PCI
+	outl(0, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
+
+	//outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR)&(~AINT_WRITE_COMPL), devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);    // stop amcc irqs
+	//outl(inl(devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR)&(~EN_A2P_TRANSFERS), devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); // stop DMA
+
+	//Disable ext trigger
+	i_APCI3120_ExttrigDisable(dev);
+
+	devpriv->us_OutputRegister = 0;
+	//stop  counters
+	outw(devpriv->
+		us_OutputRegister & APCI3120_DISABLE_TIMER0 &
+		APCI3120_DISABLE_TIMER1, dev->iobase + APCI3120_WR_ADDRESS);
+
+	outw(APCI3120_DISABLE_ALL_TIMER, dev->iobase + APCI3120_WR_ADDRESS);
+
+	//DISABLE_ALL_INTERRUPT
+	outb(APCI3120_DISABLE_ALL_INTERRUPT,
+		dev->iobase + APCI3120_WRITE_MODE_SELECT);
+	//Flush FIFO
+	inb(dev->iobase + APCI3120_RESET_FIFO);
+	inw(dev->iobase + APCI3120_RD_STATUS);
+	devpriv->ui_AiActualScan = 0;
+	devpriv->ui_AiActualScanPosition = 0;
+	s->async->cur_chan = 0;
+	devpriv->ui_AiBufferPtr = 0;
+	devpriv->b_AiContinuous = 0;
+	devpriv->ui_DmaActualBuffer = 0;
+
+	devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+	devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+	devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+	i_APCI3120_Reset(dev);
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev|
+|			,struct comedi_subdevice *s,struct comedi_cmd *cmd)					 |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Test validity for a command for cyclic anlog input     |
+|                       acquisition  						     			 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_cmd *cmd              					         |
++----------------------------------------------------------------------------+
+| Return Value      :0              					                     |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_cmd * cmd)
+{
+	int err = 0;
+	int tmp;		// divisor1,divisor2;
+
+	// step 1: make sure trigger sources are trivially valid
+
+	tmp = cmd->start_src;
+	cmd->start_src &= TRIG_NOW | TRIG_EXT;
+	if (!cmd->start_src || tmp != cmd->start_src)
+		err++;
+
+	tmp = cmd->scan_begin_src;
+	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
+	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
+		err++;
+
+	tmp = cmd->convert_src;
+	cmd->convert_src &= TRIG_TIMER;
+	if (!cmd->convert_src || tmp != cmd->convert_src)
+		err++;
+
+	tmp = cmd->scan_end_src;
+	cmd->scan_end_src &= TRIG_COUNT;
+	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
+		err++;
+
+	tmp = cmd->stop_src;
+	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
+	if (!cmd->stop_src || tmp != cmd->stop_src)
+		err++;
+
+	if (err)
+		return 1;
+
+	//step 2: make sure trigger sources are unique and mutually compatible
+
+	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
+		err++;
+	}
+
+	if (cmd->scan_begin_src != TRIG_TIMER &&
+		cmd->scan_begin_src != TRIG_FOLLOW)
+		err++;
+
+	if (cmd->convert_src != TRIG_TIMER)
+		err++;
+
+	if (cmd->scan_end_src != TRIG_COUNT) {
+		cmd->scan_end_src = TRIG_COUNT;
+		err++;
+	}
+
+	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
+		err++;
+
+	if (err)
+		return 2;
+
+	// step 3: make sure arguments are trivially compatible
+
+	if (cmd->start_arg != 0) {
+		cmd->start_arg = 0;
+		err++;
+	}
+
+	if (cmd->scan_begin_src == TRIG_TIMER)	// Test Delay timing
+	{
+		if (cmd->scan_begin_arg < this_board->ui_MinDelaytimeNs) {
+			cmd->scan_begin_arg = this_board->ui_MinDelaytimeNs;
+			err++;
+		}
+	}
+
+	if (cmd->convert_src == TRIG_TIMER)	// Test Acquisition timing
+	{
+		if (cmd->scan_begin_src == TRIG_TIMER) {
+			if ((cmd->convert_arg)
+				&& (cmd->convert_arg <
+					this_board->ui_MinAcquisitiontimeNs)) {
+				cmd->convert_arg =
+					this_board->ui_MinAcquisitiontimeNs;
+				err++;
+			}
+		} else {
+			if (cmd->convert_arg <
+				this_board->ui_MinAcquisitiontimeNs) {
+				cmd->convert_arg =
+					this_board->ui_MinAcquisitiontimeNs;
+				err++;
+
+			}
+		}
+	}
+
+	if (!cmd->chanlist_len) {
+		cmd->chanlist_len = 1;
+		err++;
+	}
+	if (cmd->chanlist_len > this_board->i_AiChannelList) {
+		cmd->chanlist_len = this_board->i_AiChannelList;
+		err++;
+	}
+	if (cmd->stop_src == TRIG_COUNT) {
+		if (!cmd->stop_arg) {
+			cmd->stop_arg = 1;
+			err++;
+		}
+	} else {		// TRIG_NONE
+		if (cmd->stop_arg != 0) {
+			cmd->stop_arg = 0;
+			err++;
+		}
+	}
+
+	if (err)
+		return 3;
+
+	// step 4: fix up any arguments
+
+	if (cmd->convert_src == TRIG_TIMER) {
+
+		if (cmd->scan_begin_src == TRIG_TIMER &&
+			cmd->scan_begin_arg <
+			cmd->convert_arg * cmd->scan_end_arg) {
+			cmd->scan_begin_arg =
+				cmd->convert_arg * cmd->scan_end_arg;
+			err++;
+		}
+	}
+
+	if (err)
+		return 4;
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev,  |
+|												struct comedi_subdevice *s) |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Does asynchronous acquisition                          |
+|                     Determines the mode 1 or 2.						     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     														 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s)
+{
+	struct comedi_cmd *cmd = &s->async->cmd;
+
+	//loading private structure with cmd structure inputs
+	devpriv->ui_AiFlags = cmd->flags;
+	devpriv->ui_AiNbrofChannels = cmd->chanlist_len;
+	devpriv->ui_AiScanLength = cmd->scan_end_arg;
+	devpriv->pui_AiChannelList = cmd->chanlist;
+
+	//UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data;
+	devpriv->AiData = s->async->prealloc_buf;
+	//UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len;
+	devpriv->ui_AiDataLength = s->async->prealloc_bufsz;
+
+	if (cmd->stop_src == TRIG_COUNT) {
+		devpriv->ui_AiNbrofScans = cmd->stop_arg;
+	} else {
+		devpriv->ui_AiNbrofScans = 0;
+	}
+
+	devpriv->ui_AiTimer0 = 0;	// variables changed to timer0,timer1
+	devpriv->ui_AiTimer1 = 0;
+	if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1))
+		devpriv->b_AiContinuous = 1;	// user want neverending analog acquisition
+	// stopped using cancel
+
+	if (cmd->start_src == TRIG_EXT)
+		devpriv->b_ExttrigEnable = APCI3120_ENABLE;
+	else
+		devpriv->b_ExttrigEnable = APCI3120_DISABLE;
+
+	if (cmd->scan_begin_src == TRIG_FOLLOW) {
+		// mode 1 or 3
+		if (cmd->convert_src == TRIG_TIMER) {
+			// mode 1
+
+			devpriv->ui_AiTimer0 = cmd->convert_arg;	// timer constant in nano seconds
+			//return this_board->i_hwdrv_CommandAnalogInput(1,dev,s);
+			return i_APCI3120_CyclicAnalogInput(1, dev, s);
+		}
+
+	}
+	if ((cmd->scan_begin_src == TRIG_TIMER)
+		&& (cmd->convert_src == TRIG_TIMER)) {
+		// mode 2
+		devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
+		devpriv->ui_AiTimer0 = cmd->convert_arg;	// variable changed timer2 to timer0
+		//return this_board->i_hwdrv_CommandAnalogInput(2,dev,s);
+		return i_APCI3120_CyclicAnalogInput(2, dev, s);
+	}
+	return -1;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :  int i_APCI3120_CyclicAnalogInput(int mode,            |
+|		 	   struct comedi_device * dev,struct comedi_subdevice * s)			 |
++----------------------------------------------------------------------------+
+| Task              : This is used for analog input cyclic acquisition       |
+|			  Performs the command operations.                       |
+|			  If DMA is configured does DMA initialization           |
+|			  otherwise does the acquisition with EOS interrupt.     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 														 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device * dev,
+	struct comedi_subdevice * s)
+{
+	BYTE b_Tmp;
+	UINT ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 =
+		0, dmalen1 = 0, ui_TimerValue2 =
+		0, ui_TimerValue0, ui_ConvertTiming;
+	USHORT us_TmpValue;
+
+	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+	//devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE;
+	//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+	/*******************/
+	/* Resets the FIFO */
+	/*******************/
+	inb(dev->iobase + APCI3120_RESET_FIFO);
+
+	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+	//inw(dev->iobase+APCI3120_RD_STATUS);
+	//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+	/***************************/
+	/* Acquisition initialized */
+	/***************************/
+	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+	devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE;
+	//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+	// clear software  registers
+	devpriv->b_TimerSelectMode = 0;
+	devpriv->us_OutputRegister = 0;
+	devpriv->b_ModeSelectRegister = 0;
+	//devpriv->b_DigitalOutputRegister=0;
+
+	//COMMENT JK 07.05.04: Followings calls are in i_APCI3120_StartAnalogInputAcquisition
+
+   /****************************/
+	/* Clear Timer Write TC INT */
+   /****************************/
+	outl(APCI3120_CLEAR_WRITE_TC_INT,
+		devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_REG_INTCSR);
+
+   /************************************/
+	/* Clears the timer status register */
+   /************************************/
+	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+	//inw(dev->iobase+APCI3120_TIMER_STATUS_REGISTER);
+	inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+	//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+   /**************************/
+	/* Disables All Timer     */
+	/* Sets PR and PA to 0    */
+   /**************************/
+	devpriv->us_OutputRegister = devpriv->us_OutputRegister &
+		APCI3120_DISABLE_TIMER0 &
+		APCI3120_DISABLE_TIMER1 & APCI3120_CLEAR_PA_PR;
+
+	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+
+   /*******************/
+	/* Resets the FIFO */
+   /*******************/
+	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+	inb(devpriv->iobase + APCI3120_RESET_FIFO);
+	//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+	devpriv->ui_AiActualScan = 0;
+	devpriv->ui_AiActualScanPosition = 0;
+	s->async->cur_chan = 0;
+	devpriv->ui_AiBufferPtr = 0;
+	devpriv->ui_DmaActualBuffer = 0;
+
+	// value for timer2  minus -2 has to be done .....dunno y??
+	ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2;
+	ui_ConvertTiming = devpriv->ui_AiTimer0;
+
+	if (mode == 2)
+		ui_DelayTiming = devpriv->ui_AiTimer1;
+
+   /**********************************/
+	/* Initializes the sequence array */
+   /**********************************/
+	if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels,
+			devpriv->pui_AiChannelList, 0))
+		return -EINVAL;
+
+	us_TmpValue = (USHORT) inw(dev->iobase + APCI3120_RD_STATUS);
+/*** EL241003 : add this section in comment because floats must not be used
+	 if((us_TmpValue & 0x00B0)==0x00B0)
+	 {
+           f_ConvertValue=(((float)ui_ConvertTiming * 0.002) - 2);
+		ui_TimerValue0=(UINT)f_ConvertValue;
+		if (mode==2)
+		{
+			f_DelayValue     = (((float)ui_DelayTiming * 0.00002) - 2);
+			ui_TimerValue1  =   (UINT) f_DelayValue;
+		}
+	 }
+   	 else
+	 {
+		f_ConvertValue=(((float)ui_ConvertTiming * 0.0012926) - 1);
+		ui_TimerValue0=(UINT)f_ConvertValue;
+		if (mode == 2)
+		{
+		     f_DelayValue     = (((float)ui_DelayTiming * 0.000012926) - 1);
+		     ui_TimerValue1  =   (UINT) f_DelayValue;
+		}
+	}
+***********************************************************************************************/
+/*** EL241003 Begin : add this section to replace floats calculation by integer calculations **/
+	//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+	if ((us_TmpValue & 0x00B0) == 0x00B0
+		|| !strcmp(this_board->pc_DriverName, "apci3001")) {
+		ui_TimerValue0 = ui_ConvertTiming * 2 - 2000;
+		ui_TimerValue0 = ui_TimerValue0 / 1000;
+
+		if (mode == 2) {
+			ui_DelayTiming = ui_DelayTiming / 1000;
+			ui_TimerValue1 = ui_DelayTiming * 2 - 200;
+			ui_TimerValue1 = ui_TimerValue1 / 100;
+		}
+	} else {
+		ui_ConvertTiming = ui_ConvertTiming / 1000;
+		ui_TimerValue0 = ui_ConvertTiming * 12926 - 10000;
+		ui_TimerValue0 = ui_TimerValue0 / 10000;
+
+		if (mode == 2) {
+			ui_DelayTiming = ui_DelayTiming / 1000;
+			ui_TimerValue1 = ui_DelayTiming * 12926 - 1;
+			ui_TimerValue1 = ui_TimerValue1 / 1000000;
+		}
+	}
+/*** EL241003 End ******************************************************************************/
+
+	if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
+		i_APCI3120_ExttrigEnable(dev);	// activate EXT trigger
+	}
+	switch (mode) {
+	case 1:
+		// init timer0 in mode 2
+		devpriv->b_TimerSelectMode =
+			(devpriv->
+			b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
+		outb(devpriv->b_TimerSelectMode,
+			dev->iobase + APCI3120_TIMER_CRT1);
+
+		//Select Timer 0
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_0_WORD;
+		outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+		//Set the convertion time
+		outw(((USHORT) ui_TimerValue0),
+			dev->iobase + APCI3120_TIMER_VALUE);
+		break;
+
+	case 2:
+		// init timer1 in mode 2
+		devpriv->b_TimerSelectMode =
+			(devpriv->
+			b_TimerSelectMode & 0xF3) | APCI3120_TIMER_1_MODE_2;
+		outb(devpriv->b_TimerSelectMode,
+			dev->iobase + APCI3120_TIMER_CRT1);
+
+		//Select Timer 1
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_1_WORD;
+		outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+		//Set the convertion time
+		outw(((USHORT) ui_TimerValue1),
+			dev->iobase + APCI3120_TIMER_VALUE);
+
+		// init timer0 in mode 2
+		devpriv->b_TimerSelectMode =
+			(devpriv->
+			b_TimerSelectMode & 0xFC) | APCI3120_TIMER_0_MODE_2;
+		outb(devpriv->b_TimerSelectMode,
+			dev->iobase + APCI3120_TIMER_CRT1);
+
+		//Select Timer 0
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_0_WORD;
+		outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+
+		//Set the convertion time
+		outw(((USHORT) ui_TimerValue0),
+			dev->iobase + APCI3120_TIMER_VALUE);
+		break;
+
+	}
+	//   ##########common for all modes#################
+
+	/***********************/
+	/* Clears the SCAN bit */
+	/***********************/
+	//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+	//devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister | APCI3120_DISABLE_SCAN;
+	devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
+		APCI3120_DISABLE_SCAN;
+	//END JK 07.05.04: Comparison between WIN32 and Linux driver
+	outb(devpriv->b_ModeSelectRegister,
+		dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+	// If DMA is disabled
+	if (devpriv->us_UseDma == APCI3120_DISABLE) {
+		// disable EOC and enable EOS
+		devpriv->b_InterruptMode = APCI3120_EOS_MODE;
+		devpriv->b_EocEosInterrupt = APCI3120_ENABLE;
+
+		devpriv->b_ModeSelectRegister =
+			(devpriv->
+			b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT) |
+			APCI3120_ENABLE_EOS_INT;
+		outb(devpriv->b_ModeSelectRegister,
+			dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+		if (!devpriv->b_AiContinuous) {
+			// configure Timer2 For counting  EOS
+			//Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
+			devpriv->us_OutputRegister =
+				devpriv->
+				us_OutputRegister & APCI3120_DISABLE_TIMER2;
+			outw(devpriv->us_OutputRegister,
+				dev->iobase + APCI3120_WR_ADDRESS);
+
+			// DISABLE TIMER INTERRUPT
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister &
+				APCI3120_DISABLE_TIMER_INT & 0xEF;
+			outb(devpriv->b_ModeSelectRegister,
+				dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+			//(1) Init timer 2 in mode 0 and write timer value
+			devpriv->b_TimerSelectMode =
+				(devpriv->
+				b_TimerSelectMode & 0x0F) |
+				APCI3120_TIMER_2_MODE_0;
+			outb(devpriv->b_TimerSelectMode,
+				dev->iobase + APCI3120_TIMER_CRT1);
+
+			//Writing LOW WORD
+			b_Tmp = ((devpriv->
+					b_DigitalOutputRegister) & 0xF0) |
+				APCI3120_SELECT_TIMER_2_LOW_WORD;
+			outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+			outw(LOWORD(ui_TimerValue2),
+				dev->iobase + APCI3120_TIMER_VALUE);
+
+			//Writing HIGH WORD
+			b_Tmp = ((devpriv->
+					b_DigitalOutputRegister) & 0xF0) |
+				APCI3120_SELECT_TIMER_2_HIGH_WORD;
+			outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0);
+			outw(HIWORD(ui_TimerValue2),
+				dev->iobase + APCI3120_TIMER_VALUE);
+
+			//(2) Reset FC_TIMER BIT  Clearing timer status register
+			inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+			// enable timer counter and disable watch dog
+			devpriv->b_ModeSelectRegister =
+				(devpriv->
+				b_ModeSelectRegister |
+				APCI3120_ENABLE_TIMER_COUNTER) &
+				APCI3120_DISABLE_WATCHDOG;
+			// select EOS clock input for timer 2
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister |
+				APCI3120_TIMER2_SELECT_EOS;
+			// Enable timer2  interrupt
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister |
+				APCI3120_ENABLE_TIMER_INT;
+			outb(devpriv->b_ModeSelectRegister,
+				dev->iobase + APCI3120_WRITE_MODE_SELECT);
+			devpriv->b_Timer2Mode = APCI3120_COUNTER;
+			devpriv->b_Timer2Interrupt = APCI3120_ENABLE;
+		}
+	} else {
+		// If DMA Enabled
+		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+		//inw(dev->iobase+0);// reset EOC bit
+		//END JK 07.05.04: Comparison between WIN32 and Linux driver
+		devpriv->b_InterruptMode = APCI3120_DMA_MODE;
+
+      /************************************/
+		/* Disables the EOC, EOS interrupt  */
+	  /************************************/
+		devpriv->b_ModeSelectRegister = devpriv->b_ModeSelectRegister &
+			APCI3120_DISABLE_EOC_INT & APCI3120_DISABLE_EOS_INT;
+
+		outb(devpriv->b_ModeSelectRegister,
+			dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+		dmalen0 = devpriv->ui_DmaBufferSize[0];
+		dmalen1 = devpriv->ui_DmaBufferSize[1];
+
+		if (!devpriv->b_AiContinuous) {
+
+			if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) {	// must we fill full first buffer?
+				dmalen0 =
+					devpriv->ui_AiNbrofScans *
+					devpriv->ui_AiScanLength * 2;
+			} else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0))	// and must we fill full second buffer when first is once filled?
+				dmalen1 =
+					devpriv->ui_AiNbrofScans *
+					devpriv->ui_AiScanLength * 2 - dmalen0;
+		}
+
+		if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) {
+			// don't we want wake up every scan?
+			if (dmalen0 > (devpriv->ui_AiScanLength * 2)) {
+				dmalen0 = devpriv->ui_AiScanLength * 2;
+				if (devpriv->ui_AiScanLength & 1)
+					dmalen0 += 2;
+			}
+			if (dmalen1 > (devpriv->ui_AiScanLength * 2)) {
+				dmalen1 = devpriv->ui_AiScanLength * 2;
+				if (devpriv->ui_AiScanLength & 1)
+					dmalen1 -= 2;
+				if (dmalen1 < 4)
+					dmalen1 = 4;
+			}
+		} else {	// isn't output buff smaller that our DMA buff?
+			if (dmalen0 > (devpriv->ui_AiDataLength)) {
+				dmalen0 = devpriv->ui_AiDataLength;
+			}
+			if (dmalen1 > (devpriv->ui_AiDataLength)) {
+				dmalen1 = devpriv->ui_AiDataLength;
+			}
+		}
+		devpriv->ui_DmaBufferUsesize[0] = dmalen0;
+		devpriv->ui_DmaBufferUsesize[1] = dmalen1;
+
+		//Initialize DMA
+
+		// Set Transfer count enable bit and A2P_fifo reset bit in AGCSTS register
+		//1
+		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
+		outl(ui_Tmp, devpriv->i_IobaseAmcc + AMCC_OP_REG_AGCSTS);
+
+		// changed  since 16 bit interface for add on
+		/*********************/
+		/* ENABLE BUS MASTER */
+		/*********************/
+		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
+			devpriv->i_IobaseAddon + 2);
+
+		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH,
+			devpriv->i_IobaseAddon + 2);
+
+		// TO VERIFIED
+		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+		outw(0x1000, devpriv->i_IobaseAddon + 2);
+		//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+		//2  No change
+		// A2P FIFO MANAGEMENT
+		// A2P fifo reset  & transfer control enable
+		 /***********************/
+		/* A2P FIFO MANAGEMENT */
+		 /***********************/
+		outl(APCI3120_A2P_FIFO_MANAGEMENT, devpriv->i_IobaseAmcc +
+			APCI3120_AMCC_OP_MCSR);
+
+		//3
+		//beginning address of dma buf
+		//The 32 bit address of dma buffer is converted into two 16 bit addresses
+		// Can done by using _attach and put into into an array
+		// array used may be for differnet pages
+
+		// DMA Start Adress Low
+		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
+		outw((devpriv->ul_DmaBufferHw[0] & 0xFFFF),
+			devpriv->i_IobaseAddon + 2);
+
+		 /*************************/
+		/* DMA Start Adress High */
+		 /*************************/
+		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
+		outw((devpriv->ul_DmaBufferHw[0] / 65536),
+			devpriv->i_IobaseAddon + 2);
+
+		//4
+		// amount of bytes to be transfered  set transfer count
+		// used ADDON MWTC register
+		//commented testing             outl(devpriv->ui_DmaBufferUsesize[0], devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC);
+
+		 /**************************/
+		/* Nbr of acquisition LOW */
+		 /**************************/
+		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
+		outw((devpriv->ui_DmaBufferUsesize[0] & 0xFFFF),
+			devpriv->i_IobaseAddon + 2);
+
+		 /***************************/
+		/* Nbr of acquisition HIGH */
+		 /***************************/
+		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
+		outw((devpriv->ui_DmaBufferUsesize[0] / 65536),
+			devpriv->i_IobaseAddon + 2);
+
+		//5
+		// To configure A2P FIFO
+		// testing outl( FIFO_ADVANCE_ON_BYTE_2,devpriv->i_IobaseAmcc+AMCC_OP_REG_INTCSR);
+
+		/******************/
+		/* A2P FIFO RESET */
+		/******************/
+		// TO VERIFY
+		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+		outl(0x04000000UL, devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
+		//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+		//6
+		//ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+		//outw(3,devpriv->i_IobaseAddon + 4);
+		//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+		//7
+		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
+		/***************************************************/
+		/* A2P FIFO CONFIGURATE, END OF DMA INTERRUPT INIT */
+		/***************************************************/
+		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
+				APCI3120_ENABLE_WRITE_TC_INT),
+			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
+
+		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+		/******************************************/
+		/* ENABLE A2P FIFO WRITE AND ENABLE AMWEN */
+		/******************************************/
+		outw(3, devpriv->i_IobaseAddon + 4);
+		//END JK 07.05.04: Comparison between WIN32 and Linux driver
+
+		/******************/
+		/* A2P FIFO RESET */
+		/******************/
+		//BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver
+		outl(0x04000000UL,
+			devpriv->i_IobaseAmcc + APCI3120_AMCC_OP_MCSR);
+		//END JK 07.05.04: Comparison between WIN32 and Linux driver
+	}
+
+	if ((devpriv->us_UseDma == APCI3120_DISABLE)
+		&& !devpriv->b_AiContinuous) {
+		// set gate 2   to start conversion
+		devpriv->us_OutputRegister =
+			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2;
+		outw(devpriv->us_OutputRegister,
+			dev->iobase + APCI3120_WR_ADDRESS);
+	}
+
+	switch (mode) {
+	case 1:
+		// set gate 0   to start conversion
+		devpriv->us_OutputRegister =
+			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
+		outw(devpriv->us_OutputRegister,
+			dev->iobase + APCI3120_WR_ADDRESS);
+		break;
+	case 2:
+		// set  gate 0 and gate 1
+		devpriv->us_OutputRegister =
+			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER1;
+		devpriv->us_OutputRegister =
+			devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER0;
+		outw(devpriv->us_OutputRegister,
+			dev->iobase + APCI3120_WR_ADDRESS);
+		break;
+
+	}
+
+	return 0;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| 			INTERNAL FUNCTIONS						                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_Reset(struct comedi_device *dev)               |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : Hardware reset function   						     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 	struct comedi_device *dev									 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_Reset(struct comedi_device * dev)
+{
+	unsigned int i;
+	unsigned short us_TmpValue;
+
+	devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+	devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+	devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+	devpriv->ui_EocEosConversionTime = 0;	// set eoc eos conv time to 0
+	devpriv->b_OutputMemoryStatus = 0;
+
+	// variables used in timer subdevice
+	devpriv->b_Timer2Mode = 0;
+	devpriv->b_Timer2Interrupt = 0;
+	devpriv->b_ExttrigEnable = 0;	// Disable ext trigger
+
+	/* Disable all interrupts, watchdog for the anolog output */
+	devpriv->b_ModeSelectRegister = 0;
+	outb(devpriv->b_ModeSelectRegister,
+		dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+	// Disables all counters, ext trigger and clears PA, PR
+	devpriv->us_OutputRegister = 0;
+	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+
+	//Code to set the all anolog o/p channel to 0v
+	//8191 is decimal value for zero(0 v)volt in bipolar mode(default)
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_1, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 1
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_2, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 2
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_3, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 3
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1);	//channel 4
+
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 5
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 6
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_7, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 7
+	outw(8191 | APCI3120_ANALOG_OP_CHANNEL_8, dev->iobase + APCI3120_ANALOG_OUTPUT_2);	//channel 8
+
+	//  Reset digital output to L0W
+
+//ES05  outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT);
+	udelay(10);
+
+	inw(dev->iobase + 0);	//make a dummy read
+	inb(dev->iobase + APCI3120_RESET_FIFO);	// flush FIFO
+	inw(dev->iobase + APCI3120_RD_STATUS);	// flush A/D status register
+
+	//code to reset the RAM sequence
+	for (i = 0; i < 16; i++) {
+		us_TmpValue = i << 8;	//select the location
+		outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
+	}
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_SetupChannelList(struct comedi_device * dev,   |
+|                     struct comedi_subdevice * s, int n_chan,unsigned int *chanlist|
+|			  ,char check)											 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              :This function will first check channel list is ok or not|
+|and then initialize the sequence RAM with the polarity, Gain,Channel number |
+|If the last argument of function "check"is 1 then it only checks the channel|
+|list is ok or not.												     		 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device * dev									 |
+|                     struct comedi_subdevice * s									 |
+|                     int n_chan                   					         |
+			  unsigned int *chanlist
+			  char check
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_SetupChannelList(struct comedi_device * dev, struct comedi_subdevice * s,
+	int n_chan, unsigned int *chanlist, char check)
+{
+	unsigned int i;		//, differencial=0, bipolar=0;
+	unsigned int gain;
+	unsigned short us_TmpValue;
+
+	/* correct channel and range number check itself comedi/range.c */
+	if (n_chan < 1) {
+		if (!check)
+			comedi_error(dev, "range/channel list is empty!");
+		return 0;
+	}
+	// All is ok, so we can setup channel/range list
+	if (check)
+		return 1;
+
+	//Code  to set the PA and PR...Here it set PA to 0..
+	devpriv->us_OutputRegister =
+		devpriv->us_OutputRegister & APCI3120_CLEAR_PA_PR;
+	devpriv->us_OutputRegister = ((n_chan - 1) & 0xf) << 8;
+	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+
+	for (i = 0; i < n_chan; i++) {
+		// store range list to card
+		us_TmpValue = CR_CHAN(chanlist[i]);	// get channel number;
+
+		if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) {
+			us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff);	// set bipolar
+		} else {
+			us_TmpValue |= APCI3120_UNIPOLAR;	// enable unipolar......
+		}
+
+		gain = CR_RANGE(chanlist[i]);	// get gain number
+		us_TmpValue |= ((gain & 0x03) << 4);	//<<4 for G0 and G1 bit in RAM
+		us_TmpValue |= i << 8;	//To select the RAM LOCATION....
+		outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS);
+
+		printk("\n Gain = %i",
+			(((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2));
+		printk("\n Channel = %i", CR_CHAN(chanlist[i]));
+		printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR);
+	}
+	return 1;		// we can serve this with scan logic
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :	int i_APCI3120_ExttrigEnable(struct comedi_device * dev)    |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : 	Enable the external trigger						     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 	struct comedi_device * dev									 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :      0        					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_ExttrigEnable(struct comedi_device * dev)
+{
+
+	devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER;
+	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : 	int i_APCI3120_ExttrigDisable(struct comedi_device * dev)   |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : 	Disables the external trigger					     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 	struct comedi_device * dev									 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :    0          					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_ExttrigDisable(struct comedi_device * dev)
+{
+	devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER;
+	outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS);
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                    INTERRUPT FUNCTIONS		    		                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : void v_APCI3120_Interrupt(int irq, void *d) 								 |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              :Interrupt handler for APCI3120                        	 |
+|			 When interrupt occurs this gets called.                 |
+|			 First it finds which interrupt has been generated and   |
+|			 handles  corresponding interrupt                        |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 	int irq 											 |
+|                        void *d											 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      : void         					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI3120_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	USHORT int_daq;
+
+	unsigned int int_amcc, ui_Check, i;
+	USHORT us_TmpValue;
+	BYTE b_DummyRead;
+
+	struct comedi_subdevice *s = dev->subdevices + 0;
+	ui_Check = 1;
+
+	int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000;	// get IRQ reasons
+	int_amcc = inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);	// get AMCC INT register
+
+	if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) {
+		comedi_error(dev, "IRQ from unknow source");
+		return;
+	}
+
+	outl(int_amcc | 0x00ff0000, devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);	// shutdown IRQ reasons in AMCC
+
+	int_daq = (int_daq >> 12) & 0xF;
+
+	if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) {
+		//Disable ext trigger
+		i_APCI3120_ExttrigDisable(dev);
+		devpriv->b_ExttrigEnable = APCI3120_DISABLE;
+	}
+	//clear the timer 2 interrupt
+	inb(devpriv->i_IobaseAmcc + APCI3120_TIMER_STATUS_REGISTER);
+
+	if (int_amcc & MASTER_ABORT_INT)
+		comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!");
+	if (int_amcc & TARGET_ABORT_INT)
+		comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!");
+
+	// Ckeck if EOC interrupt
+	if (((int_daq & 0x8) == 0)
+		&& (devpriv->b_InterruptMode == APCI3120_EOC_MODE)) {
+		if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) {
+
+			// Read the AI Value
+
+			devpriv->ui_AiReadData[0] =
+				(UINT) inw(devpriv->iobase + 0);
+			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+			send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+		} else {
+			//Disable EOC Interrupt
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT;
+			outb(devpriv->b_ModeSelectRegister,
+				devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+		}
+	}
+
+	// Check If EOS interrupt
+	if ((int_daq & 0x2) && (devpriv->b_InterruptMode == APCI3120_EOS_MODE)) {
+
+		if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE)	// enable this in without DMA ???
+		{
+
+			if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
+				ui_Check = 0;
+				i_APCI3120_InterruptHandleEos(dev);
+				devpriv->ui_AiActualScan++;
+				devpriv->b_ModeSelectRegister =
+					devpriv->
+					b_ModeSelectRegister |
+					APCI3120_ENABLE_EOS_INT;
+				outb(devpriv->b_ModeSelectRegister,
+					dev->iobase +
+					APCI3120_WRITE_MODE_SELECT);
+			} else {
+				ui_Check = 0;
+				for (i = 0; i < devpriv->ui_AiNbrofChannels;
+					i++) {
+					us_TmpValue = inw(devpriv->iobase + 0);
+					devpriv->ui_AiReadData[i] =
+						(UINT) us_TmpValue;
+				}
+				devpriv->b_EocEosInterrupt = APCI3120_DISABLE;
+				devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+
+				send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+
+			}
+
+		} else {
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
+			outb(devpriv->b_ModeSelectRegister,
+				dev->iobase + APCI3120_WRITE_MODE_SELECT);
+			devpriv->b_EocEosInterrupt = APCI3120_DISABLE;	//Default settings
+			devpriv->b_InterruptMode = APCI3120_EOC_MODE;
+		}
+
+	}
+	//Timer2 interrupt
+	if (int_daq & 0x1) {
+
+		switch (devpriv->b_Timer2Mode) {
+		case APCI3120_COUNTER:
+
+			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT;
+			outb(devpriv->b_ModeSelectRegister,
+				dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+			// stop timer 2
+			devpriv->us_OutputRegister =
+				devpriv->
+				us_OutputRegister & APCI3120_DISABLE_ALL_TIMER;
+			outw(devpriv->us_OutputRegister,
+				dev->iobase + APCI3120_WR_ADDRESS);
+
+			//stop timer 0 and timer 1
+			i_APCI3120_StopCyclicAcquisition(dev, s);
+			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+
+			//UPDATE-0.7.57->0.7.68comedi_done(dev,s);
+			s->async->events |= COMEDI_CB_EOA;
+			comedi_event(dev, s);
+
+			break;
+
+		case APCI3120_TIMER:
+
+			//Send a signal to from kernel to user space
+			send_sig(SIGIO, devpriv->tsk_Current, 0);
+			break;
+
+		case APCI3120_WATCHDOG:
+
+			//Send a signal to from kernel to user space
+			send_sig(SIGIO, devpriv->tsk_Current, 0);
+			break;
+
+		default:
+
+			// disable Timer Interrupt
+
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister &
+				APCI3120_DISABLE_TIMER_INT;
+
+			outb(devpriv->b_ModeSelectRegister,
+				dev->iobase + APCI3120_WRITE_MODE_SELECT);
+
+		}
+
+		b_DummyRead = inb(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+
+	}
+
+	if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) {
+		if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) {
+
+			/****************************/
+			/* Clear Timer Write TC INT */
+			/****************************/
+
+			outl(APCI3120_CLEAR_WRITE_TC_INT,
+				devpriv->i_IobaseAmcc +
+				APCI3120_AMCC_OP_REG_INTCSR);
+
+			/************************************/
+			/* Clears the timer status register */
+			/************************************/
+			inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER);
+			v_APCI3120_InterruptDma(irq, d);	// do some data transfer
+		} else {
+			/* Stops the Timer */
+			outw(devpriv->
+				us_OutputRegister & APCI3120_DISABLE_TIMER0 &
+				APCI3120_DISABLE_TIMER1,
+				dev->iobase + APCI3120_WR_ADDRESS);
+		}
+
+	}
+
+	return;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)   |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : This function handles EOS interrupt.                   |
+|                     This function copies the acquired data(from FIFO)      |
+|				to Comedi buffer.		 							 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     														 |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      : 0            					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+/*
+ * int i_APCI3120_InterruptHandleEos(struct comedi_device *dev)
+{
+       int n_chan,i;
+       short *data;
+       struct comedi_subdevice *s=dev->subdevices+0;
+       struct comedi_async *async = s->async;
+       data=async->data+async->buf_int_ptr;
+        n_chan=devpriv->ui_AiNbrofChannels;
+
+       for(i=0;i<n_chan;i++)
+         {
+           data[i]=inw(dev->iobase+0);
+         }
+       async->buf_int_count+=n_chan*sizeof(short);
+       async->buf_int_ptr+=n_chan*sizeof(short);
+       comedi_eos(dev,s);
+       if (s->async->buf_int_ptr>=s->async->data_len) //  for buffer rool over
+		         {
+*//* buffer rollover */
+/*	        s->async->buf_int_ptr=0;
+		comedi_eobuf(dev,s);
+         }
+ 	return 0;
+}*/
+int i_APCI3120_InterruptHandleEos(struct comedi_device * dev)
+{
+	int n_chan, i;
+	struct comedi_subdevice *s = dev->subdevices + 0;
+	int err = 1;
+
+	n_chan = devpriv->ui_AiNbrofChannels;
+
+	s->async->events = 0;
+
+	for (i = 0; i < n_chan; i++)
+		err &= comedi_buf_put(s->async, inw(dev->iobase + 0));
+
+	s->async->events |= COMEDI_CB_EOS;
+
+	if (err == 0)
+		s->async->events |= COMEDI_CB_OVERFLOW;
+
+	comedi_event(dev, s);
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : void v_APCI3120_InterruptDma(int irq, void *d) 									 |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : This is a handler for the DMA interrupt                |
+|			  This function copies the data to Comedi Buffer.        |
+|			  For continuous DMA it reinitializes the DMA operation. |
+|			  For single mode DMA it stop the acquisition.           |
+|													     			 |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq, void *d				 |
+|                     														 |
++----------------------------------------------------------------------------+
+| Return Value      :  void        					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI3120_InterruptDma(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	struct comedi_subdevice *s = dev->subdevices + 0;
+	unsigned int next_dma_buf, samplesinbuf;
+	unsigned long low_word, high_word, var;
+
+	UINT ui_Tmp;
+	samplesinbuf =
+		devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] -
+		inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC);
+
+	if (samplesinbuf <
+		devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) {
+		comedi_error(dev, "Interrupted DMA transfer!");
+	}
+	if (samplesinbuf & 1) {
+		comedi_error(dev, "Odd count of bytes in DMA ring!");
+		i_APCI3120_StopCyclicAcquisition(dev, s);
+		devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+
+		return;
+	}
+	samplesinbuf = samplesinbuf >> 1;	// number of received samples
+	if (devpriv->b_DmaDoubleBuffer) {
+		// switch DMA buffers if is used double buffering
+		next_dma_buf = 1 - devpriv->ui_DmaActualBuffer;
+
+		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
+		outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
+
+		// changed  since 16 bit interface for add on
+		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
+			devpriv->i_IobaseAddon + 2);
+		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);	// 0x1000 is out putted in windows driver
+
+		var = devpriv->ul_DmaBufferHw[next_dma_buf];
+		low_word = var & 0xffff;
+		var = devpriv->ul_DmaBufferHw[next_dma_buf];
+		high_word = var / 65536;
+
+		/* DMA Start Adress Low */
+		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
+		outw(low_word, devpriv->i_IobaseAddon + 2);
+
+		/* DMA Start Adress High */
+		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(high_word, devpriv->i_IobaseAddon + 2);
+
+		var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
+		low_word = var & 0xffff;
+		var = devpriv->ui_DmaBufferUsesize[next_dma_buf];
+		high_word = var / 65536;
+
+		/* Nbr of acquisition LOW */
+		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
+		outw(low_word, devpriv->i_IobaseAddon + 2);
+
+		/* Nbr of acquisition HIGH */
+		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(high_word, devpriv->i_IobaseAddon + 2);
+
+		// To configure A2P FIFO
+		// ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+		outw(3, devpriv->i_IobaseAddon + 4);
+		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
+		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
+				APCI3120_ENABLE_WRITE_TC_INT),
+			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
+
+	}
+/*UPDATE-0.7.57->0.7.68
+	ptr=(short *)devpriv->ul_DmaBufferVirtual[devpriv->ui_DmaActualBuffer];
+
+
+	// if there is not enough space left in the buffer to copy all data contained in the DMABufferVirtual
+	if(s->async->buf_int_ptr+samplesinbuf*sizeof(short)>=devpriv->ui_AiDataLength)
+	{
+		m=(devpriv->ui_AiDataLength-s->async->buf_int_ptr)/sizeof(short);
+		v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,m);
+		s->async->buf_int_count+=m*sizeof(short);
+		ptr+=m*sizeof(short);
+                samplesinbuf-=m;
+		s->async->buf_int_ptr=0;
+		comedi_eobuf(dev,s);
+	}
+
+	if (samplesinbuf)
+	{
+	        v_APCI3120_InterruptDmaMoveBlock16bit(dev,s,(void *)ptr,((void *)(devpriv->AiData))+s->async->buf_int_ptr,samplesinbuf);
+
+		s->async->buf_int_count+=samplesinbuf*sizeof(short);
+		s->async->buf_int_ptr+=samplesinbuf*sizeof(short);
+		if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS))
+		{
+			comedi_bufcheck(dev,s);
+                }
+	}
+	if (!devpriv->b_AiContinuous)
+	if ( devpriv->ui_AiActualScan>=devpriv->ui_AiNbrofScans )
+	{
+	    // all data sampled
+	    i_APCI3120_StopCyclicAcquisition(dev,s);
+            devpriv->b_AiCyclicAcquisition=APCI3120_DISABLE;
+	    //DPRINTK("\n Single DMA completed..\n");
+		comedi_done(dev,s);
+            	return;
+	}
+*/
+	if (samplesinbuf) {
+		v_APCI3120_InterruptDmaMoveBlock16bit(dev, s,
+			devpriv->ul_DmaBufferVirtual[devpriv->
+				ui_DmaActualBuffer], samplesinbuf);
+
+		if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) {
+			s->async->events |= COMEDI_CB_EOS;
+			comedi_event(dev, s);
+		}
+	}
+	if (!devpriv->b_AiContinuous)
+		if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) {
+			// all data sampled
+			i_APCI3120_StopCyclicAcquisition(dev, s);
+			devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE;
+			s->async->events |= COMEDI_CB_EOA;
+			comedi_event(dev, s);
+			return;
+		}
+
+	if (devpriv->b_DmaDoubleBuffer) {	// switch dma buffers
+		devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
+	} else {
+		// restart DMA if is not used double buffering
+		//ADDED REINITIALISE THE DMA
+		ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO;
+		outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS);
+
+		// changed  since 16 bit interface for add on
+		outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0);
+		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_LOW,
+			devpriv->i_IobaseAddon + 2);
+		outw(APCI3120_ADD_ON_AGCSTS_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH, devpriv->i_IobaseAddon + 2);	//
+		// A2P FIFO MANAGEMENT
+		// A2P fifo reset  & transfer control enable
+		outl(APCI3120_A2P_FIFO_MANAGEMENT,
+			devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR);
+
+		var = devpriv->ul_DmaBufferHw[0];
+		low_word = var & 0xffff;
+		var = devpriv->ul_DmaBufferHw[0];
+		high_word = var / 65536;
+		outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0);
+		outw(low_word, devpriv->i_IobaseAddon + 2);
+		outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(high_word, devpriv->i_IobaseAddon + 2);
+
+		var = devpriv->ui_DmaBufferUsesize[0];
+		low_word = var & 0xffff;	//changed
+		var = devpriv->ui_DmaBufferUsesize[0];
+		high_word = var / 65536;
+		outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0);
+		outw(low_word, devpriv->i_IobaseAddon + 2);
+		outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0);
+		outw(high_word, devpriv->i_IobaseAddon + 2);
+
+		// To configure A2P FIFO
+		//ENABLE A2P FIFO WRITE AND ENABLE AMWEN
+		// AMWEN_ENABLE | A2P_FIFO_WRITE_ENABLE (0x01|0x02)=0x03
+		outw(3, devpriv->i_IobaseAddon + 4);
+		//initialise end of dma interrupt  AINT_WRITE_COMPL = ENABLE_WRITE_TC_INT(ADDI)
+		outl((APCI3120_FIFO_ADVANCE_ON_BYTE_2 |
+				APCI3120_ENABLE_WRITE_TC_INT),
+			devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR);
+	}
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device|
+|*dev,struct comedi_subdevice *s,short *dma,short *data,int n)				     |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : This function copies the data from DMA buffer to the   |
+|				 Comedi buffer  									 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     short *dma											 |
+|                     short *data,int n          					         |
++----------------------------------------------------------------------------+
+| Return Value      : void         					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+/*void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n)
+{
+	int i,j,m;
+
+	j=s->async->cur_chan;
+	m=devpriv->ui_AiActualScanPosition;
+        for(i=0;i<n;i++)
+	{
+		*data=*dma;
+   		data++; dma++;
+		j++;
+		if(j>=devpriv->ui_AiNbrofChannels)
+		{
+			m+=j;
+			j=0;
+			if(m>=devpriv->ui_AiScanLength)
+			{
+				m=0;
+			        devpriv->ui_AiActualScan++;
+				if (devpriv->ui_AiFlags & TRIG_WAKE_EOS)
+;//UPDATE-0.7.57->0.7.68					comedi_eos(dev,s);
+			}
+		}
+	}
+        devpriv->ui_AiActualScanPosition=m;
+	s->async->cur_chan=j;
+
+}
+*/
+void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device * dev,
+	struct comedi_subdevice * s, short * dma_buffer, unsigned int num_samples)
+{
+	devpriv->ui_AiActualScan +=
+		(s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength;
+	s->async->cur_chan += num_samples;
+	s->async->cur_chan %= devpriv->ui_AiScanLength;
+
+	cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short));
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           TIMER SUBDEVICE   		                         |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev,          |
+|	struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) 			     |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              :Configure Timer 2  								     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
+|                     														 |
+|                      data[0]= TIMER  configure as timer                    |
+|              				 = WATCHDOG configure as watchdog				 |
+|       			  data[1] = Timer constant							 |
+|       			  data[2] = Timer2 interrupt (1)enable or(0) disable |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnConfigTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ui_Timervalue2;
+	USHORT us_TmpValue;
+	BYTE b_Tmp;
+
+	if (!data[1])
+		comedi_error(dev, "config:No timer constant !");
+
+	devpriv->b_Timer2Interrupt = (BYTE) data[2];	// save info whether to enable or disable interrupt
+
+	ui_Timervalue2 = data[1] / 1000;	// convert nano seconds  to u seconds
+
+	//this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(BYTE)data[0]);
+	us_TmpValue = (USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+	//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+	// and calculate the time value to set in the timer
+	if ((us_TmpValue & 0x00B0) == 0x00B0
+		|| !strcmp(this_board->pc_DriverName, "apci3001")) {
+		//Calculate the time value to set in the timer
+		ui_Timervalue2 = ui_Timervalue2 / 50;
+	} else {
+		//Calculate the time value to set in the timer
+		ui_Timervalue2 = ui_Timervalue2 / 70;
+	}
+
+	//Reset gate 2 of Timer 2 to disable it (Set Bit D14 to 0)
+	devpriv->us_OutputRegister =
+		devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER2;
+	outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS);
+
+	// Disable TIMER Interrupt
+	devpriv->b_ModeSelectRegister =
+		devpriv->
+		b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT & 0xEF;
+
+	// Disable Eoc and Eos Interrupts
+	devpriv->b_ModeSelectRegister =
+		devpriv->
+		b_ModeSelectRegister & APCI3120_DISABLE_EOC_INT &
+		APCI3120_DISABLE_EOS_INT;
+	outb(devpriv->b_ModeSelectRegister,
+		devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+	if (data[0] == APCI3120_TIMER)	//initialize timer
+	{
+
+		//devpriv->b_ModeSelectRegister=devpriv->b_ModeSelectRegister| APCI3120_ENABLE_TIMER_INT ;
+		//outb(devpriv->b_ModeSelectRegister,devpriv->iobase+APCI3120_WRITE_MODE_SELECT);
+
+		//Set the Timer 2 in mode 2(Timer)
+		devpriv->b_TimerSelectMode =
+			(devpriv->
+			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_2;
+		outb(devpriv->b_TimerSelectMode,
+			devpriv->iobase + APCI3120_TIMER_CRT1);
+
+		//Configure the timer 2 for writing the LOW WORD of timer is Delay value
+		//You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
+		//you can set the digital output and configure the timer 2,and if you don't make this, digital output
+		//are erase (Set to 0)
+
+		//Writing LOW WORD
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_LOW_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+		outw(LOWORD(ui_Timervalue2),
+			devpriv->iobase + APCI3120_TIMER_VALUE);
+
+		//Writing HIGH WORD
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_HIGH_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+		outw(HIWORD(ui_Timervalue2),
+			devpriv->iobase + APCI3120_TIMER_VALUE);
+		// timer2 in Timer mode enabled
+		devpriv->b_Timer2Mode = APCI3120_TIMER;
+
+	} else			// Initialize Watch dog
+	{
+
+		//Set the Timer 2 in mode 5(Watchdog)
+
+		devpriv->b_TimerSelectMode =
+			(devpriv->
+			b_TimerSelectMode & 0x0F) | APCI3120_TIMER_2_MODE_5;
+		outb(devpriv->b_TimerSelectMode,
+			devpriv->iobase + APCI3120_TIMER_CRT1);
+
+		//Configure the timer 2 for writing the LOW WORD of timer is Delay value
+		//You must make a b_tmp variable with DigitalOutPutRegister because at Address_1+APCI3120_TIMER_CRT0
+		//you can set the digital output and configure the timer 2,and if you don't make this, digital output
+		//are erase (Set to 0)
+
+		//Writing LOW WORD
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_LOW_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+		outw(LOWORD(ui_Timervalue2),
+			devpriv->iobase + APCI3120_TIMER_VALUE);
+
+		//Writing HIGH WORD
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_HIGH_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+		outw(HIWORD(ui_Timervalue2),
+			devpriv->iobase + APCI3120_TIMER_VALUE);
+		//watchdog enabled
+		devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
+
+	}
+
+	return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev,           |
+|                    struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)  |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              :    To start and stop the timer		                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data                                         |
+|                                                                            |
+|				data[0] = 1 (start)                                  |
+|				data[0] = 0 (stop )                                  |
+|	 			data[0] = 2  (write new value)                       |
+|	   			data[1]= new value                                   |
+|                                                                            |
+|    				devpriv->b_Timer2Mode =  0 DISABLE                   |
+|	                     					 1 Timer                     |
+|					 					 2 Watch dog			     |
+|                                                 					         |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnWriteTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ui_Timervalue2 = 0;
+	USHORT us_TmpValue;
+	BYTE b_Tmp;
+
+	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
+		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
+		comedi_error(dev, "\nwrite:timer2  not configured ");
+		return -EINVAL;
+	}
+
+	if (data[0] == 2)	// write new value
+	{
+		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
+			comedi_error(dev,
+				"write :timer2  not configured  in TIMER MODE");
+			return -EINVAL;
+		}
+
+		if (data[1])
+			ui_Timervalue2 = data[1];
+		else
+			ui_Timervalue2 = 0;
+	}
+
+	//this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2);
+
+	switch (data[0]) {
+	case APCI3120_START:
+
+		// Reset FC_TIMER BIT
+		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
+		if (devpriv->b_Timer2Mode == APCI3120_TIMER)	//start timer
+		{
+			//Enable Timer
+			devpriv->b_ModeSelectRegister =
+				devpriv->b_ModeSelectRegister & 0x0B;
+		} else		//start watch dog
+		{
+			//Enable WatchDog
+			devpriv->b_ModeSelectRegister =
+				(devpriv->
+				b_ModeSelectRegister & 0x0B) |
+				APCI3120_ENABLE_WATCHDOG;
+		}
+
+		//enable disable interrupt
+		if ((devpriv->b_Timer2Interrupt) == APCI3120_ENABLE) {
+
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister |
+				APCI3120_ENABLE_TIMER_INT;
+			// save the task structure to pass info to user
+			devpriv->tsk_Current = current;
+		} else {
+
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister &
+				APCI3120_DISABLE_TIMER_INT;
+		}
+		outb(devpriv->b_ModeSelectRegister,
+			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+		if (devpriv->b_Timer2Mode == APCI3120_TIMER)	//start timer
+		{
+			//For Timer mode is  Gate2 must be activated   **timer started
+			devpriv->us_OutputRegister =
+				devpriv->
+				us_OutputRegister | APCI3120_ENABLE_TIMER2;
+			outw(devpriv->us_OutputRegister,
+				devpriv->iobase + APCI3120_WR_ADDRESS);
+		}
+
+		break;
+
+	case APCI3120_STOP:
+		if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
+			//Disable timer
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister &
+				APCI3120_DISABLE_TIMER_COUNTER;
+		} else {
+			//Disable WatchDog
+			devpriv->b_ModeSelectRegister =
+				devpriv->
+				b_ModeSelectRegister &
+				APCI3120_DISABLE_WATCHDOG;
+		}
+		// Disable timer interrupt
+		devpriv->b_ModeSelectRegister =
+			devpriv->
+			b_ModeSelectRegister & APCI3120_DISABLE_TIMER_INT;
+
+		// Write above states  to register
+		outb(devpriv->b_ModeSelectRegister,
+			devpriv->iobase + APCI3120_WRITE_MODE_SELECT);
+
+		// Reset Gate 2
+		devpriv->us_OutputRegister =
+			devpriv->us_OutputRegister & APCI3120_DISABLE_TIMER_INT;
+		outw(devpriv->us_OutputRegister,
+			devpriv->iobase + APCI3120_WR_ADDRESS);
+
+		// Reset FC_TIMER BIT
+		inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
+
+		// Disable timer
+		//devpriv->b_Timer2Mode=APCI3120_DISABLE;
+
+		break;
+
+	case 2:		//write new value to Timer
+		if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
+			comedi_error(dev,
+				"write :timer2  not configured  in TIMER MODE");
+			return -EINVAL;
+		}
+		// ui_Timervalue2=data[1]; // passed as argument
+		us_TmpValue =
+			(USHORT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+		//EL250804: Testing if board APCI3120 have the new Quartz or if it is an APCI3001
+		// and calculate the time value to set in the timer
+		if ((us_TmpValue & 0x00B0) == 0x00B0
+			|| !strcmp(this_board->pc_DriverName, "apci3001")) {
+			//Calculate the time value to set in the timer
+			ui_Timervalue2 = ui_Timervalue2 / 50;
+		} else {
+			//Calculate the time value to set in the timer
+			ui_Timervalue2 = ui_Timervalue2 / 70;
+		}
+		//Writing LOW WORD
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_LOW_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+		outw(LOWORD(ui_Timervalue2),
+			devpriv->iobase + APCI3120_TIMER_VALUE);
+
+		//Writing HIGH WORD
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_HIGH_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+		outw(HIWORD(ui_Timervalue2),
+			devpriv->iobase + APCI3120_TIMER_VALUE);
+
+		break;
+	default:
+		return -EINVAL;	// Not a valid input
+	}
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : int i_APCI3120_InsnReadTimer(struct comedi_device *dev,           |
+|		struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) 		 |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : read the Timer value 				                 	 |
++----------------------------------------------------------------------------+
+| Input Parameters  : 	struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
+|                     														 |
++----------------------------------------------------------------------------+
+| Return Value      :   													 |
+|			for Timer:	data[0]= Timer constant						 |
+|																	 |
+|         		for watchdog: data[0]=0 (still running)                  |
+|	               			  data[0]=1  (run down)            			 |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3120_InsnReadTimer(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_Tmp;
+	USHORT us_TmpValue, us_TmpValue_2, us_StatusValue;
+
+	if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
+		&& (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
+		comedi_error(dev, "\nread:timer2  not configured ");
+	}
+
+	//this_board->i_hwdrv_InsnReadTimer(dev,data);
+	if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
+
+		//Read the LOW WORD of Timer 2 register
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_LOW_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+		us_TmpValue = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
+
+		//Read the HIGH WORD of Timer 2 register
+		b_Tmp = ((devpriv->
+				b_DigitalOutputRegister) & 0xF0) |
+			APCI3120_SELECT_TIMER_2_HIGH_WORD;
+		outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0);
+
+		us_TmpValue_2 = inw(devpriv->iobase + APCI3120_TIMER_VALUE);
+
+		// combining both words
+		data[0] = (UINT) ((us_TmpValue) | ((us_TmpValue_2) << 16));
+
+	} else			// Read watch dog status
+	{
+
+		us_StatusValue = inw(devpriv->iobase + APCI3120_RD_STATUS);
+		us_StatusValue =
+			((us_StatusValue & APCI3120_FC_TIMER) >> 12) & 1;
+		if (us_StatusValue == 1) {
+			// RESET FC_TIMER BIT
+			inb(devpriv->iobase + APCI3120_TIMER_STATUS_REGISTER);
+		}
+		data[0] = us_StatusValue;	// when data[0] = 1 then the watch dog has rundown
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL INPUT SUBDEVICE   		                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,     |
+|			struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)   |
+|                                        									 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : Reads the value of the specified  Digital input channel|
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    struct comedi_insn *insn,
+				    unsigned int *data)
+{
+	UINT ui_Chan, ui_TmpValue;
+
+	ui_Chan = CR_CHAN(insn->chanspec);	// channel specified
+
+	//this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data);
+	if (ui_Chan >= 0 && ui_Chan <= 3) {
+		ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+
+		//      since only 1 channel reqd  to bring it to last bit it is rotated
+		//  8 +(chan - 1) times then ANDed with 1 for last bit.
+		*data = (ui_TmpValue >> (ui_Chan + 8)) & 1;
+		//return 0;
+	} else {
+		//      comedi_error(dev," chan spec wrong");
+		return -EINVAL;	// "sorry channel spec wrong "
+	}
+	return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, |
+|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)                      |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Reads the value of the Digital input Port i.e.4channels|
+|   value is returned in data[0]											 |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3120_InsnBitsDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_TmpValue;
+	ui_TmpValue = (UINT) inw(devpriv->iobase + APCI3120_RD_STATUS);
+	/*****	state of 4 channels  in the 11, 10, 9, 8   bits of status reg
+			rotated right 8 times to bring them to last four bits
+			ANDed with oxf for  value.
+	*****/
+
+	*data = (ui_TmpValue >> 8) & 0xf;
+	//this_board->i_hwdrv_InsnBitsDigitalInput(dev,data);
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL OUTPUT SUBDEVICE   		                 |
++----------------------------------------------------------------------------+
+*/
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device    |
+| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)				 |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              :Configure the output memory ON or OFF				     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  :struct comedi_device *dev									 	 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}
+	if (data[0]) {
+		devpriv->b_OutputMemoryStatus = APCI3120_ENABLE;
+
+	} else {
+		devpriv->b_OutputMemoryStatus = APCI3120_DISABLE;
+		devpriv->b_DigitalOutputRegister = 0;
+	}
+	if (!devpriv->b_OutputMemoryStatus) {
+		ui_Temp = 0;
+
+	}			//if(!devpriv->b_OutputMemoryStatus )
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev,    |
+|		struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) 		 |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : write diatal output port							     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
+                      data[0]     Value to be written
+                      data[1]    :1 Set digital o/p ON
+                      data[1]     2 Set digital o/p OFF with memory ON
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device * dev,
+				     struct comedi_subdevice *s,
+				     struct comedi_insn *insn,
+				     unsigned int *data)
+{
+	if ((data[0] > this_board->i_DoMaxdata) || (data[0] < 0)) {
+
+		comedi_error(dev, "Data is not valid !!! \n");
+		return -EINVAL;
+	}
+
+	switch (data[1]) {
+	case 1:
+		data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
+		break;
+
+	case 2:
+		data[0] = data[0];
+		break;
+	default:
+		printk("\nThe parameter passed is in error \n");
+		return -EINVAL;
+	}			// switch(data[1])
+	outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
+
+	devpriv->b_DigitalOutputRegister = data[0] & 0xF0;
+
+	return insn->n;
+
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,|
+|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) 			             |
+|                                            						         |
++----------------------------------------------------------------------------+
+| Task              : Write digiatl output								     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev								 	 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data 										 |
+                      data[0]     Value to be written
+                      data[1]    :1 Set digital o/p ON
+                      data[1]     2 Set digital o/p OFF with memory ON
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,
+				      struct comedi_subdevice *s,
+				      struct comedi_insn *insn,
+				      unsigned int *data)
+{
+
+	UINT ui_Temp1;
+
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}
+	if ((ui_NoOfChannel > (this_board->i_NbrDoChannel - 1))
+		|| (ui_NoOfChannel < 0)) {
+		comedi_error(dev,
+			"This board doesn't have specified channel !!! \n");
+		return -EINVAL;
+	}
+
+	switch (data[1]) {
+	case 1:
+		data[0] = (data[0] << ui_NoOfChannel);
+//ES05                   data[0]=(data[0]<<4)|ui_Temp;
+		data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister;
+		break;
+
+	case 2:
+		data[0] = ~data[0] & 0x1;
+		ui_Temp1 = 1;
+		ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+		ui_Temp1 = ui_Temp1 << 4;
+//ES05                   ui_Temp=ui_Temp|ui_Temp1;
+		devpriv->b_DigitalOutputRegister =
+			devpriv->b_DigitalOutputRegister | ui_Temp1;
+
+		data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
+		data[0] = data[0] << 4;
+//ES05                   data[0]=data[0]& ui_Temp;
+		data[0] = data[0] & devpriv->b_DigitalOutputRegister;
+		break;
+	default:
+		printk("\nThe parameter passed is in error \n");
+		return -EINVAL;
+	}			// switch(data[1])
+	outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT);
+
+//ES05        ui_Temp=data[0] & 0xf0;
+	devpriv->b_DigitalOutputRegister = data[0] & 0xf0;
+	return (insn->n);
+
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            ANALOG OUTPUT SUBDEVICE                         |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,|
+|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data)			             |
+|                                        									 |
++----------------------------------------------------------------------------+
+| Task              : Write  analog output   							     |
+|                     										                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev									 |
+|                     struct comedi_subdevice *s									 |
+|                     struct comedi_insn *insn                                      |
+|                     unsigned int *data  										 |
++----------------------------------------------------------------------------+
+| Return Value      :              					                         |
+|                    													     |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
+				     struct comedi_subdevice *s,
+				     struct comedi_insn *insn,
+				     unsigned int *data)
+{
+	UINT ui_Range, ui_Channel;
+	USHORT us_TmpValue;
+
+	ui_Range = CR_RANGE(insn->chanspec);
+	ui_Channel = CR_CHAN(insn->chanspec);
+
+	//this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]);
+	if (ui_Range)		// if 1 then unipolar
+	{
+
+		if (data[0] != 0)
+			data[0] =
+				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
+					13) | (data[0] + 8191));
+		else
+			data[0] =
+				((((ui_Channel & 0x03) << 14) & 0xC000) | (1 <<
+					13) | 8192);
+
+	} else			// if 0 then   bipolar
+	{
+		data[0] =
+			((((ui_Channel & 0x03) << 14) & 0xC000) | (0 << 13) |
+			data[0]);
+
+	}
+
+	//out put n values at the given channel.
+	// rt_printk("\nwaiting for DA_READY BIT");
+	do			//Waiting of DA_READY BIT
+	{
+		us_TmpValue =
+			((USHORT) inw(devpriv->iobase +
+				APCI3120_RD_STATUS)) & 0x0001;
+	} while (us_TmpValue != 0x0001);
+
+	if (ui_Channel <= 3)
+		// for channel 0-3 out at  the register 1 (wrDac1-8)
+		// data[i] typecasted to ushort since  word write is to be done
+		outw((USHORT) data[0],
+			devpriv->iobase + APCI3120_ANALOG_OUTPUT_1);
+	else
+		// for channel 4-7 out at the register 2 (wrDac5-8)
+		//data[i] typecasted to ushort since  word write is to be done
+		outw((USHORT) data[0],
+			devpriv->iobase + APCI3120_ANALOG_OUTPUT_2);
+
+	return insn->n;
+}

+ 241 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h

@@ -0,0 +1,241 @@
+
+// hwdrv_apci3120.h
+
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+// comedi related defines
+
+//ANALOG INPUT RANGE
+static const struct comedi_lrange range_apci3120_ai = { 8, {
+						     BIP_RANGE(10),
+						     BIP_RANGE(5),
+						     BIP_RANGE(2),
+						     BIP_RANGE(1),
+						     UNI_RANGE(10),
+						     UNI_RANGE(5),
+						     UNI_RANGE(2),
+						     UNI_RANGE(1)
+						     }
+};
+
+// ANALOG OUTPUT RANGE
+static const struct comedi_lrange range_apci3120_ao = { 2, {
+						     BIP_RANGE(10),
+						     UNI_RANGE(10)
+						     }
+};
+
+#define APCI3120_BIPOLAR_RANGES	4	// used for test on mixture of BIP/UNI ranges
+
+#define APCI3120_BOARD_VENDOR_ID                 0x10E8
+#define APCI3120_ADDRESS_RANGE            			16
+
+#define APCI3120_DISABLE                         0
+#define APCI3120_ENABLE                          1
+
+#define APCI3120_START                           1
+#define APCI3120_STOP                            0
+
+#define     APCI3120_EOC_MODE         1
+#define     APCI3120_EOS_MODE         2
+#define     APCI3120_DMA_MODE         3
+
+//DIGITAL INPUT-OUTPUT DEFINE
+
+#define APCI3120_DIGITAL_OUTPUT                  	0x0D
+#define APCI3120_RD_STATUS                       	0x02
+#define APCI3120_RD_FIFO                     		0x00
+
+// digital output insn_write ON /OFF selection
+#define	APCI3120_SET4DIGITALOUTPUTON				1
+#define APCI3120_SET4DIGITALOUTPUTOFF				0
+
+// analog output SELECT BIT
+#define APCI3120_ANALOG_OP_CHANNEL_1   0x0000
+#define APCI3120_ANALOG_OP_CHANNEL_2   0x4000
+#define APCI3120_ANALOG_OP_CHANNEL_3   0x8000
+#define APCI3120_ANALOG_OP_CHANNEL_4   0xC000
+#define APCI3120_ANALOG_OP_CHANNEL_5   0x0000
+#define APCI3120_ANALOG_OP_CHANNEL_6   0x4000
+#define APCI3120_ANALOG_OP_CHANNEL_7   0x8000
+#define APCI3120_ANALOG_OP_CHANNEL_8   0xC000
+
+// Enable external trigger bit in nWrAddress
+#define APCI3120_ENABLE_EXT_TRIGGER    0x8000
+
+//ANALOG OUTPUT AND INPUT DEFINE
+#define APCI3120_UNIPOLAR 0x80	//$$ RAM sequence polarity BIT
+#define APCI3120_BIPOLAR  0x00	//$$ RAM sequence polarity BIT
+#define APCI3120_ANALOG_OUTPUT_1 0x08	// (ADDRESS )
+#define APCI3120_ANALOG_OUTPUT_2 0x0A	// (ADDRESS )
+#define APCI3120_1_GAIN              0x00	//$$ RAM sequence Gain Bits for gain 1
+#define APCI3120_2_GAIN              0x10	//$$ RAM sequence Gain Bits for gain 2
+#define APCI3120_5_GAIN              0x20	//$$ RAM sequence Gain Bits for gain 5
+#define APCI3120_10_GAIN             0x30	//$$ RAM sequence Gain Bits for gain 10
+#define APCI3120_SEQ_RAM_ADDRESS        0x06	//$$ EARLIER NAMED APCI3120_FIFO_ADDRESS
+#define APCI3120_RESET_FIFO          0x0C	//(ADDRESS)
+#define APCI3120_TIMER_0_MODE_2      0x01	//$$ Bits for timer mode
+#define APCI3120_TIMER_0_MODE_4       0x2
+#define APCI3120_SELECT_TIMER_0_WORD 0x00
+#define APCI3120_ENABLE_TIMER0     0x1000	//$$Gatebit 0 in nWrAddress
+#define APCI3120_CLEAR_PR          0xF0FF
+#define APCI3120_CLEAR_PA          0xFFF0
+#define APCI3120_CLEAR_PA_PR       (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA)
+
+// nWrMode_Select
+#define APCI3120_ENABLE_SCAN          0x8	//$$ bit in nWrMode_Select
+#define APCI3120_DISABLE_SCAN      (~APCI3120_ENABLE_SCAN)
+#define APCI3120_ENABLE_EOS_INT       0x2	//$$ bit in nWrMode_Select
+
+#define APCI3120_DISABLE_EOS_INT   (~APCI3120_ENABLE_EOS_INT)
+#define APCI3120_ENABLE_EOC_INT       0x1
+#define APCI3120_DISABLE_EOC_INT   (~APCI3120_ENABLE_EOC_INT)
+#define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER   (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
+#define APCI3120_DISABLE_ALL_INTERRUPT   (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT)
+
+//status register bits
+#define APCI3120_EOC                     0x8000
+#define APCI3120_EOS                     0x2000
+
+// software trigger dummy register
+#define APCI3120_START_CONVERSION        0x02	//(ADDRESS)
+
+//TIMER DEFINE
+#define APCI3120_QUARTZ_A				  70
+#define APCI3120_QUARTZ_B				  50
+#define APCI3120_TIMER                            1
+#define APCI3120_WATCHDOG                         2
+#define APCI3120_TIMER_DISABLE                    0
+#define APCI3120_TIMER_ENABLE                     1
+#define APCI3120_ENABLE_TIMER2                    0x4000	//$$ gatebit 2 in nWrAddress
+#define APCI3120_DISABLE_TIMER2                   (~APCI3120_ENABLE_TIMER2)
+#define APCI3120_ENABLE_TIMER_INT                 0x04	//$$ ENAIRQ_FC_Bit in nWrModeSelect
+#define APCI3120_DISABLE_TIMER_INT                (~APCI3120_ENABLE_TIMER_INT)
+#define APCI3120_WRITE_MODE_SELECT                0x0E	// (ADDRESS)
+#define APCI3120_SELECT_TIMER_0_WORD  0x00
+#define APCI3120_SELECT_TIMER_1_WORD  0x01
+#define APCI3120_TIMER_1_MODE_2       0x4
+
+//$$ BIT FOR MODE IN nCsTimerCtr1
+#define APCI3120_TIMER_2_MODE_0                   0x0
+#define APCI3120_TIMER_2_MODE_2                   0x10
+#define APCI3120_TIMER_2_MODE_5                   0x30
+
+//$$ BIT FOR MODE IN nCsTimerCtr0
+#define APCI3120_SELECT_TIMER_2_LOW_WORD          0x02
+#define APCI3120_SELECT_TIMER_2_HIGH_WORD         0x03
+
+#define APCI3120_TIMER_CRT0                       0x0D	//(ADDRESS for cCsTimerCtr0)
+#define APCI3120_TIMER_CRT1                       0x0C	//(ADDRESS for cCsTimerCtr1)
+
+#define APCI3120_TIMER_VALUE                      0x04	//ADDRESS for nCsTimerWert
+#define APCI3120_TIMER_STATUS_REGISTER            0x0D	//ADDRESS for delete timer 2 interrupt
+#define APCI3120_RD_STATUS                        0x02	//ADDRESS
+#define APCI3120_WR_ADDRESS                       0x00	//ADDRESS
+#define APCI3120_ENABLE_WATCHDOG                  0x20	//$$BIT in nWrMode_Select
+#define APCI3120_DISABLE_WATCHDOG                 (~APCI3120_ENABLE_WATCHDOG)
+#define APCI3120_ENABLE_TIMER_COUNTER    		  0x10	//$$BIT in nWrMode_Select
+#define APCI3120_DISABLE_TIMER_COUNTER            (~APCI3120_ENABLE_TIMER_COUNTER)
+#define APCI3120_FC_TIMER                         0x1000	//bit in  status register
+#define APCI3120_ENABLE_TIMER0                    0x1000
+#define APCI3120_ENABLE_TIMER1                    0x2000
+#define APCI3120_ENABLE_TIMER2                    0x4000
+#define APCI3120_DISABLE_TIMER0			          (~APCI3120_ENABLE_TIMER0)
+#define APCI3120_DISABLE_TIMER1		              (~APCI3120_ENABLE_TIMER1)
+#define APCI3120_DISABLE_TIMER2	                  (~APCI3120_ENABLE_TIMER2)
+
+#define APCI3120_TIMER2_SELECT_EOS                0xC0	// ADDED on 20-6
+#define APCI3120_COUNTER                          3	// on 20-6
+#define APCI3120_DISABLE_ALL_TIMER                ( APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1 & APCI3120_DISABLE_TIMER2 )	// on 20-6
+
+#define MAX_ANALOGINPUT_CHANNELS    32
+
+typedef struct {
+	BYTE b_Type;		/* EOC or EOS */
+	BYTE b_InterruptFlag;	/* Interrupt use or not                    */
+	UINT ui_ConvertTiming;	/* Selection of the convertion time        */
+	BYTE b_NbrOfChannel;	/* Number of channel to read               */
+	UINT ui_ChannelList[MAX_ANALOGINPUT_CHANNELS];	/* Number of the channel to be read        */
+	UINT ui_RangeList[MAX_ANALOGINPUT_CHANNELS];	/* Gain of each channel                    */
+
+} str_AnalogReadInformation;
+
+// Function Declaration For APCI-3120
+
+// Internal functions
+int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s,
+				int n_chan, unsigned int *chanlist, char check);
+int i_APCI3120_ExttrigEnable(struct comedi_device *dev);
+int i_APCI3120_ExttrigDisable(struct comedi_device *dev);
+int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s);
+int i_APCI3120_Reset(struct comedi_device *dev);
+int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev,
+				 struct comedi_subdevice *s);
+// Interrupt functions
+void v_APCI3120_Interrupt(int irq, void *d);
+//UPDATE-0.7.57->0.7.68 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n);
+void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,
+					   struct comedi_subdevice *s,
+					   short *dma_buffer,
+					   unsigned int num_samples);
+int i_APCI3120_InterruptHandleEos(struct comedi_device *dev);
+void v_APCI3120_InterruptDma(int irq, void *d);
+
+// TIMER
+
+int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data);
+int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s,
+			      struct comedi_insn *insn, unsigned int *data);
+int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s,
+			     struct comedi_insn *insn, unsigned int *data);
+
+//DI
+// for di read
+
+int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				    struct comedi_insn *insn, unsigned int *data);
+
+//DO
+//int i_APCI3120_WriteDigitalOutput(struct comedi_device *dev, BYTE data);
+int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev,
+				       struct comedi_subdevice *s, struct comedi_insn *insn,
+				       unsigned int *data);
+int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_insn *insn, unsigned int *data);
+
+//AO
+//int i_APCI3120_Write1AnalogValue(struct comedi_device *dev,UINT ui_Range,UINT ui_Channel,UINT data );
+int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+
+//AI HArdware layer
+
+int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				     struct comedi_insn *insn, unsigned int *data);
+int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_cmd *cmd);
+int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s);
+//int i_APCI3120_CancelAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s);
+int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s);

+ 3642 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c

@@ -0,0 +1,3642 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-3200       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci3200.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-3200                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  | 02.07.04 | J. Krauth | Modification from the driver in order to       |
+  |          |           | correct some errors when using several boards. |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+  | 26.10.04 | J. Krauth | - Update for COMEDI 0.7.68                     |
+  |          |           | - Read eeprom value                            |
+  |          |           | - Append APCI-3300                             |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
+  +----------------------------------------------------------------------------+
+  |                               Included files                               |
+  +----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci3200.h"
+//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+#include "addi_amcc_S5920.h"
+//#define PRINT_INFO
+
+//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+//BEGIN JK 06.07.04: Management of sevrals boards
+/*
+  INT i_CJCAvailable=1;
+  INT i_CJCPolarity=0;
+  INT i_CJCGain=2;//changed from 0 to 2
+  INT i_InterruptFlag=0;
+  INT i_ADDIDATAPolarity;
+  INT i_ADDIDATAGain;
+  INT i_AutoCalibration=0;   //: auto calibration
+  INT i_ADDIDATAConversionTime;
+  INT i_ADDIDATAConversionTimeUnit;
+  INT i_ADDIDATAType;
+  INT i_ChannelNo;
+  INT i_ChannelCount=0;
+  INT i_ScanType;
+  INT i_FirstChannel;
+  INT i_LastChannel;
+  INT i_Sum=0;
+  INT i_Offset;
+  UINT ui_Channel_num=0;
+  static int i_Count=0;
+  INT i_Initialised=0;
+  UINT ui_InterruptChannelValue[96]; //Buffer
+*/
+str_BoardInfos s_BoardInfos[100];	// 100 will be the max number of boards to be used
+//END JK 06.07.04: Management of sevrals boards
+
+//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+/*+----------------------------------------------------------------------------+*/
+/*| Function   Name   : INT i_AddiHeaderRW_ReadEeprom                          |*/
+/*|                               (INT    i_NbOfWordsToRead,                   |*/
+/*|                                DWORD dw_PCIBoardEepromAddress,             |*/
+/*|                                WORD   w_EepromStartAddress,                |*/
+/*|                                PWORD pw_DataRead)                          |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Task              : Read word from the 5920 eeprom.                        |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Input Parameters  : INT    i_NbOfWordsToRead : Nbr. of word to read        |*/
+/*|                     DWORD dw_PCIBoardEepromAddress : Address of the eeprom |*/
+/*|                     WORD   w_EepromStartAddress : Eeprom strat address     |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Output Parameters : PWORD pw_DataRead : Read data                          |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Return Value      : -                                                      |*/
+/*+----------------------------------------------------------------------------+*/
+
+INT i_AddiHeaderRW_ReadEeprom(INT i_NbOfWordsToRead,
+	DWORD dw_PCIBoardEepromAddress,
+	WORD w_EepromStartAddress, PWORD pw_DataRead)
+{
+	DWORD dw_eeprom_busy = 0;
+	INT i_Counter = 0;
+	INT i_WordCounter;
+	INT i;
+	BYTE pb_ReadByte[1];
+	BYTE b_ReadLowByte = 0;
+	BYTE b_ReadHighByte = 0;
+	BYTE b_SelectedAddressLow = 0;
+	BYTE b_SelectedAddressHigh = 0;
+	WORD w_ReadWord = 0;
+
+	for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead;
+		i_WordCounter++) {
+		do {
+			dw_eeprom_busy =
+				inl(dw_PCIBoardEepromAddress +
+				AMCC_OP_REG_MCSR);
+			dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+		}
+		while (dw_eeprom_busy == EEPROM_BUSY);
+
+		for (i_Counter = 0; i_Counter < 2; i_Counter++) {
+			b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256;	//Read the low 8 bit part
+			b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256;	//Read the high 8 bit part
+
+			//Select the load low address mode
+			outb(NVCMD_LOAD_LOW,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				3);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Load the low address
+			outb(b_SelectedAddressLow,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				2);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Select the load high address mode
+			outb(NVCMD_LOAD_HIGH,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				3);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Load the high address
+			outb(b_SelectedAddressHigh,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				2);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Select the READ mode
+			outb(NVCMD_BEGIN_READ,
+				dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR +
+				3);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Read data into the EEPROM
+			*pb_ReadByte =
+				inb(dw_PCIBoardEepromAddress +
+				AMCC_OP_REG_MCSR + 2);
+
+			//Wait on busy
+			do {
+				dw_eeprom_busy =
+					inl(dw_PCIBoardEepromAddress +
+					AMCC_OP_REG_MCSR);
+				dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY;
+			}
+			while (dw_eeprom_busy == EEPROM_BUSY);
+
+			//Select the upper address part
+			if (i_Counter == 0) {
+				b_ReadLowByte = pb_ReadByte[0];
+			} else {
+				b_ReadHighByte = pb_ReadByte[0];
+			}
+
+			//Sleep
+			for (i = 0; i < 10000; i++) ;
+
+		}
+		w_ReadWord =
+			(b_ReadLowByte | (((unsigned short)b_ReadHighByte) *
+				256));
+
+		pw_DataRead[i_WordCounter] = w_ReadWord;
+
+		w_EepromStartAddress += 2;	// to read the next word
+
+	}			// for (...) i_NbOfWordsToRead
+	return (0);
+}
+
+/*+----------------------------------------------------------------------------+*/
+/*| Function   Name   : void v_GetAPCI3200EepromCalibrationValue (void)        |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Task              : Read calibration value from the APCI-3200 eeprom.      |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Input Parameters  : -                                                      |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Output Parameters : -                                                      |*/
+/*+----------------------------------------------------------------------------+*/
+/*| Return Value      : -                                                      |*/
+/*+----------------------------------------------------------------------------+*/
+
+void v_GetAPCI3200EepromCalibrationValue(DWORD dw_PCIBoardEepromAddress,
+	str_BoardInfos * BoardInformations)
+{
+	WORD w_AnalogInputMainHeaderAddress;
+	WORD w_AnalogInputComponentAddress;
+	WORD w_NumberOfModuls = 0;
+	WORD w_CurrentSources[2];
+	WORD w_ModulCounter = 0;
+	WORD w_FirstHeaderSize = 0;
+	WORD w_NumberOfInputs = 0;
+	WORD w_CJCFlag = 0;
+	WORD w_NumberOfGainValue = 0;
+	WORD w_SingleHeaderAddress = 0;
+	WORD w_SingleHeaderSize = 0;
+	WORD w_Input = 0;
+	WORD w_GainFactorAddress = 0;
+	WORD w_GainFactorValue[2];
+	WORD w_GainIndex = 0;
+	WORD w_GainValue = 0;
+
+  /*****************************************/
+  /** Get the Analog input header address **/
+  /*****************************************/
+	i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+		dw_PCIBoardEepromAddress, 0x116,	//w_EepromStartAddress: Analog input header address
+		&w_AnalogInputMainHeaderAddress);
+
+  /*******************************************/
+  /** Compute the real analog input address **/
+  /*******************************************/
+	w_AnalogInputMainHeaderAddress = w_AnalogInputMainHeaderAddress + 0x100;
+
+  /******************************/
+  /** Get the number of moduls **/
+  /******************************/
+	i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+		dw_PCIBoardEepromAddress, w_AnalogInputMainHeaderAddress + 0x02,	//w_EepromStartAddress: Number of conponment
+		&w_NumberOfModuls);
+
+	for (w_ModulCounter = 0; w_ModulCounter < w_NumberOfModuls;
+		w_ModulCounter++) {
+      /***********************************/
+      /** Compute the component address **/
+      /***********************************/
+		w_AnalogInputComponentAddress =
+			w_AnalogInputMainHeaderAddress +
+			(w_FirstHeaderSize * w_ModulCounter) + 0x04;
+
+      /****************************/
+      /** Read first header size **/
+      /****************************/
+		i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+			dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress,	// Address of the first header
+			&w_FirstHeaderSize);
+
+		w_FirstHeaderSize = w_FirstHeaderSize >> 4;
+
+      /***************************/
+      /** Read number of inputs **/
+      /***************************/
+		i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+			dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x06,	// Number of inputs for the first modul
+			&w_NumberOfInputs);
+
+		w_NumberOfInputs = w_NumberOfInputs >> 4;
+
+      /***********************/
+      /** Read the CJC flag **/
+      /***********************/
+		i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+			dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x08,	// CJC flag
+			&w_CJCFlag);
+
+		w_CJCFlag = (w_CJCFlag >> 3) & 0x1;	// Get only the CJC flag
+
+      /*******************************/
+      /** Read number of gain value **/
+      /*******************************/
+		i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+			dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 0x44,	// Number of gain value
+			&w_NumberOfGainValue);
+
+		w_NumberOfGainValue = w_NumberOfGainValue & 0xFF;
+
+      /***********************************/
+      /** Compute single header address **/
+      /***********************************/
+		w_SingleHeaderAddress =
+			w_AnalogInputComponentAddress + 0x46 +
+			(((w_NumberOfGainValue / 16) + 1) * 2) +
+			(6 * w_NumberOfGainValue) +
+			(4 * (((w_NumberOfGainValue / 16) + 1) * 2));
+
+      /********************************************/
+      /** Read current sources value for input 1 **/
+      /********************************************/
+		i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+			dw_PCIBoardEepromAddress, w_SingleHeaderAddress,	//w_EepromStartAddress: Single header address
+			&w_SingleHeaderSize);
+
+		w_SingleHeaderSize = w_SingleHeaderSize >> 4;
+
+      /*************************************/
+      /** Read gain factor for the module **/
+      /*************************************/
+		w_GainFactorAddress = w_AnalogInputComponentAddress;
+
+		for (w_GainIndex = 0; w_GainIndex < w_NumberOfGainValue;
+			w_GainIndex++) {
+	  /************************************/
+	  /** Read gain value for the module **/
+	  /************************************/
+			i_AddiHeaderRW_ReadEeprom(1,	//i_NbOfWordsToRead
+				dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + (2 * (1 + (w_NumberOfGainValue / 16))) + (0x02 * w_GainIndex),	// Gain value
+				&w_GainValue);
+
+			BoardInformations->s_Module[w_ModulCounter].
+				w_GainValue[w_GainIndex] = w_GainValue;
+
+#             ifdef PRINT_INFO
+			printk("\n Gain value = %d",
+				BoardInformations->s_Module[w_ModulCounter].
+				w_GainValue[w_GainIndex]);
+#             endif
+
+	  /*************************************/
+	  /** Read gain factor for the module **/
+	  /*************************************/
+			i_AddiHeaderRW_ReadEeprom(2,	//i_NbOfWordsToRead
+				dw_PCIBoardEepromAddress, w_AnalogInputComponentAddress + 70 + ((2 * w_NumberOfGainValue) + (2 * (1 + (w_NumberOfGainValue / 16)))) + (0x04 * w_GainIndex),	// Gain factor
+				w_GainFactorValue);
+
+			BoardInformations->s_Module[w_ModulCounter].
+				ul_GainFactor[w_GainIndex] =
+				(w_GainFactorValue[1] << 16) +
+				w_GainFactorValue[0];
+
+#             ifdef PRINT_INFO
+			printk("\n w_GainFactorValue [%d] = %lu", w_GainIndex,
+				BoardInformations->s_Module[w_ModulCounter].
+				ul_GainFactor[w_GainIndex]);
+#             endif
+		}
+
+      /***************************************************************/
+      /** Read current source value for each channels of the module **/
+      /***************************************************************/
+		for (w_Input = 0; w_Input < w_NumberOfInputs; w_Input++) {
+	  /********************************************/
+	  /** Read current sources value for input 1 **/
+	  /********************************************/
+			i_AddiHeaderRW_ReadEeprom(2,	//i_NbOfWordsToRead
+				dw_PCIBoardEepromAddress,
+				(w_Input * w_SingleHeaderSize) +
+				w_SingleHeaderAddress + 0x0C, w_CurrentSources);
+
+	  /************************************/
+	  /** Save the current sources value **/
+	  /************************************/
+			BoardInformations->s_Module[w_ModulCounter].
+				ul_CurrentSource[w_Input] =
+				(w_CurrentSources[0] +
+				((w_CurrentSources[1] & 0xFFF) << 16));
+
+#             ifdef PRINT_INFO
+			printk("\n Current sources [%d] = %lu", w_Input,
+				BoardInformations->s_Module[w_ModulCounter].
+				ul_CurrentSource[w_Input]);
+#             endif
+		}
+
+      /***************************************/
+      /** Read the CJC current source value **/
+      /***************************************/
+		i_AddiHeaderRW_ReadEeprom(2,	//i_NbOfWordsToRead
+			dw_PCIBoardEepromAddress,
+			(w_Input * w_SingleHeaderSize) + w_SingleHeaderAddress +
+			0x0C, w_CurrentSources);
+
+      /************************************/
+      /** Save the current sources value **/
+      /************************************/
+		BoardInformations->s_Module[w_ModulCounter].
+			ul_CurrentSourceCJC =
+			(w_CurrentSources[0] +
+			((w_CurrentSources[1] & 0xFFF) << 16));
+
+#          ifdef PRINT_INFO
+		printk("\n Current sources CJC = %lu",
+			BoardInformations->s_Module[w_ModulCounter].
+			ul_CurrentSourceCJC);
+#          endif
+	}
+}
+
+INT i_APCI3200_GetChannelCalibrationValue(struct comedi_device * dev,
+	unsigned int ui_Channel_num, unsigned int * CJCCurrentSource,
+	unsigned int * ChannelCurrentSource, unsigned int * ChannelGainFactor)
+{
+	int i_DiffChannel = 0;
+	int i_Module = 0;
+
+#ifdef PRINT_INFO
+	printk("\n Channel = %u", ui_Channel_num);
+#endif
+
+	//Test if single or differential mode
+	if (s_BoardInfos[dev->minor].i_ConnectionType == 1) {
+		//if diff
+
+		if ((ui_Channel_num >= 0) && (ui_Channel_num <= 1))
+			i_DiffChannel = ui_Channel_num, i_Module = 0;
+		else if ((ui_Channel_num >= 2) && (ui_Channel_num <= 3))
+			i_DiffChannel = ui_Channel_num - 2, i_Module = 1;
+		else if ((ui_Channel_num >= 4) && (ui_Channel_num <= 5))
+			i_DiffChannel = ui_Channel_num - 4, i_Module = 2;
+		else if ((ui_Channel_num >= 6) && (ui_Channel_num <= 7))
+			i_DiffChannel = ui_Channel_num - 6, i_Module = 3;
+
+	} else {
+		// if single
+		if ((ui_Channel_num == 0) || (ui_Channel_num == 1))
+			i_DiffChannel = 0, i_Module = 0;
+		else if ((ui_Channel_num == 2) || (ui_Channel_num == 3))
+			i_DiffChannel = 1, i_Module = 0;
+		else if ((ui_Channel_num == 4) || (ui_Channel_num == 5))
+			i_DiffChannel = 0, i_Module = 1;
+		else if ((ui_Channel_num == 6) || (ui_Channel_num == 7))
+			i_DiffChannel = 1, i_Module = 1;
+		else if ((ui_Channel_num == 8) || (ui_Channel_num == 9))
+			i_DiffChannel = 0, i_Module = 2;
+		else if ((ui_Channel_num == 10) || (ui_Channel_num == 11))
+			i_DiffChannel = 1, i_Module = 2;
+		else if ((ui_Channel_num == 12) || (ui_Channel_num == 13))
+			i_DiffChannel = 0, i_Module = 3;
+		else if ((ui_Channel_num == 14) || (ui_Channel_num == 15))
+			i_DiffChannel = 1, i_Module = 3;
+	}
+
+	//Test if thermocouple or RTD mode
+	*CJCCurrentSource =
+		s_BoardInfos[dev->minor].s_Module[i_Module].ul_CurrentSourceCJC;
+#ifdef PRINT_INFO
+	printk("\n CJCCurrentSource = %lu", *CJCCurrentSource);
+#endif
+
+	*ChannelCurrentSource =
+		s_BoardInfos[dev->minor].s_Module[i_Module].
+		ul_CurrentSource[i_DiffChannel];
+#ifdef PRINT_INFO
+	printk("\n ChannelCurrentSource = %lu", *ChannelCurrentSource);
+#endif
+	//      }
+	//   }
+
+	//Channle gain factor
+	*ChannelGainFactor =
+		s_BoardInfos[dev->minor].s_Module[i_Module].
+		ul_GainFactor[s_BoardInfos[dev->minor].i_ADDIDATAGain];
+#ifdef PRINT_INFO
+	printk("\n ChannelGainFactor = %lu", *ChannelGainFactor);
+#endif
+	//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+	return (0);
+}
+
+//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadDigitalInput                       |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              : Read  value  of the selected channel or port           |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT ui_NoOfChannels    : No Of Channels To read  for Port
+  Channel Numberfor single channel
+  |                     UINT data[0]            : 0: Read single channel
+  1: Read port value
+  data[1]              Port number
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--	data[0] :Read status value
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+
+INT i_APCI3200_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp = 0;
+	UINT ui_NoOfChannel = 0;
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	ui_Temp = data[0];
+	*data = inl(devpriv->i_IobaseReserved);
+
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			//if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			if (data[1] < 0 || data[1] > 1) {
+				printk("\nThe port number is in error\n");
+				return -EINVAL;
+			}	//if(data[1] < 0 || data[1] >1)
+			switch (ui_NoOfChannel) {
+
+			case 2:
+				*data = (*data >> (2 * data[1])) & 0x3;
+				break;
+			case 3:
+				*data = (*data & 15);
+				break;
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+
+			}	//switch(ui_NoOfChannels)
+		}		//if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		//elseif  (ui_Temp==1)
+	}
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ConfigDigitalOutput                     |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,				 |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              : Configures The Digital Output Subdevice.               |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev : Driver handle                     |
+  |			  data[0]  :1  Memory enable
+  0  Memory Disable
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error			 |
+  |																	 |
+  +----------------------------------------------------------------------------+
+*/
+int i_APCI3200_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}			//if  ( (data[0]!=0) && (data[0]!=1) )
+	if (data[0]) {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
+	}			// if  (data[0])
+	else {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
+	}			//else if  (data[0])
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_WriteDigitalOutput                      |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,				 |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              : writes To the digital Output Subdevice                 |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     struct comedi_subdevice *s     : Subdevice Pointer            |
+  |                     struct comedi_insn *insn       : Insn Structure Pointer       |
+  |                     unsigned int *data          : Data Pointer contains        |
+  |                                          configuration parameters as below |
+  |                     data[0]             :Value to output
+  data[1]             : 0 o/p single channel
+  1 o/p port
+  data[2]             : port no
+  data[3]             :0 set the digital o/p on
+  1 set the digital o/p off
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error	     	 |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+INT i_APCI3200_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp = 0, ui_Temp1 = 0;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp = inl(devpriv->i_IobaseAddon);
+
+	}			//if(devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			//if(devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outl(data[0], devpriv->i_IobaseAddon);
+		}		//if(data[1]==0)
+		else {
+			if (data[1] == 1) {
+				switch (ui_NoOfChannel) {
+
+				case 2:
+					data[0] =
+						(data[0] << (2 *
+							data[2])) | ui_Temp;
+					break;
+				case 3:
+					data[0] = (data[0] | ui_Temp);
+					break;
+				}	//switch(ui_NoOfChannels)
+
+				outl(data[0], devpriv->i_IobaseAddon);
+			}	// if(data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	//else if(data[1]==1)
+		}		//elseif(data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] = (data[0] << ui_NoOfChannel) ^ 0xf;
+				data[0] = data[0] & ui_Temp;
+				outl(data[0], devpriv->i_IobaseAddon);
+			}	//if(data[1]==0)
+			else {
+				if (data[1] == 1) {
+					switch (ui_NoOfChannel) {
+
+					case 2:
+						data[0] = ~data[0] & 0x3;
+						ui_Temp1 = 3;
+						ui_Temp1 =
+							ui_Temp1 << 2 * data[2];
+						ui_Temp = ui_Temp | ui_Temp1;
+						data[0] =
+							((data[0] << (2 *
+									data
+									[2])) ^
+							0xf) & ui_Temp;
+
+						break;
+					case 3:
+						break;
+
+					default:
+						comedi_error(dev,
+							" chan spec wrong");
+						return -EINVAL;	// "sorry channel spec wrong "
+					}	//switch(ui_NoOfChannels)
+
+					outl(data[0], devpriv->i_IobaseAddon);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadDigitalOutput                       |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              : Read  value  of the selected channel or port           |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT ui_NoOfChannels    : No Of Channels To read       |
+  |                     UINT *data              : Data Pointer to read status  |
+  data[0]                 :0 read single channel
+  1 read port value
+  data[1]                  port no
+
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+INT i_APCI3200_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp;
+	UINT ui_NoOfChannel;
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	ui_Temp = data[0];
+	*data = inl(devpriv->i_IobaseAddon);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			// if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			if (data[1] < 0 || data[1] > 1) {
+				printk("\nThe port selection is in error\n");
+				return -EINVAL;
+			}	//if(data[1] <0 ||data[1] >1)
+			switch (ui_NoOfChannel) {
+			case 2:
+				*data = (*data >> (2 * data[1])) & 3;
+				break;
+
+			case 3:
+				break;
+
+			default:
+				comedi_error(dev, " chan spec wrong");
+				return -EINVAL;	// "sorry channel spec wrong "
+				break;
+			}	// switch(ui_NoOfChannels)
+		}		// if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		// else if (ui_Temp==1)
+	}			// else if  (ui_Temp==0)
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : INT i_APCI3200_ConfigAnalogInput                       |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              : Configures The Analog Input Subdevice                  |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     struct comedi_subdevice *s     : Subdevice Pointer            |
+  |                     struct comedi_insn *insn       : Insn Structure Pointer       |
+  |                     unsigned int *data          : Data Pointer contains        |
+  |                                          configuration parameters as below |
+  |                                                                            |
+  |					data[0]
+  |                                               0:Normal AI                  |
+  |                                               1:RTD                        |
+  |                                               2:THERMOCOUPLE               |
+  |				    data[1]            : Gain To Use                 |
+  |                                                                            |
+  |                           data[2]            : Polarity
+  |                                                0:Bipolar                   |
+  |                                                1:Unipolar                  |
+  |															    	 |
+  |                           data[3]            : Offset Range
+  |                                                                            |
+  |                           data[4]            : Coupling
+  |                                                0:DC Coupling               |
+  |                                                1:AC Coupling               |
+  |                                                                            |
+  |                           data[5]            :Differential/Single
+  |                                                0:Single                    |
+  |                                                1:Differential              |
+  |                                                                            |
+  |                           data[6]            :TimerReloadValue
+  |                                                                            |
+  |                           data[7]            :ConvertingTimeUnit
+  |                                                                            |
+  |                           data[8]             :0 Analog voltage measurement
+  1 Resistance measurement
+  2 Temperature measurement
+  |                           data[9]            :Interrupt
+  |                                              0:Disable
+  |                                              1:Enable
+  data[10]           :Type of Thermocouple
+  |                          data[11]           : 0: single channel
+  Module Number
+  |
+  |                          data[12]
+  |                                             0:Single Read
+  |                                             1:Read more channel
+  2:Single scan
+  |                                             3:Continous Scan
+  data[13]          :Number of channels to read
+  |                          data[14]          :RTD connection type
+  :0:RTD not used
+  1:RTD 2 wire connection
+  2:RTD 3 wire connection
+  3:RTD 4 wire connection
+  |                                                                            |
+  |                                                                            |
+  |                                                                            |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+INT i_APCI3200_ConfigAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	UINT ul_Config = 0, ul_Temp = 0;
+	UINT ui_ChannelNo = 0;
+	UINT ui_Dummy = 0;
+	INT i_err = 0;
+
+	//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+#ifdef PRINT_INFO
+	INT i = 0, i2 = 0;
+#endif
+	//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	// Initialize the structure
+	if (s_BoardInfos[dev->minor].b_StructInitialized != 1) {
+		s_BoardInfos[dev->minor].i_CJCAvailable = 1;
+		s_BoardInfos[dev->minor].i_CJCPolarity = 0;
+		s_BoardInfos[dev->minor].i_CJCGain = 2;	//changed from 0 to 2
+		s_BoardInfos[dev->minor].i_InterruptFlag = 0;
+		s_BoardInfos[dev->minor].i_AutoCalibration = 0;	//: auto calibration
+		s_BoardInfos[dev->minor].i_ChannelCount = 0;
+		s_BoardInfos[dev->minor].i_Sum = 0;
+		s_BoardInfos[dev->minor].ui_Channel_num = 0;
+		s_BoardInfos[dev->minor].i_Count = 0;
+		s_BoardInfos[dev->minor].i_Initialised = 0;
+		s_BoardInfos[dev->minor].b_StructInitialized = 1;
+
+		//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+		s_BoardInfos[dev->minor].i_ConnectionType = 0;
+		//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+		//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+		memset(s_BoardInfos[dev->minor].s_Module, 0,
+			sizeof(s_BoardInfos[dev->minor].s_Module[MAX_MODULE]));
+
+		v_GetAPCI3200EepromCalibrationValue(devpriv->i_IobaseAmcc,
+			&s_BoardInfos[dev->minor]);
+
+#ifdef PRINT_INFO
+		for (i = 0; i < MAX_MODULE; i++) {
+			printk("\n s_Module[%i].ul_CurrentSourceCJC = %lu", i,
+				s_BoardInfos[dev->minor].s_Module[i].
+				ul_CurrentSourceCJC);
+
+			for (i2 = 0; i2 < 5; i2++) {
+				printk("\n s_Module[%i].ul_CurrentSource [%i] = %lu", i, i2, s_BoardInfos[dev->minor].s_Module[i].ul_CurrentSource[i2]);
+			}
+
+			for (i2 = 0; i2 < 8; i2++) {
+				printk("\n s_Module[%i].ul_GainFactor [%i] = %lu", i, i2, s_BoardInfos[dev->minor].s_Module[i].ul_GainFactor[i2]);
+			}
+
+			for (i2 = 0; i2 < 8; i2++) {
+				printk("\n s_Module[%i].w_GainValue [%i] = %u",
+					i, i2,
+					s_BoardInfos[dev->minor].s_Module[i].
+					w_GainValue[i2]);
+			}
+		}
+#endif
+		//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+	}
+
+	if (data[0] != 0 && data[0] != 1 && data[0] != 2) {
+		printk("\nThe selection of acquisition type is in error\n");
+		i_err++;
+	}			//if(data[0]!=0 && data[0]!=1 && data[0]!=2)
+	if (data[0] == 1) {
+		if (data[14] != 0 && data[14] != 1 && data[14] != 2
+			&& data[14] != 4) {
+			printk("\n Error in selection of RTD connection type\n");
+			i_err++;
+		}		//if(data[14]!=0 && data[14]!=1 && data[14]!=2 && data[14]!=4)
+	}			//if(data[0]==1 )
+	if (data[1] < 0 || data[1] > 7) {
+		printk("\nThe selection of gain is in error\n");
+		i_err++;
+	}			// if(data[1]<0 || data[1]>7)
+	if (data[2] != 0 && data[2] != 1) {
+		printk("\nThe selection of polarity is in error\n");
+		i_err++;
+	}			//if(data[2]!=0 &&  data[2]!=1)
+	if (data[3] != 0) {
+		printk("\nThe selection of offset range  is in error\n");
+		i_err++;
+	}			// if(data[3]!=0)
+	if (data[4] != 0 && data[4] != 1) {
+		printk("\nThe selection of coupling is in error\n");
+		i_err++;
+	}			//if(data[4]!=0 &&  data[4]!=1)
+	if (data[5] != 0 && data[5] != 1) {
+		printk("\nThe selection of single/differential mode is in error\n");
+		i_err++;
+	}			//if(data[5]!=0 &&  data[5]!=1)
+	if (data[8] != 0 && data[8] != 1 && data[2] != 2) {
+		printk("\nError in selection of functionality\n");
+	}			//if(data[8]!=0 && data[8]!=1 && data[2]!=2)
+	if (data[12] == 0 || data[12] == 1) {
+		if (data[6] != 20 && data[6] != 40 && data[6] != 80
+			&& data[6] != 160) {
+			printk("\nThe selection of conversion time reload value is in error\n");
+			i_err++;
+		}		// if (data[6]!=20 && data[6]!=40 && data[6]!=80 && data[6]!=160 )
+		if (data[7] != 2) {
+			printk("\nThe selection of conversion time unit  is in error\n");
+			i_err++;
+		}		// if(data[7]!=2)
+	}
+	if (data[9] != 0 && data[9] != 1) {
+		printk("\nThe selection of interrupt enable is in error\n");
+		i_err++;
+	}			//if(data[9]!=0 &&  data[9]!=1)
+	if (data[11] < 0 || data[11] > 4) {
+		printk("\nThe selection of module is in error\n");
+		i_err++;
+	}			//if(data[11] <0 ||  data[11]>1)
+	if (data[12] < 0 || data[12] > 3) {
+		printk("\nThe selection of singlechannel/scan selection is in error\n");
+		i_err++;
+	}			//if(data[12] < 0 ||  data[12]> 3)
+	if (data[13] < 0 || data[13] > 16) {
+		printk("\nThe selection of number of channels is in error\n");
+		i_err++;
+	}			// if(data[13] <0 ||data[13] >15)
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	/*
+	   i_ChannelCount=data[13];
+	   i_ScanType=data[12];
+	   i_ADDIDATAPolarity = data[2];
+	   i_ADDIDATAGain=data[1];
+	   i_ADDIDATAConversionTime=data[6];
+	   i_ADDIDATAConversionTimeUnit=data[7];
+	   i_ADDIDATAType=data[0];
+	 */
+
+	// Save acquisition configuration for the actual board
+	s_BoardInfos[dev->minor].i_ChannelCount = data[13];
+	s_BoardInfos[dev->minor].i_ScanType = data[12];
+	s_BoardInfos[dev->minor].i_ADDIDATAPolarity = data[2];
+	s_BoardInfos[dev->minor].i_ADDIDATAGain = data[1];
+	s_BoardInfos[dev->minor].i_ADDIDATAConversionTime = data[6];
+	s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit = data[7];
+	s_BoardInfos[dev->minor].i_ADDIDATAType = data[0];
+	//Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+	s_BoardInfos[dev->minor].i_ConnectionType = data[5];
+	//End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+	//END JK 06.07.04: Management of sevrals boards
+
+	//Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+	memset(s_BoardInfos[dev->minor].ui_ScanValueArray, 0, (7 + 12) * sizeof(unsigned int));	// 7 is the maximal number of channels
+	//End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+
+	//BEGIN JK 02.07.04 : This while can't be do, it block the process when using severals boards
+	//while(i_InterruptFlag==1)
+	while (s_BoardInfos[dev->minor].i_InterruptFlag == 1) {
+#ifndef MSXBOX
+		udelay(1);
+#else
+		// In the case where the driver is compiled for the MSX-Box
+		// we used a printk to have a little delay because udelay
+		// seems to be broken under the MSX-Box.
+		// This solution hat to be studied.
+		printk("");
+#endif
+	}
+	//END JK 02.07.04 : This while can't be do, it block the process when using severals boards
+
+	ui_ChannelNo = CR_CHAN(insn->chanspec);	// get the channel
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//i_ChannelNo=ui_ChannelNo;
+	//ui_Channel_num =ui_ChannelNo;
+
+	s_BoardInfos[dev->minor].i_ChannelNo = ui_ChannelNo;
+	s_BoardInfos[dev->minor].ui_Channel_num = ui_ChannelNo;
+
+	//END JK 06.07.04: Management of sevrals boards
+
+	if (data[5] == 0) {
+		if (ui_ChannelNo < 0 || ui_ChannelNo > 15) {
+			printk("\nThe Selection of the channel is in error\n");
+			i_err++;
+		}		// if(ui_ChannelNo<0 || ui_ChannelNo>15)
+	}			//if(data[5]==0)
+	else {
+		if (data[14] == 2) {
+			if (ui_ChannelNo < 0 || ui_ChannelNo > 3) {
+				printk("\nThe Selection of the channel is in error\n");
+				i_err++;
+			}	// if(ui_ChannelNo<0 || ui_ChannelNo>3)
+		}		//if(data[14]==2)
+		else {
+			if (ui_ChannelNo < 0 || ui_ChannelNo > 7) {
+				printk("\nThe Selection of the channel is in error\n");
+				i_err++;
+			}	// if(ui_ChannelNo<0 || ui_ChannelNo>7)
+		}		//elseif(data[14]==2)
+	}			//elseif(data[5]==0)
+	if (data[12] == 0 || data[12] == 1) {
+		switch (data[5]) {
+		case 0:
+			if (ui_ChannelNo >= 0 && ui_ChannelNo <= 3) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_Offset=0;
+				s_BoardInfos[dev->minor].i_Offset = 0;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//if(ui_ChannelNo >=0 && ui_ChannelNo <=3)
+			if (ui_ChannelNo >= 4 && ui_ChannelNo <= 7) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_Offset=64;
+				s_BoardInfos[dev->minor].i_Offset = 64;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//if(ui_ChannelNo >=4 && ui_ChannelNo <=7)
+			if (ui_ChannelNo >= 8 && ui_ChannelNo <= 11) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_Offset=128;
+				s_BoardInfos[dev->minor].i_Offset = 128;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//if(ui_ChannelNo >=8 && ui_ChannelNo <=11)
+			if (ui_ChannelNo >= 12 && ui_ChannelNo <= 15) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_Offset=192;
+				s_BoardInfos[dev->minor].i_Offset = 192;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//if(ui_ChannelNo >=12 && ui_ChannelNo <=15)
+			break;
+		case 1:
+			if (data[14] == 2) {
+				if (ui_ChannelNo == 0) {
+					//BEGIN JK 06.07.04: Management of sevrals boards
+					//i_Offset=0;
+					s_BoardInfos[dev->minor].i_Offset = 0;
+					//END JK 06.07.04: Management of sevrals boards
+				}	//if(ui_ChannelNo ==0 )
+				if (ui_ChannelNo == 1) {
+					//BEGIN JK 06.07.04: Management of sevrals boards
+					//i_Offset=0;
+					s_BoardInfos[dev->minor].i_Offset = 64;
+					//END JK 06.07.04: Management of sevrals boards
+				}	// if(ui_ChannelNo ==1)
+				if (ui_ChannelNo == 2) {
+					//BEGIN JK 06.07.04: Management of sevrals boards
+					//i_Offset=128;
+					s_BoardInfos[dev->minor].i_Offset = 128;
+					//END JK 06.07.04: Management of sevrals boards
+				}	//if(ui_ChannelNo ==2 )
+				if (ui_ChannelNo == 3) {
+					//BEGIN JK 06.07.04: Management of sevrals boards
+					//i_Offset=192;
+					s_BoardInfos[dev->minor].i_Offset = 192;
+					//END JK 06.07.04: Management of sevrals boards
+				}	//if(ui_ChannelNo ==3)
+
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_ChannelNo=0;
+				s_BoardInfos[dev->minor].i_ChannelNo = 0;
+				//END JK 06.07.04: Management of sevrals boards
+				ui_ChannelNo = 0;
+				break;
+			}	//if(data[14]==2)
+			if (ui_ChannelNo >= 0 && ui_ChannelNo <= 1) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_Offset=0;
+				s_BoardInfos[dev->minor].i_Offset = 0;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//if(ui_ChannelNo >=0 && ui_ChannelNo <=1)
+			if (ui_ChannelNo >= 2 && ui_ChannelNo <= 3) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_ChannelNo=i_ChannelNo-2;
+				//i_Offset=64;
+				s_BoardInfos[dev->minor].i_ChannelNo =
+					s_BoardInfos[dev->minor].i_ChannelNo -
+					2;
+				s_BoardInfos[dev->minor].i_Offset = 64;
+				//END JK 06.07.04: Management of sevrals boards
+				ui_ChannelNo = ui_ChannelNo - 2;
+			}	//if(ui_ChannelNo >=2 && ui_ChannelNo <=3)
+			if (ui_ChannelNo >= 4 && ui_ChannelNo <= 5) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_ChannelNo=i_ChannelNo-4;
+				//i_Offset=128;
+				s_BoardInfos[dev->minor].i_ChannelNo =
+					s_BoardInfos[dev->minor].i_ChannelNo -
+					4;
+				s_BoardInfos[dev->minor].i_Offset = 128;
+				//END JK 06.07.04: Management of sevrals boards
+				ui_ChannelNo = ui_ChannelNo - 4;
+			}	//if(ui_ChannelNo >=4 && ui_ChannelNo <=5)
+			if (ui_ChannelNo >= 6 && ui_ChannelNo <= 7) {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//i_ChannelNo=i_ChannelNo-6;
+				//i_Offset=192;
+				s_BoardInfos[dev->minor].i_ChannelNo =
+					s_BoardInfos[dev->minor].i_ChannelNo -
+					6;
+				s_BoardInfos[dev->minor].i_Offset = 192;
+				//END JK 06.07.04: Management of sevrals boards
+				ui_ChannelNo = ui_ChannelNo - 6;
+			}	//if(ui_ChannelNo >=6 && ui_ChannelNo <=7)
+			break;
+
+		default:
+			printk("\n This selection of polarity does not exist\n");
+			i_err++;
+		}		//switch(data[2])
+	}			//if(data[12]==0 || data[12]==1)
+	else {
+		switch (data[11]) {
+		case 1:
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//i_Offset=0;
+			s_BoardInfos[dev->minor].i_Offset = 0;
+			//END JK 06.07.04: Management of sevrals boards
+			break;
+		case 2:
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//i_Offset=64;
+			s_BoardInfos[dev->minor].i_Offset = 64;
+			//END JK 06.07.04: Management of sevrals boards
+			break;
+		case 3:
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//i_Offset=128;
+			s_BoardInfos[dev->minor].i_Offset = 128;
+			//END JK 06.07.04: Management of sevrals boards
+			break;
+		case 4:
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//i_Offset=192;
+			s_BoardInfos[dev->minor].i_Offset = 192;
+			//END JK 06.07.04: Management of sevrals boards
+			break;
+		default:
+			printk("\nError in module selection\n");
+			i_err++;
+		}		// switch(data[11])
+	}			// elseif(data[12]==0 || data[12]==1)
+	if (i_err) {
+		i_APCI3200_Reset(dev);
+		return -EINVAL;
+	}
+	//if(i_ScanType!=1)
+	if (s_BoardInfos[dev->minor].i_ScanType != 1) {
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//i_Count=0;
+		//i_Sum=0;
+		s_BoardInfos[dev->minor].i_Count = 0;
+		s_BoardInfos[dev->minor].i_Sum = 0;
+		//END JK 06.07.04: Management of sevrals boards
+	}			//if(i_ScanType!=1)
+
+	ul_Config =
+		data[1] | (data[2] << 6) | (data[5] << 7) | (data[3] << 8) |
+		(data[4] << 9);
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//END JK 06.07.04: Management of sevrals boards
+  /*********************************/
+	/* Write the channel to configure */
+  /*********************************/
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//outl(0 | ui_ChannelNo , devpriv->iobase+i_Offset + 0x4);
+	outl(0 | ui_ChannelNo,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4);
+	//END JK 06.07.04: Management of sevrals boards
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//END JK 06.07.04: Management of sevrals boards
+  /**************************/
+	/* Reset the configuration */
+  /**************************/
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//outl(0 , devpriv->iobase+i_Offset + 0x0);
+	outl(0, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0);
+	//END JK 06.07.04: Management of sevrals boards
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//END JK 06.07.04: Management of sevrals boards
+
+  /***************************/
+	/* Write the configuration */
+  /***************************/
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//outl(ul_Config , devpriv->iobase+i_Offset + 0x0);
+	outl(ul_Config,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0);
+	//END JK 06.07.04: Management of sevrals boards
+
+  /***************************/
+	/*Reset the calibration bit */
+  /***************************/
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//ul_Temp = inl(devpriv->iobase+i_Offset + 12);
+	ul_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+	//END JK 06.07.04: Management of sevrals boards
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//END JK 06.07.04: Management of sevrals boards
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//outl((ul_Temp & 0xFFF9FFFF) , devpriv->iobase+.i_Offset + 12);
+	outl((ul_Temp & 0xFFF9FFFF),
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+	//END JK 06.07.04: Management of sevrals boards
+
+	if (data[9] == 1) {
+		devpriv->tsk_Current = current;
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//i_InterruptFlag=1;
+		s_BoardInfos[dev->minor].i_InterruptFlag = 1;
+		//END JK 06.07.04: Management of sevrals boards
+	}			// if(data[9]==1)
+	else {
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//i_InterruptFlag=0;
+		s_BoardInfos[dev->minor].i_InterruptFlag = 0;
+		//END JK 06.07.04: Management of sevrals boards
+	}			//else  if(data[9]==1)
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//i_Initialised=1;
+	s_BoardInfos[dev->minor].i_Initialised = 1;
+	//END JK 06.07.04: Management of sevrals boards
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//if(i_ScanType==1)
+	if (s_BoardInfos[dev->minor].i_ScanType == 1)
+		//END JK 06.07.04: Management of sevrals boards
+	{
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//i_Sum=i_Sum+1;
+		s_BoardInfos[dev->minor].i_Sum =
+			s_BoardInfos[dev->minor].i_Sum + 1;
+		//END JK 06.07.04: Management of sevrals boards
+
+		insn->unused[0] = 0;
+		i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy);
+	}
+
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadAnalogInput                         |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read  value  of the selected channel			         |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT ui_NoOfChannels    : No Of Channels To read       |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |				data[0]  : Digital Value Of Input             |
+  |				data[1]  : Calibration Offset Value           |
+  |				data[2]  : Calibration Gain Value
+  |				data[3]  : CJC value
+  |				data[4]  : CJC offset value
+  |				data[5]  : CJC gain value
+  | Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+  |				data[6] : CJC current source from eeprom
+  |				data[7] : Channel current source from eeprom
+  |				data[8] : Channle gain factor from eeprom
+  | End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+INT i_APCI3200_ReadAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_DummyValue = 0;
+	int i_ConvertCJCCalibration;
+	int i = 0;
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//if(i_Initialised==0)
+	if (s_BoardInfos[dev->minor].i_Initialised == 0)
+		//END JK 06.07.04: Management of sevrals boards
+	{
+		i_APCI3200_Reset(dev);
+		return -EINVAL;
+	}			//if(i_Initialised==0);
+
+#ifdef PRINT_INFO
+	printk("\n insn->unused[0] = %i", insn->unused[0]);
+#endif
+
+	switch (insn->unused[0]) {
+	case 0:
+
+		i_APCI3200_Read1AnalogInputChannel(dev, s, insn,
+			&ui_DummyValue);
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//ui_InterruptChannelValue[i_Count+0]=ui_DummyValue;
+		s_BoardInfos[dev->minor].
+			ui_InterruptChannelValue[s_BoardInfos[dev->minor].
+			i_Count + 0] = ui_DummyValue;
+		//END JK 06.07.04: Management of sevrals boards
+
+		//Begin JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+		i_APCI3200_GetChannelCalibrationValue(dev,
+			s_BoardInfos[dev->minor].ui_Channel_num,
+			&s_BoardInfos[dev->minor].
+			ui_InterruptChannelValue[s_BoardInfos[dev->minor].
+				i_Count + 6],
+			&s_BoardInfos[dev->minor].
+			ui_InterruptChannelValue[s_BoardInfos[dev->minor].
+				i_Count + 7],
+			&s_BoardInfos[dev->minor].
+			ui_InterruptChannelValue[s_BoardInfos[dev->minor].
+				i_Count + 8]);
+
+#ifdef PRINT_INFO
+		printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+6] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 6]);
+
+		printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+7] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 7]);
+
+		printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+8] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 8]);
+#endif
+
+		//End JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1))
+		if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2)
+			&& (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE)
+			&& (s_BoardInfos[dev->minor].i_CJCAvailable == 1))
+			//END JK 06.07.04: Management of sevrals boards
+		{
+			i_APCI3200_ReadCJCValue(dev, &ui_DummyValue);
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//ui_InterruptChannelValue[i_Count + 3]=ui_DummyValue;
+			s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[s_BoardInfos[dev->
+					minor].i_Count + 3] = ui_DummyValue;
+			//END JK 06.07.04: Management of sevrals boards
+		}		//if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE))
+		else {
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//ui_InterruptChannelValue[i_Count + 3]=0;
+			s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[s_BoardInfos[dev->
+					minor].i_Count + 3] = 0;
+			//END JK 06.07.04: Management of sevrals boards
+		}		//elseif((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1))
+
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE))
+		if ((s_BoardInfos[dev->minor].i_AutoCalibration == FALSE)
+			&& (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE))
+			//END JK 06.07.04: Management of sevrals boards
+		{
+			i_APCI3200_ReadCalibrationOffsetValue(dev,
+				&ui_DummyValue);
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//ui_InterruptChannelValue[i_Count + 1]=ui_DummyValue;
+			s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[s_BoardInfos[dev->
+					minor].i_Count + 1] = ui_DummyValue;
+			//END JK 06.07.04: Management of sevrals boards
+			i_APCI3200_ReadCalibrationGainValue(dev,
+				&ui_DummyValue);
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//ui_InterruptChannelValue[i_Count + 2]=ui_DummyValue;
+			s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[s_BoardInfos[dev->
+					minor].i_Count + 2] = ui_DummyValue;
+			//END JK 06.07.04: Management of sevrals boards
+		}		//if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE))
+
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)&& (i_CJCAvailable==1))
+		if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2)
+			&& (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE)
+			&& (s_BoardInfos[dev->minor].i_CJCAvailable == 1))
+			//END JK 06.07.04: Management of sevrals boards
+		{
+	  /**********************************************************/
+			/*Test if the Calibration channel must be read for the CJC */
+	  /**********************************************************/
+	  /**********************************/
+			/*Test if the polarity is the same */
+	  /**********************************/
+			//BEGIN JK 06.07.04: Management of sevrals boards
+			//if(i_CJCPolarity!=i_ADDIDATAPolarity)
+			if (s_BoardInfos[dev->minor].i_CJCPolarity !=
+				s_BoardInfos[dev->minor].i_ADDIDATAPolarity)
+				//END JK 06.07.04: Management of sevrals boards
+			{
+				i_ConvertCJCCalibration = 1;
+			}	//if(i_CJCPolarity!=i_ADDIDATAPolarity)
+			else {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//if(i_CJCGain==i_ADDIDATAGain)
+				if (s_BoardInfos[dev->minor].i_CJCGain ==
+					s_BoardInfos[dev->minor].i_ADDIDATAGain)
+					//END JK 06.07.04: Management of sevrals boards
+				{
+					i_ConvertCJCCalibration = 0;
+				}	//if(i_CJCGain==i_ADDIDATAGain)
+				else {
+					i_ConvertCJCCalibration = 1;
+				}	//elseif(i_CJCGain==i_ADDIDATAGain)
+			}	//elseif(i_CJCPolarity!=i_ADDIDATAPolarity)
+			if (i_ConvertCJCCalibration == 1) {
+				i_APCI3200_ReadCJCCalOffset(dev,
+					&ui_DummyValue);
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//ui_InterruptChannelValue[i_Count+4]=ui_DummyValue;
+				s_BoardInfos[dev->minor].
+					ui_InterruptChannelValue[s_BoardInfos
+					[dev->minor].i_Count + 4] =
+					ui_DummyValue;
+				//END JK 06.07.04: Management of sevrals boards
+
+				i_APCI3200_ReadCJCCalGain(dev, &ui_DummyValue);
+
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//ui_InterruptChannelValue[i_Count+5]=ui_DummyValue;
+				s_BoardInfos[dev->minor].
+					ui_InterruptChannelValue[s_BoardInfos
+					[dev->minor].i_Count + 5] =
+					ui_DummyValue;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//if(i_ConvertCJCCalibration==1)
+			else {
+				//BEGIN JK 06.07.04: Management of sevrals boards
+				//ui_InterruptChannelValue[i_Count+4]=0;
+				//ui_InterruptChannelValue[i_Count+5]=0;
+
+				s_BoardInfos[dev->minor].
+					ui_InterruptChannelValue[s_BoardInfos
+					[dev->minor].i_Count + 4] = 0;
+				s_BoardInfos[dev->minor].
+					ui_InterruptChannelValue[s_BoardInfos
+					[dev->minor].i_Count + 5] = 0;
+				//END JK 06.07.04: Management of sevrals boards
+			}	//elseif(i_ConvertCJCCalibration==1)
+		}		//if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE))
+
+		//BEGIN JK 06.07.04: Management of sevrals boards
+		//if(i_ScanType!=1)
+		if (s_BoardInfos[dev->minor].i_ScanType != 1) {
+			//i_Count=0;
+			s_BoardInfos[dev->minor].i_Count = 0;
+		}		//if(i_ScanType!=1)
+		else {
+			//i_Count=i_Count +6;
+			//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+			//s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count +6;
+			s_BoardInfos[dev->minor].i_Count =
+				s_BoardInfos[dev->minor].i_Count + 9;
+			//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+		}		//else if(i_ScanType!=1)
+
+		//if((i_ScanType==1) &&(i_InterruptFlag==1))
+		if ((s_BoardInfos[dev->minor].i_ScanType == 1)
+			&& (s_BoardInfos[dev->minor].i_InterruptFlag == 1)) {
+			//i_Count=i_Count-6;
+			//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+			//s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count-6;
+			s_BoardInfos[dev->minor].i_Count =
+				s_BoardInfos[dev->minor].i_Count - 9;
+			//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+		}
+		//if(i_ScanType==0)
+		if (s_BoardInfos[dev->minor].i_ScanType == 0) {
+			/*
+			   data[0]= ui_InterruptChannelValue[0];
+			   data[1]= ui_InterruptChannelValue[1];
+			   data[2]= ui_InterruptChannelValue[2];
+			   data[3]= ui_InterruptChannelValue[3];
+			   data[4]= ui_InterruptChannelValue[4];
+			   data[5]= ui_InterruptChannelValue[5];
+			 */
+#ifdef PRINT_INFO
+			printk("\n data[0]= s_BoardInfos [dev->minor].ui_InterruptChannelValue[0];");
+#endif
+			data[0] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[0];
+			data[1] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[1];
+			data[2] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[2];
+			data[3] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[3];
+			data[4] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[4];
+			data[5] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[5];
+
+			//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+			//printk("\n 0 - i_APCI3200_GetChannelCalibrationValue data [6] = %lu, data [7] = %lu, data [8] = %lu", data [6], data [7], data [8]);
+			i_APCI3200_GetChannelCalibrationValue(dev,
+				s_BoardInfos[dev->minor].ui_Channel_num,
+				&data[6], &data[7], &data[8]);
+			//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+		}
+		break;
+	case 1:
+
+		for (i = 0; i < insn->n; i++) {
+			//data[i]=ui_InterruptChannelValue[i];
+			data[i] =
+				s_BoardInfos[dev->minor].
+				ui_InterruptChannelValue[i];
+		}
+
+		//i_Count=0;
+		//i_Sum=0;
+		//if(i_ScanType==1)
+		s_BoardInfos[dev->minor].i_Count = 0;
+		s_BoardInfos[dev->minor].i_Sum = 0;
+		if (s_BoardInfos[dev->minor].i_ScanType == 1) {
+			//i_Initialised=0;
+			//i_InterruptFlag=0;
+			s_BoardInfos[dev->minor].i_Initialised = 0;
+			s_BoardInfos[dev->minor].i_InterruptFlag = 0;
+			//END JK 06.07.04: Management of sevrals boards
+		}
+		break;
+	default:
+		printk("\nThe parameters passed are in error\n");
+		i_APCI3200_Reset(dev);
+		return -EINVAL;
+	}			//switch(insn->unused[0])
+
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_Read1AnalogInputChannel                 |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read  value  of the selected channel			         |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT ui_NoOfChannel    : Channel No to read            |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			          data[0]  : Digital Value read                   |
+  |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+INT i_APCI3200_Read1AnalogInputChannel(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_EOC = 0;
+	UINT ui_ChannelNo = 0;
+	UINT ui_CommandRegister = 0;
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//ui_ChannelNo=i_ChannelNo;
+	ui_ChannelNo = s_BoardInfos[dev->minor].i_ChannelNo;
+
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+  /*********************************/
+	/* Write the channel to configure */
+  /*********************************/
+	//Begin JK 20.10.2004: Bad channel value is used when using differential mode
+	//outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4);
+	//outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4);
+	outl(0 | s_BoardInfos[dev->minor].i_ChannelNo,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4);
+	//End JK 20.10.2004: Bad channel value is used when using differential mode
+
+  /*******************************/
+	/* Set the convert timing unit */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+
+  /**************************/
+	/* Set the convert timing */
+  /**************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+
+  /**************************************************************************/
+	/* Set the start end stop index to the selected channel and set the start */
+  /**************************************************************************/
+
+	ui_CommandRegister = ui_ChannelNo | (ui_ChannelNo << 8) | 0x80000;
+
+  /*********************************/
+	/*Test if the interrupt is enable */
+  /*********************************/
+
+	//if (i_InterruptFlag == ADDIDATA_ENABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) {
+      /************************/
+		/* Enable the interrupt */
+      /************************/
+		ui_CommandRegister = ui_CommandRegister | 0x00100000;
+	}			//if (i_InterruptFlag == ADDIDATA_ENABLE)
+
+  /******************************/
+	/* Write the command register */
+  /******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8);
+	outl(ui_CommandRegister,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+
+  /*****************************/
+	/*Test if interrupt is enable */
+  /*****************************/
+	//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) {
+		do {
+	  /*************************/
+			/*Read the EOC Status bit */
+	  /*************************/
+
+			//ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1;
+			ui_EOC = inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 20) & 1;
+
+		} while (ui_EOC != 1);
+
+      /***************************************/
+		/* Read the digital value of the input */
+      /***************************************/
+
+		//data[0] = inl (devpriv->iobase+i_Offset + 28);
+		data[0] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+		//END JK 06.07.04: Management of sevrals boards
+
+	}			// if (i_InterruptFlag == ADDIDATA_DISABLE)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadCalibrationOffsetValue              |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read calibration offset  value  of the selected channel|
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			          data[0]  : Calibration offset Value   |
+  |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device * dev, UINT * data)
+{
+	UINT ui_Temp = 0, ui_EOC = 0;
+	UINT ui_CommandRegister = 0;
+
+	//BEGIN JK 06.07.04: Management of sevrals boards
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+  /*********************************/
+	/* Write the channel to configure */
+  /*********************************/
+	//Begin JK 20.10.2004: This seems not necessary !
+	//outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4);
+	//outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4);
+	//End JK 20.10.2004: This seems not necessary !
+
+  /*******************************/
+	/* Set the convert timing unit */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+  /**************************/
+	/* Set the convert timing */
+  /**************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+  /*****************************/
+	/*Read the calibration offset */
+  /*****************************/
+	//ui_Temp = inl(devpriv->iobase+i_Offset + 12);
+	ui_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+
+  /*********************************/
+	/*Configure the Offset Conversion */
+  /*********************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl((ui_Temp | 0x00020000), devpriv->iobase+i_Offset + 12);
+	outl((ui_Temp | 0x00020000),
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+  /*******************************/
+	/*Initialise ui_CommandRegister */
+  /*******************************/
+
+	ui_CommandRegister = 0;
+
+  /*********************************/
+	/*Test if the interrupt is enable */
+  /*********************************/
+
+	//if (i_InterruptFlag == ADDIDATA_ENABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) {
+
+      /**********************/
+		/*Enable the interrupt */
+      /**********************/
+
+		ui_CommandRegister = ui_CommandRegister | 0x00100000;
+
+	}			//if (i_InterruptFlag == ADDIDATA_ENABLE)
+
+  /**********************/
+	/*Start the conversion */
+  /**********************/
+	ui_CommandRegister = ui_CommandRegister | 0x00080000;
+
+  /***************************/
+	/*Write the command regiter */
+  /***************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_CommandRegister, devpriv->iobase+i_Offset + 8);
+	outl(ui_CommandRegister,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+
+  /*****************************/
+	/*Test if interrupt is enable */
+  /*****************************/
+
+	//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) {
+
+		do {
+	  /*******************/
+			/*Read the EOC flag */
+	  /*******************/
+
+			//ui_EOC = inl (devpriv->iobase+i_Offset + 20) & 1;
+			ui_EOC = inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 20) & 1;
+
+		} while (ui_EOC != 1);
+
+      /**************************************************/
+		/*Read the digital value of the calibration Offset */
+      /**************************************************/
+
+		//data[0] = inl(devpriv->iobase+i_Offset+ 28);
+		data[0] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+	}			//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadCalibrationGainValue                |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read calibration gain  value  of the selected channel  |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			          data[0]  : Calibration gain Value Of Input     |
+  |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+int i_APCI3200_ReadCalibrationGainValue(struct comedi_device * dev, UINT * data)
+{
+	UINT ui_EOC = 0;
+	INT ui_CommandRegister = 0;
+
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+  /*********************************/
+	/* Write the channel to configure */
+  /*********************************/
+	//Begin JK 20.10.2004: This seems not necessary !
+	//outl(0 | ui_Channel_num , devpriv->iobase+i_Offset + 0x4);
+	//outl(0 | s_BoardInfos [dev->minor].ui_Channel_num , devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 0x4);
+	//End JK 20.10.2004: This seems not necessary !
+
+  /***************************/
+	/*Read the calibration gain */
+  /***************************/
+  /*******************************/
+	/* Set the convert timing unit */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+  /**************************/
+	/* Set the convert timing */
+  /**************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+  /*******************************/
+	/*Configure the Gain Conversion */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(0x00040000 , devpriv->iobase+i_Offset + 12);
+	outl(0x00040000,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+
+  /*******************************/
+	/*Initialise ui_CommandRegister */
+  /*******************************/
+
+	ui_CommandRegister = 0;
+
+  /*********************************/
+	/*Test if the interrupt is enable */
+  /*********************************/
+
+	//if (i_InterruptFlag == ADDIDATA_ENABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) {
+
+      /**********************/
+		/*Enable the interrupt */
+      /**********************/
+
+		ui_CommandRegister = ui_CommandRegister | 0x00100000;
+
+	}			//if (i_InterruptFlag == ADDIDATA_ENABLE)
+
+  /**********************/
+	/*Start the conversion */
+  /**********************/
+
+	ui_CommandRegister = ui_CommandRegister | 0x00080000;
+  /***************************/
+	/*Write the command regiter */
+  /***************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8);
+	outl(ui_CommandRegister,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+
+  /*****************************/
+	/*Test if interrupt is enable */
+  /*****************************/
+
+	//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) {
+
+		do {
+
+	  /*******************/
+			/*Read the EOC flag */
+	  /*******************/
+
+			//ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1;
+			ui_EOC = inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 20) & 1;
+
+		} while (ui_EOC != 1);
+
+      /************************************************/
+		/*Read the digital value of the calibration Gain */
+      /************************************************/
+
+		//data[0] = inl(devpriv->iobase+i_Offset + 28);
+		data[0] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+
+	}			//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadCJCValue                            |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read CJC  value  of the selected channel               |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			          data[0]  : CJC Value                           |
+  |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+
+int i_APCI3200_ReadCJCValue(struct comedi_device * dev, unsigned int * data)
+{
+	UINT ui_EOC = 0;
+	INT ui_CommandRegister = 0;
+
+  /******************************/
+	/*Set the converting time unit */
+  /******************************/
+
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+  /**************************/
+	/* Set the convert timing */
+  /**************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+
+  /******************************/
+	/*Configure the CJC Conversion */
+  /******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl( 0x00000400 , devpriv->iobase+i_Offset + 4);
+	outl(0x00000400,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4);
+  /*******************************/
+	/*Initialise dw_CommandRegister */
+  /*******************************/
+	ui_CommandRegister = 0;
+  /*********************************/
+	/*Test if the interrupt is enable */
+  /*********************************/
+	//if (i_InterruptFlag == ADDIDATA_ENABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) {
+      /**********************/
+		/*Enable the interrupt */
+      /**********************/
+		ui_CommandRegister = ui_CommandRegister | 0x00100000;
+	}
+
+  /**********************/
+	/*Start the conversion */
+  /**********************/
+
+	ui_CommandRegister = ui_CommandRegister | 0x00080000;
+
+  /***************************/
+	/*Write the command regiter */
+  /***************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_CommandRegister , devpriv->iobase+i_Offset + 8);
+	outl(ui_CommandRegister,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+
+  /*****************************/
+	/*Test if interrupt is enable */
+  /*****************************/
+
+	//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) {
+		do {
+
+	  /*******************/
+			/*Read the EOC flag */
+	  /*******************/
+
+			//ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1;
+			ui_EOC = inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 20) & 1;
+
+		} while (ui_EOC != 1);
+
+      /***********************************/
+		/*Read the digital value of the CJC */
+      /***********************************/
+
+		//data[0] = inl(devpriv->iobase+i_Offset + 28);
+		data[0] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+
+	}			//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadCJCCalOffset                        |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read CJC calibration offset  value  of the selected channel
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			          data[0]  : CJC calibration offset Value
+  |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+int i_APCI3200_ReadCJCCalOffset(struct comedi_device * dev, unsigned int * data)
+{
+	UINT ui_EOC = 0;
+	INT ui_CommandRegister = 0;
+  /*******************************************/
+	/*Read calibration offset value for the CJC */
+  /*******************************************/
+  /*******************************/
+	/* Set the convert timing unit */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+  /**************************/
+	/* Set the convert timing */
+  /**************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+  /******************************/
+	/*Configure the CJC Conversion */
+  /******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(0x00000400 , devpriv->iobase+i_Offset + 4);
+	outl(0x00000400,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4);
+  /*********************************/
+	/*Configure the Offset Conversion */
+  /*********************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(0x00020000, devpriv->iobase+i_Offset + 12);
+	outl(0x00020000,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+  /*******************************/
+	/*Initialise ui_CommandRegister */
+  /*******************************/
+	ui_CommandRegister = 0;
+  /*********************************/
+	/*Test if the interrupt is enable */
+  /*********************************/
+
+	//if (i_InterruptFlag == ADDIDATA_ENABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) {
+      /**********************/
+		/*Enable the interrupt */
+      /**********************/
+		ui_CommandRegister = ui_CommandRegister | 0x00100000;
+
+	}
+
+  /**********************/
+	/*Start the conversion */
+  /**********************/
+	ui_CommandRegister = ui_CommandRegister | 0x00080000;
+  /***************************/
+	/*Write the command regiter */
+  /***************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_CommandRegister,devpriv->iobase+i_Offset + 8);
+	outl(ui_CommandRegister,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+	//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) {
+		do {
+	  /*******************/
+			/*Read the EOC flag */
+	  /*******************/
+			//ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1;
+			ui_EOC = inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 20) & 1;
+		} while (ui_EOC != 1);
+
+      /**************************************************/
+		/*Read the digital value of the calibration Offset */
+      /**************************************************/
+		//data[0] = inl(devpriv->iobase+i_Offset + 28);
+		data[0] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+	}			//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_ReadCJCGainValue                        |
+  |			          (struct comedi_device *dev,struct comedi_subdevice *s,       |
+  |                     struct comedi_insn *insn,unsigned int *data)                      |
+  +----------------------------------------------------------------------------+
+  | Task              : Read CJC calibration gain value
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     UINT ui_NoOfChannels    : No Of Channels To read       |
+  |                     UINT *data              : Data Pointer to read status  |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			          data[0]  : CJC calibration gain value
+  |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+int i_APCI3200_ReadCJCCalGain(struct comedi_device * dev, unsigned int * data)
+{
+	UINT ui_EOC = 0;
+	INT ui_CommandRegister = 0;
+  /*******************************/
+	/* Set the convert timing unit */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTimeUnit , devpriv->iobase+i_Offset + 36);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+  /**************************/
+	/* Set the convert timing */
+  /**************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(i_ADDIDATAConversionTime , devpriv->iobase+i_Offset + 32);
+	outl(s_BoardInfos[dev->minor].i_ADDIDATAConversionTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+  /******************************/
+	/*Configure the CJC Conversion */
+  /******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(0x00000400,devpriv->iobase+i_Offset + 4);
+	outl(0x00000400,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4);
+  /*******************************/
+	/*Configure the Gain Conversion */
+  /*******************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(0x00040000,devpriv->iobase+i_Offset + 12);
+	outl(0x00040000,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+
+  /*******************************/
+	/*Initialise dw_CommandRegister */
+  /*******************************/
+	ui_CommandRegister = 0;
+  /*********************************/
+	/*Test if the interrupt is enable */
+  /*********************************/
+	//if (i_InterruptFlag == ADDIDATA_ENABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_ENABLE) {
+      /**********************/
+		/*Enable the interrupt */
+      /**********************/
+		ui_CommandRegister = ui_CommandRegister | 0x00100000;
+	}
+  /**********************/
+	/*Start the conversion */
+  /**********************/
+	ui_CommandRegister = ui_CommandRegister | 0x00080000;
+  /***************************/
+	/*Write the command regiter */
+  /***************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_CommandRegister ,devpriv->iobase+i_Offset + 8);
+	outl(ui_CommandRegister,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+	//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == ADDIDATA_DISABLE) {
+		do {
+	  /*******************/
+			/*Read the EOC flag */
+	  /*******************/
+			//ui_EOC = inl(devpriv->iobase+i_Offset + 20) & 1;
+			ui_EOC = inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 20) & 1;
+		} while (ui_EOC != 1);
+      /************************************************/
+		/*Read the digital value of the calibration Gain */
+      /************************************************/
+		//data[0] = inl (devpriv->iobase+i_Offset + 28);
+		data[0] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+	}			//if (i_InterruptFlag == ADDIDATA_DISABLE)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_InsnBits_AnalogInput_Test               |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              : Tests the Selected Anlog Input Channel                 |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     struct comedi_subdevice *s     : Subdevice Pointer            |
+  |                     struct comedi_insn *insn       : Insn Structure Pointer       |
+  |                     unsigned int *data          : Data Pointer contains        |
+  |                                          configuration parameters as below |
+  |
+  |
+  |                           data[0]            : 0 TestAnalogInputShortCircuit
+  |									     1 TestAnalogInputConnection							 														                        |
+
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  |			        data[0]            : Digital value obtained      |
+  |                           data[1]            : calibration offset          |
+  |                           data[2]            : calibration gain            |
+  |			                                                         |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+
+INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Configuration = 0;
+	INT i_Temp;		//,i_TimeUnit;
+	//if(i_Initialised==0)
+
+	if (s_BoardInfos[dev->minor].i_Initialised == 0) {
+		i_APCI3200_Reset(dev);
+		return -EINVAL;
+	}			//if(i_Initialised==0);
+	if (data[0] != 0 && data[0] != 1) {
+		printk("\nError in selection of functionality\n");
+		i_APCI3200_Reset(dev);
+		return -EINVAL;
+	}			//if(data[0]!=0 && data[0]!=1)
+
+	if (data[0] == 1)	//Perform Short Circuit TEST
+	{
+      /**************************/
+		/*Set the short-cicuit bit */
+      /**************************/
+		//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+		while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].
+						i_Offset + 12) >> 19) & 1) !=
+			1) ;
+		//outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4);
+		outl((0x00001000 | s_BoardInfos[dev->minor].i_ChannelNo),
+			devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+			4);
+      /*************************/
+		/*Set the time unit to ns */
+      /*************************/
+		/* i_TimeUnit= i_ADDIDATAConversionTimeUnit;
+		   i_ADDIDATAConversionTimeUnit= 1; */
+		//i_Temp= i_InterruptFlag ;
+		i_Temp = s_BoardInfos[dev->minor].i_InterruptFlag;
+		//i_InterruptFlag = ADDIDATA_DISABLE;
+		s_BoardInfos[dev->minor].i_InterruptFlag = ADDIDATA_DISABLE;
+		i_APCI3200_Read1AnalogInputChannel(dev, s, insn, data);
+		//if(i_AutoCalibration == FALSE)
+		if (s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) {
+			//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+			while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].
+							i_Offset +
+							12) >> 19) & 1) != 1) ;
+
+			//outl((0x00001000 |i_ChannelNo) , devpriv->iobase+i_Offset + 4);
+			outl((0x00001000 | s_BoardInfos[dev->minor].
+					i_ChannelNo),
+				devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 4);
+			data++;
+			i_APCI3200_ReadCalibrationOffsetValue(dev, data);
+			data++;
+			i_APCI3200_ReadCalibrationGainValue(dev, data);
+		}
+	} else {
+		//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+		while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].
+						i_Offset + 12) >> 19) & 1) !=
+			1) ;
+		//outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4);
+		outl((0x00000800 | s_BoardInfos[dev->minor].i_ChannelNo),
+			devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+			4);
+		//ui_Configuration = inl(devpriv->iobase+i_Offset + 0);
+		ui_Configuration =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 0);
+      /*************************/
+		/*Set the time unit to ns */
+      /*************************/
+		/* i_TimeUnit= i_ADDIDATAConversionTimeUnit;
+		   i_ADDIDATAConversionTimeUnit= 1; */
+		//i_Temp= i_InterruptFlag ;
+		i_Temp = s_BoardInfos[dev->minor].i_InterruptFlag;
+		//i_InterruptFlag = ADDIDATA_DISABLE;
+		s_BoardInfos[dev->minor].i_InterruptFlag = ADDIDATA_DISABLE;
+		i_APCI3200_Read1AnalogInputChannel(dev, s, insn, data);
+		//if(i_AutoCalibration == FALSE)
+		if (s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) {
+			//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+			while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].
+							i_Offset +
+							12) >> 19) & 1) != 1) ;
+			//outl((0x00000800|i_ChannelNo) , devpriv->iobase+i_Offset + 4);
+			outl((0x00000800 | s_BoardInfos[dev->minor].
+					i_ChannelNo),
+				devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 4);
+			data++;
+			i_APCI3200_ReadCalibrationOffsetValue(dev, data);
+			data++;
+			i_APCI3200_ReadCalibrationGainValue(dev, data);
+		}
+	}
+	//i_InterruptFlag=i_Temp ;
+	s_BoardInfos[dev->minor].i_InterruptFlag = i_Temp;
+	//printk("\ni_InterruptFlag=%d\n",i_InterruptFlag);
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : int i_APCI3200_InsnWriteReleaseAnalogInput             |
+  |			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+  |                      struct comedi_insn *insn,unsigned int *data)                     |
+  +----------------------------------------------------------------------------+
+  | Task              :  Resets the channels                                                      |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev      : Driver handle                |
+  |                     struct comedi_subdevice *s     : Subdevice Pointer            |
+  |                     struct comedi_insn *insn       : Insn Structure Pointer       |
+  |                     unsigned int *data          : Data Pointer
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error          |
+  |			                                                         |
+  +----------------------------------------------------------------------------+
+*/
+
+INT i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	i_APCI3200_Reset(dev);
+	return insn->n;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function name     :int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev|
+  |			,struct comedi_subdevice *s,struct comedi_cmd *cmd)			         |
+  |                                        									 |
+  +----------------------------------------------------------------------------+
+  | Task              : Test validity for a command for cyclic anlog input     |
+  |                       acquisition  						     			 |
+  |                     										                 |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev									 |
+  |                     struct comedi_subdevice *s									 |
+  |                     struct comedi_cmd *cmd              					         |
+  |                     										                 |
+  |
+  |                     										                 |
+  |                     										                 |
+  |                     										                 |
+  +----------------------------------------------------------------------------+
+  | Return Value      :0              					                     |
+  |                    													     |
+  +----------------------------------------------------------------------------+
+*/
+
+int i_APCI3200_CommandTestAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_cmd * cmd)
+{
+
+	int err = 0;
+	int tmp;		// divisor1,divisor2;
+	UINT ui_ConvertTime = 0;
+	UINT ui_ConvertTimeBase = 0;
+	UINT ui_DelayTime = 0;
+	UINT ui_DelayTimeBase = 0;
+	INT i_Triggermode = 0;
+	INT i_TriggerEdge = 0;
+	INT i_NbrOfChannel = 0;
+	INT i_Cpt = 0;
+	double d_ConversionTimeForAllChannels = 0.0;
+	double d_SCANTimeNewUnit = 0.0;
+	// step 1: make sure trigger sources are trivially valid
+
+	tmp = cmd->start_src;
+	cmd->start_src &= TRIG_NOW | TRIG_EXT;
+	if (!cmd->start_src || tmp != cmd->start_src)
+		err++;
+	tmp = cmd->scan_begin_src;
+	cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW;
+	if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
+		err++;
+	tmp = cmd->convert_src;
+	cmd->convert_src &= TRIG_TIMER;
+	if (!cmd->convert_src || tmp != cmd->convert_src)
+		err++;
+	tmp = cmd->scan_end_src;
+	cmd->scan_end_src &= TRIG_COUNT;
+	if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
+		err++;
+	tmp = cmd->stop_src;
+	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
+	if (!cmd->stop_src || tmp != cmd->stop_src)
+		err++;
+	//if(i_InterruptFlag==0)
+	if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) {
+		err++;
+		//          printk("\nThe interrupt should be enabled\n");
+	}
+	if (err) {
+		i_APCI3200_Reset(dev);
+		return 1;
+	}
+
+	if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
+		err++;
+	}
+	if (cmd->start_src == TRIG_EXT) {
+		i_TriggerEdge = cmd->start_arg & 0xFFFF;
+		i_Triggermode = cmd->start_arg >> 16;
+		if (i_TriggerEdge < 1 || i_TriggerEdge > 3) {
+			err++;
+			printk("\nThe trigger edge selection is in error\n");
+		}
+		if (i_Triggermode != 2) {
+			err++;
+			printk("\nThe trigger mode selection is in error\n");
+		}
+	}
+
+	if (cmd->scan_begin_src != TRIG_TIMER &&
+		cmd->scan_begin_src != TRIG_FOLLOW)
+		err++;
+
+	if (cmd->convert_src != TRIG_TIMER)
+		err++;
+
+	if (cmd->scan_end_src != TRIG_COUNT) {
+		cmd->scan_end_src = TRIG_COUNT;
+		err++;
+	}
+
+	if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT)
+		err++;
+
+	if (err) {
+		i_APCI3200_Reset(dev);
+		return 2;
+	}
+	//i_FirstChannel=cmd->chanlist[0];
+	s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0];
+	//i_LastChannel=cmd->chanlist[1];
+	s_BoardInfos[dev->minor].i_LastChannel = cmd->chanlist[1];
+
+	if (cmd->convert_src == TRIG_TIMER) {
+		ui_ConvertTime = cmd->convert_arg & 0xFFFF;
+		ui_ConvertTimeBase = cmd->convert_arg >> 16;
+		if (ui_ConvertTime != 20 && ui_ConvertTime != 40
+			&& ui_ConvertTime != 80 && ui_ConvertTime != 160)
+		{
+			printk("\nThe selection of conversion time reload value is in error\n");
+			err++;
+		}		// if (ui_ConvertTime!=20 && ui_ConvertTime!=40 && ui_ConvertTime!=80 && ui_ConvertTime!=160 )
+		if (ui_ConvertTimeBase != 2) {
+			printk("\nThe selection of conversion time unit  is in error\n");
+			err++;
+		}		//if(ui_ConvertTimeBase!=2)
+	} else {
+		ui_ConvertTime = 0;
+		ui_ConvertTimeBase = 0;
+	}
+	if (cmd->scan_begin_src == TRIG_FOLLOW) {
+		ui_DelayTime = 0;
+		ui_DelayTimeBase = 0;
+	}			//if(cmd->scan_begin_src==TRIG_FOLLOW)
+	else {
+		ui_DelayTime = cmd->scan_begin_arg & 0xFFFF;
+		ui_DelayTimeBase = cmd->scan_begin_arg >> 16;
+		if (ui_DelayTimeBase != 2 && ui_DelayTimeBase != 3) {
+			err++;
+			printk("\nThe Delay time base selection is in error\n");
+		}
+		if (ui_DelayTime < 1 && ui_DelayTime > 1023) {
+			err++;
+			printk("\nThe Delay time value is in error\n");
+		}
+		if (err) {
+			i_APCI3200_Reset(dev);
+			return 3;
+		}
+		fpu_begin();
+		d_SCANTimeNewUnit = (double)ui_DelayTime;
+		//i_NbrOfChannel= i_LastChannel-i_FirstChannel + 4;
+		i_NbrOfChannel =
+			s_BoardInfos[dev->minor].i_LastChannel -
+			s_BoardInfos[dev->minor].i_FirstChannel + 4;
+      /**********************************************************/
+		/*calculate the total conversion time for all the channels */
+      /**********************************************************/
+		d_ConversionTimeForAllChannels =
+			(double)((double)ui_ConvertTime /
+			(double)i_NbrOfChannel);
+
+      /*******************************/
+		/*Convert the frequence in time */
+      /*******************************/
+		d_ConversionTimeForAllChannels =
+			(double)1.0 / d_ConversionTimeForAllChannels;
+		ui_ConvertTimeBase = 3;
+      /***********************************/
+		/*Test if the time unit is the same */
+      /***********************************/
+
+		if (ui_DelayTimeBase <= ui_ConvertTimeBase) {
+
+			for (i_Cpt = 0;
+				i_Cpt < (ui_ConvertTimeBase - ui_DelayTimeBase);
+				i_Cpt++) {
+
+				d_ConversionTimeForAllChannels =
+					d_ConversionTimeForAllChannels * 1000;
+				d_ConversionTimeForAllChannels =
+					d_ConversionTimeForAllChannels + 1;
+			}
+		} else {
+			for (i_Cpt = 0;
+				i_Cpt < (ui_DelayTimeBase - ui_ConvertTimeBase);
+				i_Cpt++) {
+				d_SCANTimeNewUnit = d_SCANTimeNewUnit * 1000;
+
+			}
+		}
+
+		if (d_ConversionTimeForAllChannels >= d_SCANTimeNewUnit) {
+
+			printk("\nSCAN Delay value cannot be used\n");
+	  /*********************************/
+			/*SCAN Delay value cannot be used */
+	  /*********************************/
+			err++;
+		}
+		fpu_end();
+	}			//else if(cmd->scan_begin_src==TRIG_FOLLOW)
+
+	if (err) {
+		i_APCI3200_Reset(dev);
+		return 4;
+	}
+
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function name     :int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev,|
+  | 											     struct comedi_subdevice *s)|
+  |                                        									 |
+  +----------------------------------------------------------------------------+
+  | Task              : Stop the  acquisition  						     |
+  |                     										                 |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev									 |
+  |                     struct comedi_subdevice *s									 |
+  |                                                 					         |
+  +----------------------------------------------------------------------------+
+  | Return Value      :0              					                     |
+  |                    													     |
+  +----------------------------------------------------------------------------+
+*/
+
+int i_APCI3200_StopCyclicAcquisition(struct comedi_device * dev, struct comedi_subdevice * s)
+{
+	UINT ui_Configuration = 0;
+	//i_InterruptFlag=0;
+	//i_Initialised=0;
+	//i_Count=0;
+	//i_Sum=0;
+	s_BoardInfos[dev->minor].i_InterruptFlag = 0;
+	s_BoardInfos[dev->minor].i_Initialised = 0;
+	s_BoardInfos[dev->minor].i_Count = 0;
+	s_BoardInfos[dev->minor].i_Sum = 0;
+
+  /*******************/
+	/*Read the register */
+  /*******************/
+	//ui_Configuration = inl(devpriv->iobase+i_Offset + 8);
+	ui_Configuration =
+		inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+  /*****************************/
+	/*Reset the START and IRQ bit */
+  /*****************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl((ui_Configuration & 0xFFE7FFFF),devpriv->iobase+i_Offset + 8);
+	outl((ui_Configuration & 0xFFE7FFFF),
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function name     : int i_APCI3200_CommandAnalogInput(struct comedi_device *dev,  |
+  |												struct comedi_subdevice *s) |
+  |                                        									 |
+  +----------------------------------------------------------------------------+
+  | Task              : Does asynchronous acquisition                          |
+  |                     Determines the mode 1 or 2.						     |
+  |                     										                 |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev									 |
+  |                     struct comedi_subdevice *s									 |
+  |                     														 |
+  |                     														 |
+  +----------------------------------------------------------------------------+
+  | Return Value      :              					                         |
+  |                    													     |
+  +----------------------------------------------------------------------------+
+*/
+
+int i_APCI3200_CommandAnalogInput(struct comedi_device * dev, struct comedi_subdevice * s)
+{
+	struct comedi_cmd *cmd = &s->async->cmd;
+	UINT ui_Configuration = 0;
+	//INT  i_CurrentSource = 0;
+	UINT ui_Trigger = 0;
+	UINT ui_TriggerEdge = 0;
+	UINT ui_Triggermode = 0;
+	UINT ui_ScanMode = 0;
+	UINT ui_ConvertTime = 0;
+	UINT ui_ConvertTimeBase = 0;
+	UINT ui_DelayTime = 0;
+	UINT ui_DelayTimeBase = 0;
+	UINT ui_DelayMode = 0;
+	//i_FirstChannel=cmd->chanlist[0];
+	//i_LastChannel=cmd->chanlist[1];
+	s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0];
+	s_BoardInfos[dev->minor].i_LastChannel = cmd->chanlist[1];
+	if (cmd->start_src == TRIG_EXT) {
+		ui_Trigger = 1;
+		ui_TriggerEdge = cmd->start_arg & 0xFFFF;
+		ui_Triggermode = cmd->start_arg >> 16;
+	}			//if(cmd->start_src==TRIG_EXT)
+	else {
+		ui_Trigger = 0;
+	}			//elseif(cmd->start_src==TRIG_EXT)
+
+	if (cmd->stop_src == TRIG_COUNT) {
+		ui_ScanMode = 0;
+	}			// if (cmd->stop_src==TRIG_COUNT)
+	else {
+		ui_ScanMode = 2;
+	}			//else if (cmd->stop_src==TRIG_COUNT)
+
+	if (cmd->scan_begin_src == TRIG_FOLLOW) {
+		ui_DelayTime = 0;
+		ui_DelayTimeBase = 0;
+		ui_DelayMode = 0;
+	}			//if(cmd->scan_begin_src==TRIG_FOLLOW)
+	else {
+		ui_DelayTime = cmd->scan_begin_arg & 0xFFFF;
+		ui_DelayTimeBase = cmd->scan_begin_arg >> 16;
+		ui_DelayMode = 1;
+	}			//else if(cmd->scan_begin_src==TRIG_FOLLOW)
+	//        printk("\nui_DelayTime=%u\n",ui_DelayTime);
+	//        printk("\nui_DelayTimeBase=%u\n",ui_DelayTimeBase);
+	if (cmd->convert_src == TRIG_TIMER) {
+		ui_ConvertTime = cmd->convert_arg & 0xFFFF;
+		ui_ConvertTimeBase = cmd->convert_arg >> 16;
+	} else {
+		ui_ConvertTime = 0;
+		ui_ConvertTimeBase = 0;
+	}
+
+	// if(i_ADDIDATAType ==1 || ((i_ADDIDATAType==2)))
+	//   {
+  /**************************************************/
+	/*Read the old configuration of the current source */
+  /**************************************************/
+	//ui_Configuration = inl(devpriv->iobase+i_Offset + 12);
+	ui_Configuration =
+		inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+  /***********************************************/
+	/*Write the configuration of the current source */
+  /***********************************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl((ui_Configuration & 0xFFC00000 ), devpriv->iobase+i_Offset +12);
+	outl((ui_Configuration & 0xFFC00000),
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12);
+	// }
+	ui_Configuration = 0;
+	//     printk("\nfirstchannel=%u\n",i_FirstChannel);
+	//     printk("\nlastchannel=%u\n",i_LastChannel);
+	//     printk("\nui_Trigger=%u\n",ui_Trigger);
+	//     printk("\nui_TriggerEdge=%u\n",ui_TriggerEdge);
+	//     printk("\nui_Triggermode=%u\n",ui_Triggermode);
+	//      printk("\nui_DelayMode=%u\n",ui_DelayMode);
+	//     printk("\nui_ScanMode=%u\n",ui_ScanMode);
+
+	//ui_Configuration = i_FirstChannel |(i_LastChannel << 8)| 0x00100000 |
+	ui_Configuration =
+		s_BoardInfos[dev->minor].i_FirstChannel | (s_BoardInfos[dev->
+			minor].
+		i_LastChannel << 8) | 0x00100000 | (ui_Trigger << 24) |
+		(ui_TriggerEdge << 25) | (ui_Triggermode << 27) | (ui_DelayMode
+		<< 18) | (ui_ScanMode << 16);
+
+  /*************************/
+	/*Write the Configuration */
+  /*************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl( ui_Configuration, devpriv->iobase+i_Offset + 0x8);
+	outl(ui_Configuration,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x8);
+  /***********************/
+	/*Write the Delay Value */
+  /***********************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_DelayTime,devpriv->iobase+i_Offset + 40);
+	outl(ui_DelayTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 40);
+  /***************************/
+	/*Write the Delay time base */
+  /***************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_DelayTimeBase,devpriv->iobase+i_Offset + 44);
+	outl(ui_DelayTimeBase,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 44);
+  /*********************************/
+	/*Write the conversion time value */
+  /*********************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_ConvertTime,devpriv->iobase+i_Offset + 32);
+	outl(ui_ConvertTime,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 32);
+
+  /********************************/
+	/*Write the conversion time base */
+  /********************************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl(ui_ConvertTimeBase,devpriv->iobase+i_Offset + 36);
+	outl(ui_ConvertTimeBase,
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 36);
+  /*******************/
+	/*Read the register */
+  /*******************/
+	//ui_Configuration = inl(devpriv->iobase+i_Offset + 4);
+	ui_Configuration =
+		inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4);
+  /******************/
+	/*Set the SCAN bit */
+  /******************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+
+	//outl(((ui_Configuration & 0x1E0FF) | 0x00002000),devpriv->iobase+i_Offset + 4);
+	outl(((ui_Configuration & 0x1E0FF) | 0x00002000),
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 4);
+  /*******************/
+	/*Read the register */
+  /*******************/
+	ui_Configuration = 0;
+	//ui_Configuration = inl(devpriv->iobase+i_Offset + 8);
+	ui_Configuration =
+		inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+
+  /*******************/
+	/*Set the START bit */
+  /*******************/
+	//while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1);
+	while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset +
+					12) >> 19) & 1) != 1) ;
+	//outl((ui_Configuration | 0x00080000),devpriv->iobase+i_Offset + 8);
+	outl((ui_Configuration | 0x00080000),
+		devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 8);
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   :  int i_APCI3200_Reset(struct comedi_device *dev)			     |
+  |							                                         |
+  +----------------------------------------------------------------------------+
+  | Task              :Resets the registers of the card                        |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  :                                                        |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  +----------------------------------------------------------------------------+
+  | Return Value      :                                                        |
+  |					                                                 |
+  +----------------------------------------------------------------------------+
+*/
+
+int i_APCI3200_Reset(struct comedi_device * dev)
+{
+	INT i_Temp;
+	DWORD dw_Dummy;
+	//i_InterruptFlag=0;
+	//i_Initialised==0;
+	//i_Count=0;
+	//i_Sum=0;
+
+	s_BoardInfos[dev->minor].i_InterruptFlag = 0;
+	s_BoardInfos[dev->minor].i_Initialised = 0;
+	s_BoardInfos[dev->minor].i_Count = 0;
+	s_BoardInfos[dev->minor].i_Sum = 0;
+	s_BoardInfos[dev->minor].b_StructInitialized = 0;
+
+	outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
+
+	// Enable the interrupt for the controler
+	dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
+	outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
+	outl(0, devpriv->i_IobaseAddon);	//Resets the output
+  /***************/
+	/*Empty the buffer */
+  /**************/
+	for (i_Temp = 0; i_Temp <= 95; i_Temp++) {
+		//ui_InterruptChannelValue[i_Temp]=0;
+		s_BoardInfos[dev->minor].ui_InterruptChannelValue[i_Temp] = 0;
+	}			//for(i_Temp=0;i_Temp<=95;i_Temp++)
+  /*****************************/
+	/*Reset the START and IRQ bit */
+  /*****************************/
+	for (i_Temp = 0; i_Temp <= 192;) {
+		while (((inl(devpriv->iobase + i_Temp + 12) >> 19) & 1) != 1) ;
+		outl(0, devpriv->iobase + i_Temp + 8);
+		i_Temp = i_Temp + 64;
+	}			//for(i_Temp=0;i_Temp<=192;i_Temp+64)
+	return 0;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function   Name   : static void v_APCI3200_Interrupt					     |
+  |					  (int irq , void *d)				 |
+  +----------------------------------------------------------------------------+
+  | Task              : Interrupt processing Routine                           |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : int irq                 : irq number                   |
+  |                     void *d                 : void pointer                 |
+  +----------------------------------------------------------------------------+
+  | Output Parameters :	--													 |
+  +----------------------------------------------------------------------------+
+  | Return Value      : TRUE  : No error occur                                 |
+  |		            : FALSE : Error occur. Return the error					 |
+  |					                                                         |
+  +----------------------------------------------------------------------------+
+*/
+void v_APCI3200_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	UINT ui_StatusRegister = 0;
+	UINT ui_ChannelNumber = 0;
+	INT i_CalibrationFlag = 0;
+	INT i_CJCFlag = 0;
+	UINT ui_DummyValue = 0;
+	UINT ui_DigitalTemperature = 0;
+	UINT ui_DigitalInput = 0;
+	int i_ConvertCJCCalibration;
+
+	//BEGIN JK TEST
+	int i_ReturnValue = 0;
+	//END JK TEST
+
+	//printk ("\n i_ScanType = %i i_ADDIDATAType = %i", s_BoardInfos [dev->minor].i_ScanType, s_BoardInfos [dev->minor].i_ADDIDATAType);
+
+	//switch(i_ScanType)
+	switch (s_BoardInfos[dev->minor].i_ScanType) {
+	case 0:
+	case 1:
+		//switch(i_ADDIDATAType)
+		switch (s_BoardInfos[dev->minor].i_ADDIDATAType) {
+		case 0:
+		case 1:
+
+	  /************************************/
+			/*Read the interrupt status register */
+	  /************************************/
+			//ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16);
+			ui_StatusRegister =
+				inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 16);
+			if ((ui_StatusRegister & 0x2) == 0x2) {
+				//i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17);
+				i_CalibrationFlag =
+					((inl(devpriv->iobase +
+							s_BoardInfos[dev->
+								minor].
+							i_Offset +
+							12) & 0x00060000) >>
+					17);
+	      /*************************/
+				/*Read the channel number */
+	      /*************************/
+				//ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24);
+
+	      /*************************************/
+				/*Read the digital analog input value */
+	      /*************************************/
+				//ui_DigitalInput = inl(devpriv->iobase+i_Offset + 28);
+				ui_DigitalInput =
+					inl(devpriv->iobase +
+					s_BoardInfos[dev->minor].i_Offset + 28);
+
+	      /***********************************************/
+				/* Test if the value read is the channel value */
+	      /***********************************************/
+				if (i_CalibrationFlag == 0) {
+					//ui_InterruptChannelValue[i_Count + 0] = ui_DigitalInput;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 0] = ui_DigitalInput;
+
+					//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+					/*
+					   printk("\n 1 - i_APCI3200_GetChannelCalibrationValue (dev, s_BoardInfos %i", ui_ChannelNumber);
+					   i_APCI3200_GetChannelCalibrationValue (dev, s_BoardInfos [dev->minor].ui_Channel_num,
+					   &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 6],
+					   &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 7],
+					   &s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count + 8]);
+					 */
+					//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+		  /******************************************************/
+					/*Start the conversion of the calibration offset value */
+		  /******************************************************/
+					i_APCI3200_ReadCalibrationOffsetValue
+						(dev, &ui_DummyValue);
+				}	//if (i_CalibrationFlag == 0)
+	      /**********************************************************/
+				/* Test if the value read is the calibration offset value */
+	      /**********************************************************/
+
+				if (i_CalibrationFlag == 1) {
+
+		  /******************/
+					/* Save the value */
+		  /******************/
+
+					//ui_InterruptChannelValue[i_Count + 1] = ui_DigitalInput;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 1] = ui_DigitalInput;
+
+		  /******************************************************/
+					/* Start the conversion of the calibration gain value */
+		  /******************************************************/
+					i_APCI3200_ReadCalibrationGainValue(dev,
+						&ui_DummyValue);
+				}	//if (i_CalibrationFlag == 1)
+	      /******************************************************/
+				/*Test if the value read is the calibration gain value */
+	      /******************************************************/
+
+				if (i_CalibrationFlag == 2) {
+
+		  /****************/
+					/*Save the value */
+		  /****************/
+					//ui_InterruptChannelValue[i_Count + 2] = ui_DigitalInput;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 2] = ui_DigitalInput;
+					//if(i_ScanType==1)
+					if (s_BoardInfos[dev->minor].
+						i_ScanType == 1) {
+
+						//i_InterruptFlag=0;
+						s_BoardInfos[dev->minor].
+							i_InterruptFlag = 0;
+						//i_Count=i_Count + 6;
+						//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+						//s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6;
+						s_BoardInfos[dev->minor].
+							i_Count =
+							s_BoardInfos[dev->
+							minor].i_Count + 9;
+						//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+					}	//if(i_ScanType==1)
+					else {
+						//i_Count=0;
+						s_BoardInfos[dev->minor].
+							i_Count = 0;
+					}	//elseif(i_ScanType==1)
+					//if(i_ScanType!=1)
+					if (s_BoardInfos[dev->minor].
+						i_ScanType != 1) {
+						i_ReturnValue = send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+					}	//if(i_ScanType!=1)
+					else {
+						//if(i_ChannelCount==i_Sum)
+						if (s_BoardInfos[dev->minor].
+							i_ChannelCount ==
+							s_BoardInfos[dev->
+								minor].i_Sum) {
+							send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+						}
+					}	//if(i_ScanType!=1)
+				}	//if (i_CalibrationFlag == 2)
+			}	// if ((ui_StatusRegister & 0x2) == 0x2)
+
+			break;
+
+		case 2:
+	  /************************************/
+			/*Read the interrupt status register */
+	  /************************************/
+
+			//ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16);
+			ui_StatusRegister =
+				inl(devpriv->iobase +
+				s_BoardInfos[dev->minor].i_Offset + 16);
+	  /*************************/
+			/*Test if interrupt occur */
+	  /*************************/
+
+			if ((ui_StatusRegister & 0x2) == 0x2) {
+
+				//i_CJCFlag = ((inl(devpriv->iobase+i_Offset + 4) & 0x00000400) >> 10);
+				i_CJCFlag =
+					((inl(devpriv->iobase +
+							s_BoardInfos[dev->
+								minor].
+							i_Offset +
+							4) & 0x00000400) >> 10);
+
+				//i_CalibrationFlag = ((inl(devpriv->iobase+i_Offset + 12) & 0x00060000) >> 17);
+				i_CalibrationFlag =
+					((inl(devpriv->iobase +
+							s_BoardInfos[dev->
+								minor].
+							i_Offset +
+							12) & 0x00060000) >>
+					17);
+
+	      /*************************/
+				/*Read the channel number */
+	      /*************************/
+
+				//ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24);
+				ui_ChannelNumber =
+					inl(devpriv->iobase +
+					s_BoardInfos[dev->minor].i_Offset + 24);
+				//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+				s_BoardInfos[dev->minor].ui_Channel_num =
+					ui_ChannelNumber;
+				//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+	      /************************************/
+				/*Read the digital temperature value */
+	      /************************************/
+				//ui_DigitalTemperature = inl(devpriv->iobase+i_Offset + 28);
+				ui_DigitalTemperature =
+					inl(devpriv->iobase +
+					s_BoardInfos[dev->minor].i_Offset + 28);
+
+	      /*********************************************/
+				/*Test if the value read is the channel value */
+	      /*********************************************/
+
+				if ((i_CalibrationFlag == 0)
+					&& (i_CJCFlag == 0)) {
+					//ui_InterruptChannelValue[i_Count + 0]=ui_DigitalTemperature;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 0] =
+						ui_DigitalTemperature;
+
+		  /*********************************/
+					/*Start the conversion of the CJC */
+		  /*********************************/
+					i_APCI3200_ReadCJCValue(dev,
+						&ui_DummyValue);
+
+				}	//if ((i_CalibrationFlag == 0) && (i_CJCFlag == 0))
+
+		 /*****************************************/
+				/*Test if the value read is the CJC value */
+		 /*****************************************/
+
+				if ((i_CJCFlag == 1)
+					&& (i_CalibrationFlag == 0)) {
+					//ui_InterruptChannelValue[i_Count + 3]=ui_DigitalTemperature;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 3] =
+						ui_DigitalTemperature;
+
+		  /******************************************************/
+					/*Start the conversion of the calibration offset value */
+		  /******************************************************/
+					i_APCI3200_ReadCalibrationOffsetValue
+						(dev, &ui_DummyValue);
+				}	// if ((i_CJCFlag == 1) && (i_CalibrationFlag == 0))
+
+		 /********************************************************/
+				/*Test if the value read is the calibration offset value */
+		 /********************************************************/
+
+				if ((i_CalibrationFlag == 1)
+					&& (i_CJCFlag == 0)) {
+					//ui_InterruptChannelValue[i_Count + 1]=ui_DigitalTemperature;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 1] =
+						ui_DigitalTemperature;
+
+		  /****************************************************/
+					/*Start the conversion of the calibration gain value */
+		  /****************************************************/
+					i_APCI3200_ReadCalibrationGainValue(dev,
+						&ui_DummyValue);
+
+				}	//if ((i_CalibrationFlag == 1) && (i_CJCFlag == 0))
+
+	      /******************************************************/
+				/*Test if the value read is the calibration gain value */
+	      /******************************************************/
+
+				if ((i_CalibrationFlag == 2)
+					&& (i_CJCFlag == 0)) {
+					//ui_InterruptChannelValue[i_Count + 2]=ui_DigitalTemperature;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 2] =
+						ui_DigitalTemperature;
+
+		  /**********************************************************/
+					/*Test if the Calibration channel must be read for the CJC */
+		  /**********************************************************/
+
+					/*Test if the polarity is the same */
+		  /**********************************/
+					//if(i_CJCPolarity!=i_ADDIDATAPolarity)
+					if (s_BoardInfos[dev->minor].
+						i_CJCPolarity !=
+						s_BoardInfos[dev->minor].
+						i_ADDIDATAPolarity) {
+						i_ConvertCJCCalibration = 1;
+					}	//if(i_CJCPolarity!=i_ADDIDATAPolarity)
+					else {
+						//if(i_CJCGain==i_ADDIDATAGain)
+						if (s_BoardInfos[dev->minor].
+							i_CJCGain ==
+							s_BoardInfos[dev->
+								minor].
+							i_ADDIDATAGain) {
+							i_ConvertCJCCalibration
+								= 0;
+						}	//if(i_CJCGain==i_ADDIDATAGain)
+						else {
+							i_ConvertCJCCalibration
+								= 1;
+						}	//elseif(i_CJCGain==i_ADDIDATAGain)
+					}	//elseif(i_CJCPolarity!=i_ADDIDATAPolarity)
+					if (i_ConvertCJCCalibration == 1) {
+		      /****************************************************************/
+						/*Start the conversion of the calibration gain value for the CJC */
+		      /****************************************************************/
+						i_APCI3200_ReadCJCCalOffset(dev,
+							&ui_DummyValue);
+
+					}	//if(i_ConvertCJCCalibration==1)
+					else {
+						//ui_InterruptChannelValue[i_Count + 4]=0;
+						//ui_InterruptChannelValue[i_Count + 5]=0;
+						s_BoardInfos[dev->minor].
+							ui_InterruptChannelValue
+							[s_BoardInfos[dev->
+								minor].i_Count +
+							4] = 0;
+						s_BoardInfos[dev->minor].
+							ui_InterruptChannelValue
+							[s_BoardInfos[dev->
+								minor].i_Count +
+							5] = 0;
+					}	//elseif(i_ConvertCJCCalibration==1)
+				}	//else if ((i_CalibrationFlag == 2) && (i_CJCFlag == 0))
+
+		 /********************************************************************/
+				/*Test if the value read is the calibration offset value for the CJC */
+		 /********************************************************************/
+
+				if ((i_CalibrationFlag == 1)
+					&& (i_CJCFlag == 1)) {
+					//ui_InterruptChannelValue[i_Count + 4]=ui_DigitalTemperature;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 4] =
+						ui_DigitalTemperature;
+
+		  /****************************************************************/
+					/*Start the conversion of the calibration gain value for the CJC */
+		  /****************************************************************/
+					i_APCI3200_ReadCJCCalGain(dev,
+						&ui_DummyValue);
+
+				}	//if ((i_CalibrationFlag == 1) && (i_CJCFlag == 1))
+
+	      /******************************************************************/
+				/*Test if the value read is the calibration gain value for the CJC */
+	      /******************************************************************/
+
+				if ((i_CalibrationFlag == 2)
+					&& (i_CJCFlag == 1)) {
+					//ui_InterruptChannelValue[i_Count + 5]=ui_DigitalTemperature;
+					s_BoardInfos[dev->minor].
+						ui_InterruptChannelValue
+						[s_BoardInfos[dev->minor].
+						i_Count + 5] =
+						ui_DigitalTemperature;
+
+					//if(i_ScanType==1)
+					if (s_BoardInfos[dev->minor].
+						i_ScanType == 1) {
+
+						//i_InterruptFlag=0;
+						s_BoardInfos[dev->minor].
+							i_InterruptFlag = 0;
+						//i_Count=i_Count + 6;
+						//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+						//s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count + 6;
+						s_BoardInfos[dev->minor].
+							i_Count =
+							s_BoardInfos[dev->
+							minor].i_Count + 9;
+						//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+					}	//if(i_ScanType==1)
+					else {
+						//i_Count=0;
+						s_BoardInfos[dev->minor].
+							i_Count = 0;
+					}	//elseif(i_ScanType==1)
+
+					//if(i_ScanType!=1)
+					if (s_BoardInfos[dev->minor].
+						i_ScanType != 1) {
+						send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+					}	//if(i_ScanType!=1)
+					else {
+						//if(i_ChannelCount==i_Sum)
+						if (s_BoardInfos[dev->minor].
+							i_ChannelCount ==
+							s_BoardInfos[dev->
+								minor].i_Sum) {
+							send_sig(SIGIO, devpriv->tsk_Current, 0);	// send signal to the sample
+
+						}	//if(i_ChannelCount==i_Sum)
+					}	//else if(i_ScanType!=1)
+				}	//if ((i_CalibrationFlag == 2) && (i_CJCFlag == 1))
+
+			}	//else if ((ui_StatusRegister & 0x2) == 0x2)
+			break;
+		}		//switch(i_ADDIDATAType)
+		break;
+	case 2:
+	case 3:
+		i_APCI3200_InterruptHandleEos(dev);
+		break;
+	}			//switch(i_ScanType)
+	return;
+}
+
+/*
+  +----------------------------------------------------------------------------+
+  | Function name     :int i_APCI3200_InterruptHandleEos(struct comedi_device *dev)   |
+  |                                        									 |
+  |                                            						         |
+  +----------------------------------------------------------------------------+
+  | Task              : .                   |
+  |                     This function copies the acquired data(from FIFO)      |
+  |				to Comedi buffer.		 							 |
+  |                     										                 |
+  +----------------------------------------------------------------------------+
+  | Input Parameters  : struct comedi_device *dev									 |
+  |                     														 |
+  |                                                 					         |
+  +----------------------------------------------------------------------------+
+  | Return Value      : 0            					                         |
+  |                    													     |
+  +----------------------------------------------------------------------------+
+*/
+int i_APCI3200_InterruptHandleEos(struct comedi_device * dev)
+{
+	UINT ui_StatusRegister = 0;
+	struct comedi_subdevice *s = dev->subdevices + 0;
+
+	//BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+	//comedi_async *async = s->async;
+	//UINT *data;
+	//data=async->data+async->buf_int_ptr;//new samples added from here onwards
+	int n = 0, i = 0;
+	//END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+
+  /************************************/
+	/*Read the interrupt status register */
+  /************************************/
+	//ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16);
+	ui_StatusRegister =
+		inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16);
+
+  /*************************/
+	/*Test if interrupt occur */
+  /*************************/
+
+	if ((ui_StatusRegister & 0x2) == 0x2) {
+      /*************************/
+		/*Read the channel number */
+      /*************************/
+		//ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24);
+		//BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+		//This value is not used
+		//ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24);
+		s->async->events = 0;
+		//END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+
+      /*************************************/
+		/*Read the digital Analog Input value */
+      /*************************************/
+
+		//data[i_Count] = inl(devpriv->iobase+i_Offset + 28);
+		//Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+		//data[s_BoardInfos [dev->minor].i_Count] = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 28);
+		s_BoardInfos[dev->minor].ui_ScanValueArray[s_BoardInfos[dev->
+				minor].i_Count] =
+			inl(devpriv->iobase +
+			s_BoardInfos[dev->minor].i_Offset + 28);
+		//End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+
+		//if((i_Count == (i_LastChannel-i_FirstChannel+3)))
+		if ((s_BoardInfos[dev->minor].i_Count ==
+				(s_BoardInfos[dev->minor].i_LastChannel -
+					s_BoardInfos[dev->minor].
+					i_FirstChannel + 3))) {
+
+			//Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+			s_BoardInfos[dev->minor].i_Count++;
+
+			for (i = s_BoardInfos[dev->minor].i_FirstChannel;
+				i <= s_BoardInfos[dev->minor].i_LastChannel;
+				i++) {
+				i_APCI3200_GetChannelCalibrationValue(dev, i,
+					&s_BoardInfos[dev->minor].
+					ui_ScanValueArray[s_BoardInfos[dev->
+							minor].i_Count + ((i -
+								s_BoardInfos
+								[dev->minor].
+								i_FirstChannel)
+							* 3)],
+					&s_BoardInfos[dev->minor].
+					ui_ScanValueArray[s_BoardInfos[dev->
+							minor].i_Count + ((i -
+								s_BoardInfos
+								[dev->minor].
+								i_FirstChannel)
+							* 3) + 1],
+					&s_BoardInfos[dev->minor].
+					ui_ScanValueArray[s_BoardInfos[dev->
+							minor].i_Count + ((i -
+								s_BoardInfos
+								[dev->minor].
+								i_FirstChannel)
+							* 3) + 2]);
+			}
+
+			//End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+			//i_Count=-1;
+
+			s_BoardInfos[dev->minor].i_Count = -1;
+
+			//async->buf_int_count+=(i_LastChannel-i_FirstChannel+4)*sizeof(UINT);
+			//Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+			//async->buf_int_count+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(UINT);
+			//End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+			//async->buf_int_ptr+=(i_LastChannel-i_FirstChannel+4)*sizeof(UINT);
+			//Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+			//async->buf_int_ptr+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(UINT);
+			//comedi_eos(dev,s);
+
+			// Set the event type (Comedi Buffer End Of Scan)
+			s->async->events |= COMEDI_CB_EOS;
+
+			// Test if enougth memory is available and allocate it for 7 values
+			//n = comedi_buf_write_alloc(s->async, 7*sizeof(unsigned int));
+			n = comedi_buf_write_alloc(s->async,
+				(7 + 12) * sizeof(unsigned int));
+
+			// If not enougth memory available, event is set to Comedi Buffer Errror
+			if (n > ((7 + 12) * sizeof(unsigned int))) {
+				printk("\ncomedi_buf_write_alloc n = %i", n);
+				s->async->events |= COMEDI_CB_ERROR;
+			}
+			// Write all 7 scan values in the comedi buffer
+			comedi_buf_memcpy_to(s->async, 0,
+				(unsigned int *) s_BoardInfos[dev->minor].
+				ui_ScanValueArray, (7 + 12) * sizeof(unsigned int));
+
+			// Update comedi buffer pinters indexes
+			comedi_buf_write_free(s->async,
+				(7 + 12) * sizeof(unsigned int));
+
+			// Send events
+			comedi_event(dev, s);
+			//End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+
+			//BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+			//
+			//if (s->async->buf_int_ptr>=s->async->data_len) //  for buffer rool over
+			//  {
+			//    /* buffer rollover */
+			//    s->async->buf_int_ptr=0;
+			//    comedi_eobuf(dev,s);
+			//  }
+			//End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+		}
+		//i_Count++;
+		s_BoardInfos[dev->minor].i_Count++;
+	}
+	//i_InterruptFlag=0;
+	s_BoardInfos[dev->minor].i_InterruptFlag = 0;
+	return 0;
+}

+ 187 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h

@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+// Card Specific information
+#define APCI3200_BOARD_VENDOR_ID                 0x15B8
+//#define APCI3200_ADDRESS_RANGE                   264
+
+int MODULE_NO;
+struct {
+	INT i_Gain;
+	INT i_Polarity;
+	INT i_OffsetRange;
+	INT i_Coupling;
+	INT i_SingleDiff;
+	INT i_AutoCalibration;
+	UINT ui_ReloadValue;
+	UINT ui_TimeUnitReloadVal;
+	INT i_Interrupt;
+	INT i_ModuleSelection;
+} Config_Parameters_Module1, Config_Parameters_Module2,
+    Config_Parameters_Module3, Config_Parameters_Module4;
+
+//ANALOG INPUT RANGE
+static const struct comedi_lrange range_apci3200_ai = { 8, {
+						     BIP_RANGE(10),
+						     BIP_RANGE(5),
+						     BIP_RANGE(2),
+						     BIP_RANGE(1),
+						     UNI_RANGE(10),
+						     UNI_RANGE(5),
+						     UNI_RANGE(2),
+						     UNI_RANGE(1)
+						     }
+};
+
+static const struct comedi_lrange range_apci3300_ai = { 4, {
+						     UNI_RANGE(10),
+						     UNI_RANGE(5),
+						     UNI_RANGE(2),
+						     UNI_RANGE(1)
+						     }
+};
+
+//Analog Input related Defines
+#define APCI3200_AI_OFFSET_GAIN                  0
+#define APCI3200_AI_SC_TEST                      4
+#define APCI3200_AI_IRQ                          8
+#define APCI3200_AI_AUTOCAL                      12
+#define APCI3200_RELOAD_CONV_TIME_VAL            32
+#define APCI3200_CONV_TIME_TIME_BASE             36
+#define APCI3200_RELOAD_DELAY_TIME_VAL           40
+#define APCI3200_DELAY_TIME_TIME_BASE            44
+#define APCI3200_AI_MODULE1                      0
+#define APCI3200_AI_MODULE2                      64
+#define APCI3200_AI_MODULE3                      128
+#define APCI3200_AI_MODULE4                      192
+#define TRUE                                     1
+#define FALSE                                    0
+#define APCI3200_AI_EOSIRQ                       16
+#define APCI3200_AI_EOS                          20
+#define APCI3200_AI_CHAN_ID                      24
+#define APCI3200_AI_CHAN_VAL                     28
+#define ANALOG_INPUT                             0
+#define TEMPERATURE                              1
+#define RESISTANCE                               2
+
+#define ENABLE_EXT_TRIG                          1
+#define ENABLE_EXT_GATE                          2
+#define ENABLE_EXT_TRIG_GATE                     3
+
+#define APCI3200_MAXVOLT                         2.5
+#define ADDIDATA_GREATER_THAN_TEST               0
+#define ADDIDATA_LESS_THAN_TEST                  1
+
+#define ADDIDATA_UNIPOLAR                        1
+#define ADDIDATA_BIPOLAR                         2
+
+//BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+#define MAX_MODULE				4
+//END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+typedef struct {
+	ULONG ul_NumberOfValue;
+	ULONG *pul_ResistanceValue;
+	ULONG *pul_TemperatureValue;
+} str_ADDIDATA_RTDStruct, *pstr_ADDIDATA_RTDStruct;
+
+//BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+typedef struct {
+	// Begin JK 05/08/2003 change for Linux
+	unsigned long ul_CurrentSourceCJC;
+	unsigned long ul_CurrentSource[5];
+	// End JK 05/08/2003 change for Linux
+
+	// Begin CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1
+	unsigned long ul_GainFactor[8];	// Gain Factor
+	unsigned int w_GainValue[10];
+	// End CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1
+} str_Module;
+//END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+
+//BEGIN JK 06.07.04: Management of sevrals boards
+typedef struct {
+	INT i_CJCAvailable;
+	INT i_CJCPolarity;
+	INT i_CJCGain;
+	INT i_InterruptFlag;
+	INT i_ADDIDATAPolarity;
+	INT i_ADDIDATAGain;
+	INT i_AutoCalibration;
+	INT i_ADDIDATAConversionTime;
+	INT i_ADDIDATAConversionTimeUnit;
+	INT i_ADDIDATAType;
+	INT i_ChannelNo;
+	INT i_ChannelCount;
+	INT i_ScanType;
+	INT i_FirstChannel;
+	INT i_LastChannel;
+	INT i_Sum;
+	INT i_Offset;
+	UINT ui_Channel_num;
+	INT i_Count;
+	INT i_Initialised;
+	//UINT ui_InterruptChannelValue[96]; //Buffer
+	UINT ui_InterruptChannelValue[144];	//Buffer
+	BYTE b_StructInitialized;
+	//Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+	unsigned int ui_ScanValueArray[7 + 12];	// 7 is the maximal number of channels
+	//End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68
+
+	//Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+	INT i_ConnectionType;
+	INT i_NbrOfModule;
+	str_Module s_Module[MAX_MODULE];
+	//End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values
+} str_BoardInfos;
+//END JK 06.07.04: Management of sevrals boards
+
+// Hardware Layer  functions for Apci3200
+
+//AI
+
+INT i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3200_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+			       struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev,
+					   struct comedi_subdevice *s,
+					   struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev,
+					 struct comedi_subdevice *s,
+					 struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s);
+INT i_APCI3200_InterruptHandleEos(struct comedi_device *dev);
+INT i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				      struct comedi_cmd *cmd);
+INT i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s);
+INT i_APCI3200_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int *data);
+//Interrupt
+void v_APCI3200_Interrupt(int irq, void *d);
+int i_APCI3200_InterruptHandleEos(struct comedi_device *dev);
+//Reset functions
+INT i_APCI3200_Reset(struct comedi_device *dev);
+
+int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, unsigned int *data);
+int i_APCI3200_ReadCJCValue(struct comedi_device *dev, unsigned int *data);
+int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, UINT *data);
+int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, UINT *data);
+int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev,
+				       struct comedi_subdevice *s, struct comedi_insn *insn,
+				       unsigned int *data);
+int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, unsigned int *data);

+ 742 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c

@@ -0,0 +1,742 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*.
+
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-------------------------------+---------------------------------------+
+  | Project     : APCI-3501       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci3501.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
+  +-------------------------------+---------------------------------------+
+  | Description :   Hardware Layer Acces For APCI-3501                    |
+  +-----------------------------------------------------------------------+
+  |                             UPDATES                                   |
+  +----------+-----------+------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          |           |                                                |
+  |          |           |                                                |
+  |          |           |                                                |
+  +----------+-----------+------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+|                               Included files                               |
++----------------------------------------------------------------------------+
+*/
+#include "hwdrv_apci3501.h"
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_ReadDigitalInput                    |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To read       |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+INT i_APCI3501_ReadDigitalInput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp;
+	UINT ui_NoOfChannel;
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	ui_Temp = data[0];
+	*data = inl(devpriv->iobase + APCI3501_DIGITAL_IP);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			//if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+
+			*data = *data & 0x3;
+		}		//if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		//elseif  (ui_Temp==1)
+	}			//elseif  (ui_Temp==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_ConfigDigitalOutput                     |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Digital Output Subdevice.               |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[1]            : 1 Enable  VCC  Interrupt  |
+|										   0 Disable VCC  Interrupt  |
+|					  data[2]            : 1 Enable  CC  Interrupt   |
+|										   0 Disable CC  Interrupt   |
+|																	 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3501_ConfigDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+
+	if ((data[0] != 0) && (data[0] != 1)) {
+		comedi_error(dev,
+			"Not a valid Data !!! ,Data should be 1 or 0\n");
+		return -EINVAL;
+	}			//if  ( (data[0]!=0) && (data[0]!=1) )
+	if (data[0]) {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
+	}			// if  (data[0])
+	else {
+		devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
+	}			//else if  (data[0])
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_WriteDigitalOutput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : writes To the digital Output Subdevice                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s     : Subdevice Pointer            |
+|                     struct comedi_insn *insn       : Insn Structure Pointer       |
+|                     unsigned int *data          : Data Pointer contains        |
+|                                          configuration parameters as below |
+|                                                                            |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI3501_WriteDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp, ui_Temp1;
+	UINT ui_NoOfChannel = CR_CHAN(insn->chanspec);	// get the channel
+	if (devpriv->b_OutputMemoryStatus) {
+		ui_Temp = inl(devpriv->iobase + APCI3501_DIGITAL_OP);
+	}			//if(devpriv->b_OutputMemoryStatus )
+	else {
+		ui_Temp = 0;
+	}			//if(devpriv->b_OutputMemoryStatus )
+	if (data[3] == 0) {
+		if (data[1] == 0) {
+			data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
+			outl(data[0], devpriv->iobase + APCI3501_DIGITAL_OP);
+		}		//if(data[1]==0)
+		else {
+			if (data[1] == 1) {
+				data[0] = (data[0] << (2 * data[2])) | ui_Temp;
+				outl(data[0],
+					devpriv->iobase + APCI3501_DIGITAL_OP);
+			}	// if(data[1]==1)
+			else {
+				printk("\nSpecified channel not supported\n");
+			}	//else if(data[1]==1)
+		}		//elseif(data[1]==0)
+	}			//if(data[3]==0)
+	else {
+		if (data[3] == 1) {
+			if (data[1] == 0) {
+				data[0] = ~data[0] & 0x1;
+				ui_Temp1 = 1;
+				ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
+				ui_Temp = ui_Temp | ui_Temp1;
+				data[0] =
+					(data[0] << ui_NoOfChannel) ^
+					0xffffffff;
+				data[0] = data[0] & ui_Temp;
+				outl(data[0],
+					devpriv->iobase + APCI3501_DIGITAL_OP);
+			}	//if(data[1]==0)
+			else {
+				if (data[1] == 1) {
+					data[0] = ~data[0] & 0x3;
+					ui_Temp1 = 3;
+					ui_Temp1 = ui_Temp1 << 2 * data[2];
+					ui_Temp = ui_Temp | ui_Temp1;
+					data[0] =
+						((data[0] << (2 *
+								data[2])) ^
+						0xffffffff) & ui_Temp;
+					outl(data[0],
+						devpriv->iobase +
+						APCI3501_DIGITAL_OP);
+				}	// if(data[1]==1)
+				else {
+					printk("\nSpecified channel not supported\n");
+				}	//else if(data[1]==1)
+			}	//elseif(data[1]==0)
+		}		//if(data[3]==1);
+		else {
+			printk("\nSpecified functionality does not exist\n");
+			return -EINVAL;
+		}		//if else data[3]==1)
+	}			//if else data[3]==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_ReadDigitalOutput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read  value  of the selected channel or port           |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     UINT ui_NoOfChannels    : No Of Channels To read       |
+|                     UINT *data              : Data Pointer to read status  |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI3501_ReadDigitalOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	UINT ui_Temp;
+	UINT ui_NoOfChannel;
+
+	ui_NoOfChannel = CR_CHAN(insn->chanspec);
+	ui_Temp = data[0];
+	*data = inl(devpriv->iobase + APCI3501_DIGITAL_OP);
+	if (ui_Temp == 0) {
+		*data = (*data >> ui_NoOfChannel) & 0x1;
+	}			// if  (ui_Temp==0)
+	else {
+		if (ui_Temp == 1) {
+			*data = *data & 0x3;
+
+		}		// if  (ui_Temp==1)
+		else {
+			printk("\nSpecified channel not supported \n");
+		}		// else if (ui_Temp==1)
+	}			// else if  (ui_Temp==0)
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_ConfigAnalogOutput                      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Analog Output Subdevice                 |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s     : Subdevice Pointer            |
+|                     struct comedi_insn *insn       : Insn Structure Pointer       |
+|                     unsigned int *data          : Data Pointer contains        |
+|                                          configuration parameters as below |
+|                                                                            |
+|					data[0]            : Voltage Mode                |
+|                                                0:Mode 0                    |
+|                                                1:Mode 1                    |
+|                                                                            |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI3501_ConfigAnalogOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	outl(data[0],
+		devpriv->iobase + APCI3501_ANALOG_OUTPUT +
+		APCI3501_AO_VOLT_MODE);
+
+	if (data[0]) {
+		devpriv->b_InterruptMode = MODE1;
+	} else {
+		devpriv->b_InterruptMode = MODE0;
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_WriteAnalogOutput                       |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Writes To the Selected Anlog Output Channel            |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev      : Driver handle                |
+|                     struct comedi_subdevice *s     : Subdevice Pointer            |
+|                     struct comedi_insn *insn       : Insn Structure Pointer       |
+|                     unsigned int *data          : Data Pointer contains        |
+|                                          configuration parameters as below |
+|                                                                            |
+|                                                                            |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI3501_WriteAnalogOutput(struct comedi_device * dev, struct comedi_subdevice * s,
+	struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0;;
+
+	ul_Channel_no = CR_CHAN(insn->chanspec);
+
+	if (devpriv->b_InterruptMode == MODE1) {
+		ul_Polarity = 0x80000000;
+		if ((*data < 0) || (*data > 16384)) {
+			printk("\nIn WriteAnalogOutput :: Not Valid Data\n");
+		}
+
+	}			// end if(devpriv->b_InterruptMode==MODE1)
+	else {
+		ul_Polarity = 0;
+		if ((*data < 0) || (*data > 8192)) {
+			printk("\nIn WriteAnalogOutput :: Not Valid Data\n");
+		}
+
+	}			// end else
+
+	if ((ul_Channel_no < 0) || (ul_Channel_no > 7)) {
+		printk("\nIn WriteAnalogOutput :: Not Valid Channel\n");
+	}			// end if((ul_Channel_no<0)||(ul_Channel_no>7))
+
+	ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT);
+
+	while (ul_DAC_Ready == 0) {
+		ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT);
+		ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1;
+	}
+
+	if (ul_DAC_Ready) {
+// Output the Value on the output channels.
+		ul_Command1 =
+			(ULONG) ((ULONG) (ul_Channel_no & 0xFF) |
+			(ULONG) ((*data << 0x8) & 0x7FFFFF00L) |
+			(ULONG) (ul_Polarity));
+		outl(ul_Command1,
+			devpriv->iobase + APCI3501_ANALOG_OUTPUT +
+			APCI3501_AO_PROG);
+	}
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_ConfigTimerCounterWatchdog              |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Configures The Timer , Counter or Watchdog             |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[0]            : 0 Configure As Timer      |
+|										   1 Configure As Counter    |
+|										   2 Configure As Watchdog   |
+|					  data[1]            : 1 Enable  Interrupt       |
+|										   0 Disable Interrupt 	     |
+|					  data[2]            : Time Unit                 |
+|					  data[3]			 : Reload Value			     |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+INT i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command1 = 0;
+	devpriv->tsk_Current = current;
+	if (data[0] == ADDIDATA_WATCHDOG) {
+
+		devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG;
+		//Disable the watchdog
+		outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);	//disable Wa
+
+		if (data[1] == 1) {
+			//Enable TIMER int & DISABLE ALL THE OTHER int SOURCES
+			outl(0x02,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		} else {
+			outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);	//disable Timer interrupt
+		}
+
+		//Loading the Timebase value
+		outl(data[2],
+			devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_TIMEBASE);
+
+		//Loading the Reload value
+		outl(data[3],
+			devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_RELOAD_VALUE);
+		//Set the mode
+		ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG) | 0xFFF819E0UL;	//e2->e0
+		outl(ul_Command1,
+			devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_PROG);
+	}			//end if(data[0]==ADDIDATA_WATCHDOG)
+
+	else if (data[0] == ADDIDATA_TIMER) {
+		//First Stop The Timer
+		ul_Command1 =
+			inl(devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_PROG);
+		ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
+		outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);	//Stop The Timer
+		devpriv->b_TimerSelectMode = ADDIDATA_TIMER;
+		if (data[1] == 1) {
+			//Enable TIMER int & DISABLE ALL THE OTHER int SOURCES
+			outl(0x02,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		} else {
+			outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);	//disable Timer interrupt
+		}
+
+		// Loading Timebase
+		outl(data[2],
+			devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_TIMEBASE);
+
+		//Loading the Reload value
+		outl(data[3],
+			devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_RELOAD_VALUE);
+
+		// printk ("\nTimer Address :: %x\n", (devpriv->iobase+APCI3501_WATCHDOG));
+		ul_Command1 =
+			inl(devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_PROG);
+		ul_Command1 =
+			(ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL;
+		outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);	//mode 2
+
+	}			//end if(data[0]==ADDIDATA_TIMER)
+
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_StartStopWriteTimerCounterWatchdog      |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Start / Stop The Selected Timer , Counter or Watchdog  |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[0]            : 0 Timer                   |
+|										   1 Counter                 |
+|										   2 Watchdog          		 |                             |            				 data[1]            : 1 Start                   |
+|										   0 Stop      				 |									                                              2 Trigger                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	ULONG ul_Command1 = 0;
+	int i_Temp;
+	if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+
+		if (data[1] == 1) {
+			ul_Command1 =
+				inl(devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
+			//Enable the Watchdog
+			outl(ul_Command1,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		}
+
+		else if (data[1] == 0)	//Stop The Watchdog
+		{
+			//Stop The Watchdog
+			ul_Command1 =
+				inl(devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+			ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
+			outl(0x0,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		} else if (data[1] == 2) {
+			ul_Command1 =
+				inl(devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x200UL;
+			outl(ul_Command1,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		}		//if(data[1]==2)
+	}			// end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG)
+
+	if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+		if (data[1] == 1) {
+
+			ul_Command1 =
+				inl(devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL;
+			//Enable the Timer
+			outl(ul_Command1,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		} else if (data[1] == 0) {
+			//Stop The Timer
+			ul_Command1 =
+				inl(devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+			ul_Command1 = ul_Command1 & 0xFFFFF9FEUL;
+			outl(ul_Command1,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		}
+
+		else if (data[1] == 2) {
+			//Trigger the Timer
+			ul_Command1 =
+				inl(devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+			ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x200UL;
+			outl(ul_Command1,
+				devpriv->iobase + APCI3501_WATCHDOG +
+				APCI3501_TCW_PROG);
+		}
+
+	}			// end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER)
+	i_Temp = inl(devpriv->iobase + APCI3501_WATCHDOG +
+		APCI3501_TCW_TRIG_STATUS) & 0x1;
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3501_ReadTimerCounterWatchdog                |
+|			  (struct comedi_device *dev,struct comedi_subdevice *s,               |
+|                      struct comedi_insn *insn,unsigned int *data)                     |
++----------------------------------------------------------------------------+
+| Task              : Read The Selected Timer , Counter or Watchdog          |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev : Driver handle                     |
+|                     UINT *data         : Data Pointer contains             |
+|                                          configuration parameters as below |
+|                                                                            |
+|					  data[0]            : 0 Timer                   |
+|										   1 Counter                 |
+|										   2 Watchdog                |                             |					  data[1]             : Timer Counter Watchdog Number   |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+
+	if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
+		data[0] =
+			inl(devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_TRIG_STATUS) & 0x1;
+		data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG);
+	}			// end if  (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG)
+
+	else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) {
+		data[0] =
+			inl(devpriv->iobase + APCI3501_WATCHDOG +
+			APCI3501_TCW_TRIG_STATUS) & 0x1;
+		data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG);
+	}			// end if  (devpriv->b_TimerSelectMode==ADDIDATA_TIMER)
+
+	else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER)
+		&& (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)) {
+		printk("\nIn ReadTimerCounterWatchdog :: Invalid Subdevice \n");
+	}
+	return insn->n;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   :  int i_APCI3501_Reset(struct comedi_device *dev)			     |
+|					                                                 |
++----------------------------------------------------------------------------+
+| Task              :Resets the registers of the card                        |
++----------------------------------------------------------------------------+
+| Input Parameters  :                                                        |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      :                                                        |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3501_Reset(struct comedi_device * dev)
+{
+	int i_Count = 0, i_temp = 0;
+	ULONG ul_Command1 = 0, ul_Polarity, ul_DAC_Ready = 0;
+	outl(0x0, devpriv->iobase + APCI3501_DIGITAL_OP);
+	outl(1, devpriv->iobase + APCI3501_ANALOG_OUTPUT +
+		APCI3501_AO_VOLT_MODE);
+
+	ul_Polarity = 0x80000000;
+
+	for (i_Count = 0; i_Count <= 7; i_Count++) {
+		ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT);
+
+		while (ul_DAC_Ready == 0) {
+			ul_DAC_Ready =
+				inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT);
+			ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1;
+		}
+
+		if (ul_DAC_Ready) {
+			// Output the Value on the output channels.
+			ul_Command1 =
+				(ULONG) ((ULONG) (i_Count & 0xFF) |
+				(ULONG) ((i_temp << 0x8) & 0x7FFFFF00L) |
+				(ULONG) (ul_Polarity));
+			outl(ul_Command1,
+				devpriv->iobase + APCI3501_ANALOG_OUTPUT +
+				APCI3501_AO_PROG);
+		}
+	}
+
+	return 0;
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : static void v_APCI3501_Interrupt					     |
+|					  (int irq , void *d)      |
++----------------------------------------------------------------------------+
+| Task              : Interrupt processing Routine                           |
++----------------------------------------------------------------------------+
+| Input Parameters  : int irq                 : irq number                   |
+|                     void *d                 : void pointer                 |
++----------------------------------------------------------------------------+
+| Output Parameters :	--													 |
++----------------------------------------------------------------------------+
+| Return Value      : TRUE  : No error occur                                 |
+|		            : FALSE : Error occur. Return the error          |
+|			                                                         |
++----------------------------------------------------------------------------+
+*/
+void v_APCI3501_Interrupt(int irq, void *d)
+{
+	int i_temp;
+	struct comedi_device *dev = d;
+	unsigned int ui_Timer_AOWatchdog;
+	unsigned long ul_Command1;
+	// Disable Interrupt
+	ul_Command1 =
+		inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
+
+	ul_Command1 = (ul_Command1 & 0xFFFFF9FDul);
+	outl(ul_Command1,
+		devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
+
+	ui_Timer_AOWatchdog =
+		inl(devpriv->iobase + APCI3501_WATCHDOG +
+		APCI3501_TCW_IRQ) & 0x1;
+
+	if ((!ui_Timer_AOWatchdog)) {
+		comedi_error(dev, "IRQ from unknow source");
+		return;
+	}
+
+	// Enable Interrupt
+	//Send a signal to from kernel to user space
+	send_sig(SIGIO, devpriv->tsk_Current, 0);
+	ul_Command1 =
+		inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
+	ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1);
+	outl(ul_Command1,
+		devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG);
+	i_temp = inl(devpriv->iobase + APCI3501_WATCHDOG +
+		APCI3501_TCW_TRIG_STATUS) & 0x1;
+	return;
+}

+ 94 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h

@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+// Card Specific information
+#define APCI3501_BOARD_VENDOR_ID                 0x15B8
+#define APCI3501_ADDRESS_RANGE                   255
+
+#define APCI3501_DIGITAL_IP                       0x50
+#define APCI3501_DIGITAL_OP                       0x40
+#define APCI3501_ANALOG_OUTPUT                    0x00
+
+//Analog Output related Defines
+#define APCI3501_AO_VOLT_MODE                     0
+#define APCI3501_AO_PROG                          4
+#define APCI3501_AO_TRIG_SCS                      8
+#define UNIPOLAR                                  0
+#define BIPOLAR                                   1
+#define MODE0                                     0
+#define MODE1                                     1
+// ANALOG OUTPUT RANGE
+struct comedi_lrange range_apci3501_ao = { 2, {
+					BIP_RANGE(10),
+					UNI_RANGE(10)
+					}
+};
+
+//Watchdog Related Defines
+
+#define APCI3501_WATCHDOG                         0x20
+#define APCI3501_TCW_SYNC_ENABLEDISABLE           0
+#define APCI3501_TCW_RELOAD_VALUE                 4
+#define APCI3501_TCW_TIMEBASE                     8
+#define APCI3501_TCW_PROG                         12
+#define APCI3501_TCW_TRIG_STATUS                  16
+#define APCI3501_TCW_IRQ                          20
+#define APCI3501_TCW_WARN_TIMEVAL                 24
+#define APCI3501_TCW_WARN_TIMEBASE                28
+#define ADDIDATA_TIMER                            0
+#define ADDIDATA_WATCHDOG                         2
+
+// Hardware Layer  functions for Apci3501
+
+//AO
+INT i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+//DI
+// for di read
+//INT i_APCI3501_ReadDigitalInput(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data);
+
+INT i_APCI3501_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s,
+				struct comedi_insn *insn, unsigned int *data);
+
+//DO
+int i_APCI3501_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				   struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3501_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				  struct comedi_insn *insn, unsigned int *data);
+INT i_APCI3501_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
+				 struct comedi_insn *insn, unsigned int *data);
+
+// TIMER
+// timer value is passed as u seconds
+INT i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev,
+					  struct comedi_subdevice *s,
+					  struct comedi_insn *insn, unsigned int *data);
+int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev,
+						  struct comedi_subdevice *s,
+						  struct comedi_insn *insn,
+						  unsigned int *data);
+int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev,
+					struct comedi_subdevice *s,
+					struct comedi_insn *insn, unsigned int *data);
+//Interrupt
+void v_APCI3501_Interrupt(int irq, void *d);
+
+//Reset functions
+int i_APCI3501_Reset(struct comedi_device *dev);

+ 1691 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c

@@ -0,0 +1,1691 @@
+/**
+@verbatim
+
+Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+
+        ADDI-DATA GmbH
+        Dieselstrasse 3
+        D-77833 Ottersweier
+        Tel: +19(0)7223/9493-0
+        Fax: +49(0)7223/9493-92
+        http://www.addi-data-com
+        info@addi-data.com
+
+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.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You shoud also find the complete GPL in the COPYING file accompanying this source code.
+
+@endverbatim
+*/
+/*
+  +-----------------------------------------------------------------------+
+  | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
+  +-----------------------------------------------------------------------+
+  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
+  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
+  +-----------------------------------------------------------------------+
+  | Project     : APCI-3XXX       | Compiler   : GCC                      |
+  | Module name : hwdrv_apci3xxx.c| Version    : 2.96                     |
+  +-------------------------------+---------------------------------------+
+  | Project manager: S. Weber     | Date       :  15/09/2005              |
+  +-----------------------------------------------------------------------+
+  | Description :APCI3XXX Module.  Hardware abstraction Layer for APCI3XXX|
+  +-----------------------------------------------------------------------+
+  |                             UPDATE'S                                  |
+  +-----------------------------------------------------------------------+
+  |   Date   |   Author  |          Description of updates                |
+  +----------+-----------+------------------------------------------------+
+  |          | 		 | 						  |
+  |          |           |						  |
+  +----------+-----------+------------------------------------------------+
+*/
+
+#include "hwdrv_apci3xxx.h"
+
+/*
++----------------------------------------------------------------------------+
+|                         ANALOG INPUT FUNCTIONS                             |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_TestConversionStarted                 |
+|                          (struct comedi_device    *dev)                           |
++----------------------------------------------------------------------------+
+| Task                Test if any conversion started                         |
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0 : Conversion not started                             |
+|                     1 : Conversion started                                 |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_TestConversionStarted(struct comedi_device * dev)
+{
+	if ((readl((void *)(devpriv->dw_AiBase + 8)) & 0x80000UL) == 0x80000UL) {
+		return (1);
+	} else {
+		return (0);
+	}
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_AnalogInputConfigOperatingMode        |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           Converting mode and convert time selection                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_SingleDiff  = (BYTE)  data[1];                       |
+|                     b_TimeBase    = (BYTE)  data[2]; (0: ns, 1:micros 2:ms)|
+|                    dw_ReloadValue = (DWORD) data[3];                       |
+|                     ........                                               |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0 : No error                                           |
+|                    -1 : Single/Diff selection error                        |
+|                    -2 : Convert time base unity selection error            |
+|                    -3 : Convert time value selection error                 |
+|                    -10: Any conversion started                             |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_TimeBase = 0;
+	BYTE b_SingleDiff = 0;
+	DWORD dw_ReloadValue = 0;
+	DWORD dw_TestReloadValue = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n == 4) {
+	   /****************************/
+		/* Get the Singel/Diff flag */
+	   /****************************/
+
+		b_SingleDiff = (BYTE) data[1];
+
+	   /****************************/
+		/* Get the time base unitiy */
+	   /****************************/
+
+		b_TimeBase = (BYTE) data[2];
+
+	   /*************************************/
+		/* Get the convert time reload value */
+	   /*************************************/
+
+		dw_ReloadValue = (DWORD) data[3];
+
+	   /**********************/
+		/* Test the time base */
+	   /**********************/
+
+		if ((devpriv->ps_BoardInfo->
+				b_AvailableConvertUnit & (1 << b_TimeBase)) !=
+			0) {
+	      /*******************************/
+			/* Test the convert time value */
+	      /*******************************/
+
+			if ((dw_ReloadValue >= 0) && (dw_ReloadValue <= 65535)) {
+				dw_TestReloadValue = dw_ReloadValue;
+
+				if (b_TimeBase == 1) {
+					dw_TestReloadValue =
+						dw_TestReloadValue * 1000UL;
+				}
+				if (b_TimeBase == 2) {
+					dw_TestReloadValue =
+						dw_TestReloadValue * 1000000UL;
+				}
+
+		 /*******************************/
+				/* Test the convert time value */
+		 /*******************************/
+
+				if (dw_TestReloadValue >=
+					devpriv->ps_BoardInfo->
+					ui_MinAcquisitiontimeNs) {
+					if ((b_SingleDiff == APCI3XXX_SINGLE)
+						|| (b_SingleDiff ==
+							APCI3XXX_DIFF)) {
+						if (((b_SingleDiff == APCI3XXX_SINGLE) && (devpriv->ps_BoardInfo->i_NbrAiChannel == 0)) || ((b_SingleDiff == APCI3XXX_DIFF) && (devpriv->ps_BoardInfo->i_NbrAiChannelDiff == 0))) {
+			   /*******************************/
+							/* Single/Diff selection error */
+			   /*******************************/
+
+							printk("Single/Diff selection error\n");
+							i_ReturnValue = -1;
+						} else {
+			   /**********************************/
+							/* Test if conversion not started */
+			   /**********************************/
+
+							if (i_APCI3XXX_TestConversionStarted(dev) == 0) {
+								devpriv->
+									ui_EocEosConversionTime
+									=
+									(UINT)
+									dw_ReloadValue;
+								devpriv->
+									b_EocEosConversionTimeBase
+									=
+									b_TimeBase;
+								devpriv->
+									b_SingelDiff
+									=
+									b_SingleDiff;
+								devpriv->
+									b_AiInitialisation
+									= 1;
+
+			      /*******************************/
+								/* Set the convert timing unit */
+			      /*******************************/
+
+								writel((DWORD)
+									b_TimeBase,
+									(void *)
+									(devpriv->
+										dw_AiBase
+										+
+										36));
+
+			      /**************************/
+								/* Set the convert timing */
+			      /*************************/
+
+								writel(dw_ReloadValue, (void *)(devpriv->dw_AiBase + 32));
+							} else {
+			      /**************************/
+								/* Any conversion started */
+			      /**************************/
+
+								printk("Any conversion started\n");
+								i_ReturnValue =
+									-10;
+							}
+						}
+					} else {
+		       /*******************************/
+						/* Single/Diff selection error */
+		       /*******************************/
+
+						printk("Single/Diff selection error\n");
+						i_ReturnValue = -1;
+					}
+				} else {
+		    /************************/
+					/* Time selection error */
+		    /************************/
+
+					printk("Convert time value selection error\n");
+					i_ReturnValue = -3;
+				}
+			} else {
+		 /************************/
+				/* Time selection error */
+		 /************************/
+
+				printk("Convert time value selection error\n");
+				i_ReturnValue = -3;
+			}
+		} else {
+	      /*****************************/
+			/* Time base selection error */
+	      /*****************************/
+
+			printk("Convert time base unity selection error\n");
+			i_ReturnValue = -2;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnConfigAnalogInput                 |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           Converting mode and convert time selection                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_ConvertMode = (BYTE)  data[0];                       |
+|                     b_TimeBase    = (BYTE)  data[1]; (0: ns, 1:micros 2:ms)|
+|                    dw_ReloadValue = (DWORD) data[2];                       |
+|                     ........                                               |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+		switch ((BYTE) data[0]) {
+		case APCI3XXX_CONFIGURATION:
+			i_ReturnValue =
+				i_APCI3XXX_AnalogInputConfigOperatingMode(dev,
+				s, insn, data);
+			break;
+
+		default:
+			i_ReturnValue = -100;
+			printk("Config command error %d\n", data[0]);
+			break;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnReadAnalogInput                   |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task                Read 1 analog input                                    |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Range             = CR_RANGE(insn->chanspec);        |
+|                     b_Channel           = CR_CHAN(insn->chanspec);         |
+|                     dw_NbrOfAcquisition = insn->n;                         |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -3 : Channel selection error                            |
+|                    -4 : Configuration selelection error                    |
+|                    -10: Any conversion started                             |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Configuration = (BYTE) CR_RANGE(insn->chanspec);
+	BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+	DWORD dw_Temp = 0;
+	DWORD dw_Configuration = 0;
+	DWORD dw_AcquisitionCpt = 0;
+	BYTE b_Interrupt = 0;
+
+	/*************************************/
+	/* Test if operating mode configured */
+	/*************************************/
+
+	if (devpriv->b_AiInitialisation) {
+	   /***************************/
+		/* Test the channel number */
+	   /***************************/
+
+		if (((b_Channel < devpriv->ps_BoardInfo->i_NbrAiChannel)
+				&& (devpriv->b_SingelDiff == APCI3XXX_SINGLE))
+			|| ((b_Channel < devpriv->ps_BoardInfo->
+					i_NbrAiChannelDiff)
+				&& (devpriv->b_SingelDiff == APCI3XXX_DIFF))) {
+	      /**********************************/
+			/* Test the channel configuration */
+	      /**********************************/
+
+			if (b_Configuration > 7) {
+		 /***************************/
+				/* Channel not initialised */
+		 /***************************/
+
+				i_ReturnValue = -4;
+				printk("Channel %d range %d selection error\n",
+					b_Channel, b_Configuration);
+			}
+		} else {
+	      /***************************/
+			/* Channel selection error */
+	      /***************************/
+
+			i_ReturnValue = -3;
+			printk("Channel %d selection error\n", b_Channel);
+		}
+
+	   /**************************/
+		/* Test if no error occur */
+	   /**************************/
+
+		if (i_ReturnValue >= 0) {
+	      /************************/
+			/* Test the buffer size */
+	      /************************/
+
+			if ((b_Interrupt != 0) || ((b_Interrupt == 0)
+					&& (insn->n >= 1))) {
+		 /**********************************/
+				/* Test if conversion not started */
+		 /**********************************/
+
+				if (i_APCI3XXX_TestConversionStarted(dev) == 0) {
+		    /******************/
+					/* Clear the FIFO */
+		    /******************/
+
+					writel(0x10000UL,
+						(void *)(devpriv->dw_AiBase +
+							12));
+
+		    /*******************************/
+					/* Get and save the delay mode */
+		    /*******************************/
+
+					dw_Temp =
+						readl((void *)(devpriv->
+							dw_AiBase + 4));
+					dw_Temp = dw_Temp & 0xFFFFFEF0UL;
+
+		    /***********************************/
+					/* Channel configuration selection */
+		    /***********************************/
+
+					writel(dw_Temp,
+						(void *)(devpriv->dw_AiBase +
+							4));
+
+		    /**************************/
+					/* Make the configuration */
+		    /**************************/
+
+					dw_Configuration =
+						(b_Configuration & 3) |
+						((DWORD) (b_Configuration >> 2)
+						<< 6) | ((DWORD) devpriv->
+						b_SingelDiff << 7);
+
+		    /***************************/
+					/* Write the configuration */
+		    /***************************/
+
+					writel(dw_Configuration,
+						(void *)(devpriv->dw_AiBase +
+							0));
+
+		    /*********************/
+					/* Channel selection */
+		    /*********************/
+
+					writel(dw_Temp | 0x100UL,
+						(void *)(devpriv->dw_AiBase +
+							4));
+					writel((DWORD) b_Channel,
+						(void *)(devpriv->dw_AiBase +
+							0));
+
+		    /***********************/
+					/* Restaure delay mode */
+		    /***********************/
+
+					writel(dw_Temp,
+						(void *)(devpriv->dw_AiBase +
+							4));
+
+		    /***********************************/
+					/* Set the number of sequence to 1 */
+		    /***********************************/
+
+					writel(1,
+						(void *)(devpriv->dw_AiBase +
+							48));
+
+		    /***************************/
+					/* Save the interrupt flag */
+		    /***************************/
+
+					devpriv->b_EocEosInterrupt =
+						b_Interrupt;
+
+		    /*******************************/
+					/* Save the number of channels */
+		    /*******************************/
+
+					devpriv->ui_AiNbrofChannels = 1;
+
+		    /******************************/
+					/* Test if interrupt not used */
+		    /******************************/
+
+					if (b_Interrupt == 0) {
+						for (dw_AcquisitionCpt = 0;
+							dw_AcquisitionCpt <
+							insn->n;
+							dw_AcquisitionCpt++) {
+			  /************************/
+							/* Start the conversion */
+			  /************************/
+
+							writel(0x80000UL,
+								(void *)
+								(devpriv->
+									dw_AiBase
+									+ 8));
+
+			  /****************/
+							/* Wait the EOS */
+			  /****************/
+
+							do {
+								dw_Temp =
+									readl(
+									(void *)
+									(devpriv->
+										dw_AiBase
+										+
+										20));
+								dw_Temp =
+									dw_Temp
+									& 1;
+							}
+							while (dw_Temp != 1);
+
+			  /*************************/
+							/* Read the analog value */
+			  /*************************/
+
+							data[dw_AcquisitionCpt]
+								=
+								(unsigned int)
+								readl((void
+									*)
+								(devpriv->
+									dw_AiBase
+									+ 28));
+						}
+					} else {
+		       /************************/
+						/* Start the conversion */
+		       /************************/
+
+						writel(0x180000UL,
+							(void *)(devpriv->
+								dw_AiBase + 8));
+					}
+				} else {
+		    /**************************/
+					/* Any conversion started */
+		    /**************************/
+
+					printk("Any conversion started\n");
+					i_ReturnValue = -10;
+				}
+			} else {
+		 /*******************/
+				/* Data size error */
+		 /*******************/
+
+				printk("Buffer size error\n");
+				i_ReturnValue = -101;
+			}
+		}
+	} else {
+	   /***************************/
+		/* Channel selection error */
+	   /***************************/
+
+		printk("Operating mode not configured\n");
+		i_ReturnValue = -1;
+	}
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     : void v_APCI3XXX_Interrupt (int            irq,         |
+|                                                void           *d)       |
++----------------------------------------------------------------------------+
+| Task              :Interrupt handler for APCI3XXX                          |
+|                    When interrupt occurs this gets called.                 |
+|                    First it finds which interrupt has been generated and   |
+|                    handles  corresponding interrupt                        |
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : -                                                      |
++----------------------------------------------------------------------------+
+*/
+
+void v_APCI3XXX_Interrupt(int irq, void *d)
+{
+	struct comedi_device *dev = d;
+	BYTE b_CopyCpt = 0;
+	DWORD dw_Status = 0;
+
+	/***************************/
+	/* Test if interrupt occur */
+	/***************************/
+
+	if (((dw_Status = readl((void *)(devpriv->dw_AiBase + 16))) & 0x2UL) ==
+		0x2UL) {
+	   /***********************/
+		/* Reset the interrupt */
+	   /***********************/
+
+		writel(dw_Status, (void *)(devpriv->dw_AiBase + 16));
+
+	   /*****************************/
+		/* Test if interrupt enabled */
+	   /*****************************/
+
+		if (devpriv->b_EocEosInterrupt == 1) {
+	      /********************************/
+			/* Read all analog inputs value */
+	      /********************************/
+
+			for (b_CopyCpt = 0;
+				b_CopyCpt < devpriv->ui_AiNbrofChannels;
+				b_CopyCpt++) {
+				devpriv->ui_AiReadData[b_CopyCpt] =
+					(UINT) readl((void *)(devpriv->
+						dw_AiBase + 28));
+			}
+
+	      /**************************/
+			/* Set the interrupt flag */
+	      /**************************/
+
+			devpriv->b_EocEosInterrupt = 2;
+
+	      /**********************************************/
+			/* Send a signal to from kernel to user space */
+	      /**********************************************/
+
+			send_sig(SIGIO, devpriv->tsk_Current, 0);
+		}
+	}
+}
+
+/*
++----------------------------------------------------------------------------+
+|                            ANALOG OUTPUT SUBDEVICE                         |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnWriteAnalogOutput                 |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task                Read 1 analog input                                    |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Range    = CR_RANGE(insn->chanspec);                 |
+|                     b_Channel  = CR_CHAN(insn->chanspec);                  |
+|                     data[0]    = analog value;                             |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -3 : Channel selection error                            |
+|                    -4 : Configuration selelection error                    |
+|                    ....                                                    |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_Range = (BYTE) CR_RANGE(insn->chanspec);
+	BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+	DWORD dw_Status = 0;
+	INT i_ReturnValue = insn->n;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /***************************/
+		/* Test the channel number */
+	   /***************************/
+
+		if (b_Channel < devpriv->ps_BoardInfo->i_NbrAoChannel) {
+	      /**********************************/
+			/* Test the channel configuration */
+	      /**********************************/
+
+			if (b_Range < 2) {
+		 /***************************/
+				/* Set the range selection */
+		 /***************************/
+
+				writel(b_Range,
+					(void *)(devpriv->dw_AiBase + 96));
+
+		 /**************************************************/
+				/* Write the analog value to the selected channel */
+		 /**************************************************/
+
+				writel((data[0] << 8) | b_Channel,
+					(void *)(devpriv->dw_AiBase + 100));
+
+		 /****************************/
+				/* Wait the end of transfer */
+		 /****************************/
+
+				do {
+					dw_Status =
+						readl((void *)(devpriv->
+							dw_AiBase + 96));
+				}
+				while ((dw_Status & 0x100) != 0x100);
+			} else {
+		 /***************************/
+				/* Channel not initialised */
+		 /***************************/
+
+				i_ReturnValue = -4;
+				printk("Channel %d range %d selection error\n",
+					b_Channel, b_Range);
+			}
+		} else {
+	      /***************************/
+			/* Channel selection error */
+	      /***************************/
+
+			i_ReturnValue = -3;
+			printk("Channel %d selection error\n", b_Channel);
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                              TTL FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT   i_APCI3XXX_InsnConfigInitTTLIO                   |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task           You must calling this function be                           |
+|                for you call any other function witch access of TTL.        |
+|                APCI3XXX_TTL_INIT_DIRECTION_PORT2(user inputs for direction)|
++----------------------------------------------------------------------------+
+| Input Parameters  : b_InitType    = (BYTE) data[0];                        |
+|                     b_Port2Mode   = (BYTE) data[1];                        |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    -1: Port 2 mode selection is wrong                      |
+|                    ....                                                    |
+|                    -100 : Config command error                             |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Command = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /*******************/
+		/* Get the command */
+		/* **************** */
+
+		b_Command = (BYTE) data[0];
+
+	   /********************/
+		/* Test the command */
+	   /********************/
+
+		if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) {
+	      /***************************************/
+			/* Test the initialisation buffer size */
+	      /***************************************/
+
+			if ((b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)
+				&& (insn->n != 2)) {
+		 /*******************/
+				/* Data size error */
+		 /*******************/
+
+				printk("Buffer size error\n");
+				i_ReturnValue = -101;
+			}
+		} else {
+	      /************************/
+			/* Config command error */
+	      /************************/
+
+			printk("Command selection error\n");
+			i_ReturnValue = -100;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	/*********************************************************************************/
+	/* Test if no error occur and APCI3XXX_TTL_INIT_DIRECTION_PORT2 command selected */
+	/*********************************************************************************/
+
+	if ((i_ReturnValue >= 0)
+		&& (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)) {
+	   /**********************/
+		/* Test the direction */
+	   /**********************/
+
+		if ((data[1] == 0) || (data[1] == 0xFF)) {
+	      /**************************/
+			/* Save the configuration */
+	      /**************************/
+
+			devpriv->ul_TTLPortConfiguration[0] =
+				devpriv->ul_TTLPortConfiguration[0] | data[1];
+		} else {
+	      /************************/
+			/* Port direction error */
+	      /************************/
+
+			printk("Port 2 direction selection error\n");
+			i_ReturnValue = -1;
+		}
+	}
+
+	/**************************/
+	/* Test if no error occur */
+	/**************************/
+
+	if (i_ReturnValue >= 0) {
+	   /***********************************/
+		/* Test if TTL port initilaisation */
+	   /***********************************/
+
+		if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) {
+	      /*************************/
+			/* Set the configuration */
+	      /*************************/
+
+			outl(data[1], devpriv->iobase + 224);
+		}
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                        TTL INPUT FUNCTIONS                                 |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT     i_APCI3XXX_InsnBitsTTLIO                       |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Write the selected output mask and read the status from|
+|                     all TTL channles                                       |
++----------------------------------------------------------------------------+
+| Input Parameters  : dw_ChannelMask = data [0];                             |
+|                     dw_BitMask     = data [1];                             |
++----------------------------------------------------------------------------+
+| Output Parameters : data[1] : All TTL channles states                      |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -4   : Channel mask error                               |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_ChannelCpt = 0;
+	DWORD dw_ChannelMask = 0;
+	DWORD dw_BitMask = 0;
+	DWORD dw_Status = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 2) {
+	   /*******************************/
+		/* Get the channe and bit mask */
+	   /*******************************/
+
+		dw_ChannelMask = data[0];
+		dw_BitMask = data[1];
+
+	   /*************************/
+		/* Test the channel mask */
+	   /*************************/
+
+		if (((dw_ChannelMask & 0XFF00FF00) == 0) &&
+			(((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0xFF)
+				|| (((devpriv->ul_TTLPortConfiguration[0] &
+							0xFF) == 0)
+					&& ((dw_ChannelMask & 0XFF0000) ==
+						0)))) {
+	      /*********************************/
+			/* Test if set/reset any channel */
+	      /*********************************/
+
+			if (dw_ChannelMask) {
+		 /****************************************/
+				/* Test if set/rest any port 0 channels */
+		 /****************************************/
+
+				if (dw_ChannelMask & 0xFF) {
+		    /*******************************************/
+					/* Read port 0 (first digital output port) */
+		    /*******************************************/
+
+					dw_Status = inl(devpriv->iobase + 80);
+
+					for (b_ChannelCpt = 0; b_ChannelCpt < 8;
+						b_ChannelCpt++) {
+						if ((dw_ChannelMask >>
+								b_ChannelCpt) &
+							1) {
+							dw_Status =
+								(dw_Status &
+								(0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
+						}
+					}
+
+					outl(dw_Status, devpriv->iobase + 80);
+				}
+
+		 /****************************************/
+				/* Test if set/rest any port 2 channels */
+		 /****************************************/
+
+				if (dw_ChannelMask & 0xFF0000) {
+					dw_BitMask = dw_BitMask >> 16;
+					dw_ChannelMask = dw_ChannelMask >> 16;
+
+		    /********************************************/
+					/* Read port 2 (second digital output port) */
+		    /********************************************/
+
+					dw_Status = inl(devpriv->iobase + 112);
+
+					for (b_ChannelCpt = 0; b_ChannelCpt < 8;
+						b_ChannelCpt++) {
+						if ((dw_ChannelMask >>
+								b_ChannelCpt) &
+							1) {
+							dw_Status =
+								(dw_Status &
+								(0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
+						}
+					}
+
+					outl(dw_Status, devpriv->iobase + 112);
+				}
+			}
+
+	      /*******************************************/
+			/* Read port 0 (first digital output port) */
+	      /*******************************************/
+
+			data[1] = inl(devpriv->iobase + 80);
+
+	      /******************************************/
+			/* Read port 1 (first digital input port) */
+	      /******************************************/
+
+			data[1] = data[1] | (inl(devpriv->iobase + 64) << 8);
+
+	      /************************/
+			/* Test if port 2 input */
+	      /************************/
+
+			if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0) {
+				data[1] =
+					data[1] | (inl(devpriv->iobase +
+						96) << 16);
+			} else {
+				data[1] =
+					data[1] | (inl(devpriv->iobase +
+						112) << 16);
+			}
+		} else {
+	      /************************/
+			/* Config command error */
+	      /************************/
+
+			printk("Channel mask error\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT i_APCI3XXX_InsnReadTTLIO                           |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Read the status from selected channel                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Selected TTL channel state                   |
++----------------------------------------------------------------------------+
+| Return Value      : 0   : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+	INT i_ReturnValue = insn->n;
+	unsigned int *pls_ReadData = data;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /***********************/
+		/* Test if read port 0 */
+	   /***********************/
+
+		if (b_Channel < 8) {
+	      /*******************************************/
+			/* Read port 0 (first digital output port) */
+	      /*******************************************/
+
+			pls_ReadData[0] = inl(devpriv->iobase + 80);
+			pls_ReadData[0] = (pls_ReadData[0] >> b_Channel) & 1;
+		} else {
+	      /***********************/
+			/* Test if read port 1 */
+	      /***********************/
+
+			if ((b_Channel > 7) && (b_Channel < 16)) {
+		 /******************************************/
+				/* Read port 1 (first digital input port) */
+		 /******************************************/
+
+				pls_ReadData[0] = inl(devpriv->iobase + 64);
+				pls_ReadData[0] =
+					(pls_ReadData[0] >> (b_Channel -
+						8)) & 1;
+			} else {
+		 /***********************/
+				/* Test if read port 2 */
+		 /***********************/
+
+				if ((b_Channel > 15) && (b_Channel < 24)) {
+		    /************************/
+					/* Test if port 2 input */
+		    /************************/
+
+					if ((devpriv->ul_TTLPortConfiguration[0]
+							& 0xFF) == 0) {
+						pls_ReadData[0] =
+							inl(devpriv->iobase +
+							96);
+						pls_ReadData[0] =
+							(pls_ReadData[0] >>
+							(b_Channel - 16)) & 1;
+					} else {
+						pls_ReadData[0] =
+							inl(devpriv->iobase +
+							112);
+						pls_ReadData[0] =
+							(pls_ReadData[0] >>
+							(b_Channel - 16)) & 1;
+					}
+				} else {
+		    /***************************/
+					/* Channel selection error */
+		    /***************************/
+
+					i_ReturnValue = -3;
+					printk("Channel %d selection error\n",
+						b_Channel);
+				}
+			}
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                        TTL OUTPUT FUNCTIONS                                |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function Name     : INT     i_APCI3XXX_InsnWriteTTLIO                      |
+|                          (struct comedi_device    *dev,                           |
+|                           struct comedi_subdevice *s,                             |
+|                           struct comedi_insn      *insn,                          |
+|                           unsigned int         *data)                          |
++----------------------------------------------------------------------------+
+| Task              : Set the state from TTL output channel                  |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
+|                     b_State   = data [0]                                   |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : 0   : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+	BYTE b_State = 0;
+	DWORD dw_Status = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+		b_State = (BYTE) data[0];
+
+	   /***********************/
+		/* Test if read port 0 */
+	   /***********************/
+
+		if (b_Channel < 8) {
+	      /*****************************************************************************/
+			/* Read port 0 (first digital output port) and set/reset the selcted channel */
+	      /*****************************************************************************/
+
+			dw_Status = inl(devpriv->iobase + 80);
+			dw_Status =
+				(dw_Status & (0xFF -
+					(1 << b_Channel))) | ((b_State & 1) <<
+				b_Channel);
+			outl(dw_Status, devpriv->iobase + 80);
+		} else {
+	      /***********************/
+			/* Test if read port 2 */
+	      /***********************/
+
+			if ((b_Channel > 15) && (b_Channel < 24)) {
+		 /*************************/
+				/* Test if port 2 output */
+		 /*************************/
+
+				if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF)
+					== 0xFF) {
+		    /*****************************************************************************/
+					/* Read port 2 (first digital output port) and set/reset the selcted channel */
+		    /*****************************************************************************/
+
+					dw_Status = inl(devpriv->iobase + 112);
+					dw_Status =
+						(dw_Status & (0xFF -
+							(1 << (b_Channel -
+									16)))) |
+						((b_State & 1) << (b_Channel -
+							16));
+					outl(dw_Status, devpriv->iobase + 112);
+				} else {
+		    /***************************/
+					/* Channel selection error */
+		    /***************************/
+
+					i_ReturnValue = -3;
+					printk("Channel %d selection error\n",
+						b_Channel);
+				}
+			} else {
+		 /***************************/
+				/* Channel selection error */
+		 /***************************/
+
+				i_ReturnValue = -3;
+				printk("Channel %d selection error\n",
+					b_Channel);
+			}
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL INPUT SUBDEVICE                          |
++----------------------------------------------------------------------------+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnReadDigitalInput                     |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Reads the value of the specified Digital input channel |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec) (0 to 3)           |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Channel value                                |
++----------------------------------------------------------------------------+
+| Return Value      : 0   : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Channel = (BYTE) CR_CHAN(insn->chanspec);
+	DWORD dw_Temp = 0;
+
+	/***************************/
+	/* Test the channel number */
+	/***************************/
+
+	if (b_Channel <= devpriv->ps_BoardInfo->i_NbrDiChannel) {
+	   /************************/
+		/* Test the buffer size */
+	   /************************/
+
+		if (insn->n >= 1) {
+			dw_Temp = inl(devpriv->iobase + 32);
+			*data = (dw_Temp >> b_Channel) & 1;
+		} else {
+	      /*******************/
+			/* Data size error */
+	      /*******************/
+
+			printk("Buffer size error\n");
+			i_ReturnValue = -101;
+		}
+	} else {
+	   /***************************/
+		/* Channel selection error */
+	   /***************************/
+
+		printk("Channel selection error\n");
+		i_ReturnValue = -3;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnBitsDigitalInput                     |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Reads the value of the Digital input Port i.e.4channels|
++----------------------------------------------------------------------------+
+| Input Parameters  : -                                                      |
++----------------------------------------------------------------------------+
+| Output Parameters : data[0] : Port value                                   |
++----------------------------------------------------------------------------+
+| Return Value      :>0: No error                                            |
+|                    ....                                                    |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	DWORD dw_Temp = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+		dw_Temp = inl(devpriv->iobase + 32);
+		*data = dw_Temp & 0xf;
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+|                           DIGITAL OUTPUT SUBDEVICE                         |
++----------------------------------------------------------------------------+
+
+*/
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnBitsDigitalOutput                    |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Write the selected output mask and read the status from|
+|                     all digital output channles                            |
++----------------------------------------------------------------------------+
+| Input Parameters  : dw_ChannelMask = data [0];                             |
+|                     dw_BitMask     = data [1];                             |
++----------------------------------------------------------------------------+
+| Output Parameters : data[1] : All digital output channles states           |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -4   : Channel mask error                               |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_ChannelCpt = 0;
+	DWORD dw_ChannelMask = 0;
+	DWORD dw_BitMask = 0;
+	DWORD dw_Status = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 2) {
+	   /*******************************/
+		/* Get the channe and bit mask */
+	   /*******************************/
+
+		dw_ChannelMask = data[0];
+		dw_BitMask = data[1];
+
+	   /*************************/
+		/* Test the channel mask */
+	   /*************************/
+
+		if ((dw_ChannelMask & 0XFFFFFFF0) == 0) {
+	      /*********************************/
+			/* Test if set/reset any channel */
+	      /*********************************/
+
+			if (dw_ChannelMask & 0xF) {
+		 /********************************/
+				/* Read the digital output port */
+		 /********************************/
+
+				dw_Status = inl(devpriv->iobase + 48);
+
+				for (b_ChannelCpt = 0; b_ChannelCpt < 4;
+					b_ChannelCpt++) {
+					if ((dw_ChannelMask >> b_ChannelCpt) &
+						1) {
+						dw_Status =
+							(dw_Status & (0xF -
+								(1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt));
+					}
+				}
+
+				outl(dw_Status, devpriv->iobase + 48);
+			}
+
+	      /********************************/
+			/* Read the digital output port */
+	      /********************************/
+
+			data[1] = inl(devpriv->iobase + 48);
+		} else {
+	      /************************/
+			/* Config command error */
+	      /************************/
+
+			printk("Channel mask error\n");
+			i_ReturnValue = -4;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnWriteDigitalOutput                   |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Set the state from digital output channel              |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
+|                     b_State   = data [0]                                   |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Channel = CR_CHAN(insn->chanspec);
+	BYTE b_State = 0;
+	DWORD dw_Status = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /***************************/
+		/* Test the channel number */
+	   /***************************/
+
+		if (b_Channel < devpriv->ps_BoardInfo->i_NbrDoChannel) {
+	      /*******************/
+			/* Get the command */
+	      /*******************/
+
+			b_State = (BYTE) data[0];
+
+	      /********************************/
+			/* Read the digital output port */
+	      /********************************/
+
+			dw_Status = inl(devpriv->iobase + 48);
+
+			dw_Status =
+				(dw_Status & (0xF -
+					(1 << b_Channel))) | ((b_State & 1) <<
+				b_Channel);
+			outl(dw_Status, devpriv->iobase + 48);
+		} else {
+	      /***************************/
+			/* Channel selection error */
+	      /***************************/
+
+			printk("Channel selection error\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function name     :int i_APCI3XXX_InsnReadDigitalOutput                    |
+|                                          (struct comedi_device *dev,              |
+|                                           struct comedi_subdevice *s,             |
+|                                           struct comedi_insn *insn,               |
+|                                           unsigned int *data)                  |
++----------------------------------------------------------------------------+
+| Task              : Read the state from digital output channel             |
++----------------------------------------------------------------------------+
+| Input Parameters  : b_Channel = CR_CHAN(insn->chanspec)                    |
++----------------------------------------------------------------------------+
+| Output Parameters : b_State   = data [0]                                   |
++----------------------------------------------------------------------------+
+| Return Value      : >0  : No error                                         |
+|                    -3   : Channel selection error                          |
+|                    -101 : Data size error                                  |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device * dev,
+	struct comedi_subdevice * s, struct comedi_insn * insn, unsigned int * data)
+{
+	INT i_ReturnValue = insn->n;
+	BYTE b_Channel = CR_CHAN(insn->chanspec);
+	DWORD dw_Status = 0;
+
+	/************************/
+	/* Test the buffer size */
+	/************************/
+
+	if (insn->n >= 1) {
+	   /***************************/
+		/* Test the channel number */
+	   /***************************/
+
+		if (b_Channel < devpriv->ps_BoardInfo->i_NbrDoChannel) {
+	      /********************************/
+			/* Read the digital output port */
+	      /********************************/
+
+			dw_Status = inl(devpriv->iobase + 48);
+
+			dw_Status = (dw_Status >> b_Channel) & 1;
+			*data = dw_Status;
+		} else {
+	      /***************************/
+			/* Channel selection error */
+	      /***************************/
+
+			printk("Channel selection error\n");
+			i_ReturnValue = -3;
+		}
+	} else {
+	   /*******************/
+		/* Data size error */
+	   /*******************/
+
+		printk("Buffer size error\n");
+		i_ReturnValue = -101;
+	}
+
+	return (i_ReturnValue);
+}
+
+/*
++----------------------------------------------------------------------------+
+| Function   Name   : int i_APCI3XXX_Reset(struct comedi_device *dev)               |                                                         +----------------------------------------------------------------------------+
+| Task              :resets all the registers                                |
++----------------------------------------------------------------------------+
+| Input Parameters  : struct comedi_device *dev                                     |
++----------------------------------------------------------------------------+
+| Output Parameters : -                                                      |
++----------------------------------------------------------------------------+
+| Return Value      : -                                                      |
++----------------------------------------------------------------------------+
+*/
+
+int i_APCI3XXX_Reset(struct comedi_device * dev)
+{
+	unsigned char b_Cpt = 0;
+
+	/*************************/
+	/* Disable the interrupt */
+	/*************************/
+
+	disable_irq(dev->irq);
+
+	/****************************/
+	/* Reset the interrupt flag */
+	/****************************/
+
+	devpriv->b_EocEosInterrupt = 0;
+
+	/***************************/
+	/* Clear the start command */
+	/***************************/
+
+	writel(0, (void *)(devpriv->dw_AiBase + 8));
+
+	/*****************************/
+	/* Reset the interrupt flags */
+	/*****************************/
+
+	writel(readl((void *)(devpriv->dw_AiBase + 16)),
+		(void *)(devpriv->dw_AiBase + 16));
+
+	/*****************/
+	/* clear the EOS */
+	/*****************/
+
+	readl((void *)(devpriv->dw_AiBase + 20));
+
+	/******************/
+	/* Clear the FIFO */
+	/******************/
+
+	for (b_Cpt = 0; b_Cpt < 16; b_Cpt++) {
+		readl((void *)(devpriv->dw_AiBase + 28));
+	}
+
+	/************************/
+	/* Enable the interrupt */
+	/************************/
+
+	enable_irq(dev->irq);
+
+	return 0;
+}

+ 62 - 0
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
+ *
+ *	ADDI-DATA GmbH
+ *	Dieselstrasse 3
+ *	D-77833 Ottersweier
+ *	Tel: +19(0)7223/9493-0
+ *	Fax: +49(0)7223/9493-92
+ *	http://www.addi-data-com
+ *	info@addi-data.com
+ *
+ * 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.
+ */
+
+#ifndef COMEDI_SUBD_TTLIO
+#define COMEDI_SUBD_TTLIO   11	/* Digital Input Output But TTL */
+#endif
+
+#ifndef ADDIDATA_ENABLE
+#define ADDIDATA_ENABLE  1
+#define ADDIDATA_DISABLE 0
+#endif
+
+#define APCI3XXX_SINGLE                              0
+#define APCI3XXX_DIFF                                1
+#define APCI3XXX_CONFIGURATION                       0
+
+#define APCI3XXX_TTL_INIT_DIRECTION_PORT2   0
+
+#ifdef __KERNEL__
+
+static const struct comedi_lrange range_apci3XXX_ai = { 8, {BIP_RANGE(10),
+						     BIP_RANGE(5),
+						     BIP_RANGE(2),
+						     BIP_RANGE(1),
+						     UNI_RANGE(10),
+						     UNI_RANGE(5),
+						     UNI_RANGE(2),
+						     UNI_RANGE(1)}
+};
+
+static const struct comedi_lrange range_apci3XXX_ttl = { 12, {BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1),
+						       BIP_RANGE(1)}
+};
+
+static const struct comedi_lrange range_apci3XXX_ao = { 2, {BIP_RANGE(10),
+						     UNI_RANGE(10)}
+};
+#endif

+ 5 - 0
drivers/staging/comedi/drivers/addi_apci_035.c

@@ -0,0 +1,5 @@
+#define CONFIG_APCI_035 1
+
+#define ADDIDATA_WATCHDOG 2	// Or shold it be something else
+
+#include "addi-data/addi_common.c"

+ 3 - 0
drivers/staging/comedi/drivers/addi_apci_1032.c

@@ -0,0 +1,3 @@
+#define CONFIG_APCI_1032 1
+
+#include "addi-data/addi_common.c"

+ 3 - 0
drivers/staging/comedi/drivers/addi_apci_1500.c

@@ -0,0 +1,3 @@
+#define CONFIG_APCI_1500 1
+
+#include "addi-data/addi_common.c"

+ 3 - 0
drivers/staging/comedi/drivers/addi_apci_1516.c

@@ -0,0 +1,3 @@
+#define CONFIG_APCI_1516 1
+
+#include "addi-data/addi_common.c"

+ 3 - 0
drivers/staging/comedi/drivers/addi_apci_1564.c

@@ -0,0 +1,3 @@
+#define CONFIG_APCI_1564 1
+
+#include "addi-data/addi_common.c"

+ 3 - 0
drivers/staging/comedi/drivers/addi_apci_16xx.c

@@ -0,0 +1,3 @@
+#define CONFIG_APCI_16XX 1
+
+#include "addi-data/addi_common.c"

+ 3 - 0
drivers/staging/comedi/drivers/addi_apci_1710.c

@@ -0,0 +1,3 @@
+#define CONFIG_APCI_1710 1
+
+#include "addi-data/addi_common.c"

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels