|
@@ -119,15 +119,6 @@ static const struct comedi_lrange range_analog = { 4, {
|
|
|
|
|
|
static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
|
|
|
|
|
|
-/*
|
|
|
-==============================================================================
|
|
|
- Forward declarations
|
|
|
-==============================================================================
|
|
|
-*/
|
|
|
-static int icp_multi_attach(struct comedi_device *dev,
|
|
|
- struct comedi_devconfig *it);
|
|
|
-static int icp_multi_detach(struct comedi_device *dev);
|
|
|
-
|
|
|
/*
|
|
|
==============================================================================
|
|
|
Data & Structure declarations
|
|
@@ -154,48 +145,6 @@ struct boardtype {
|
|
|
const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
|
|
|
};
|
|
|
|
|
|
-static const struct boardtype boardtypes[] = {
|
|
|
- {"icp_multi", /* Driver name */
|
|
|
- DEVICE_ID, /* PCI device ID */
|
|
|
- IORANGE_ICP_MULTI, /* I/O range length */
|
|
|
- 1, /* 1=Card supports interrupts */
|
|
|
- TYPE_ICP_MULTI, /* Card type = ICP MULTI */
|
|
|
- 16, /* Num of A/D channels */
|
|
|
- 8, /* Num of A/D channels in diff mode */
|
|
|
- 4, /* Num of D/A channels */
|
|
|
- 16, /* Num of digital inputs */
|
|
|
- 8, /* Num of digital outputs */
|
|
|
- 4, /* Num of counters */
|
|
|
- 0x0fff, /* Resolution of A/D */
|
|
|
- 0x0fff, /* Resolution of D/A */
|
|
|
- &range_analog, /* Rangelist for A/D */
|
|
|
- range_codes_analog, /* Range codes for programming */
|
|
|
- &range_analog}, /* Rangelist for D/A */
|
|
|
-};
|
|
|
-
|
|
|
-static struct comedi_driver driver_icp_multi = {
|
|
|
- .driver_name = "icp_multi",
|
|
|
- .module = THIS_MODULE,
|
|
|
- .attach = icp_multi_attach,
|
|
|
- .detach = icp_multi_detach,
|
|
|
- .num_names = ARRAY_SIZE(boardtypes),
|
|
|
- .board_name = &boardtypes[0].name,
|
|
|
- .offset = sizeof(struct boardtype),
|
|
|
-};
|
|
|
-
|
|
|
-static int __init driver_icp_multi_init_module(void)
|
|
|
-{
|
|
|
- return comedi_driver_register(&driver_icp_multi);
|
|
|
-}
|
|
|
-
|
|
|
-static void __exit driver_icp_multi_cleanup_module(void)
|
|
|
-{
|
|
|
- comedi_driver_unregister(&driver_icp_multi);
|
|
|
-}
|
|
|
-
|
|
|
-module_init(driver_icp_multi_init_module);
|
|
|
-module_exit(driver_icp_multi_cleanup_module);
|
|
|
-
|
|
|
struct icp_multi_private {
|
|
|
struct pcilst_struct *card; /* pointer to card */
|
|
|
char valid; /* card is usable */
|
|
@@ -220,25 +169,81 @@ struct icp_multi_private {
|
|
|
|
|
|
/*
|
|
|
==============================================================================
|
|
|
- More forward declarations
|
|
|
+
|
|
|
+Name: setup_channel_list
|
|
|
+
|
|
|
+Description:
|
|
|
+ This function sets the appropriate channel selection,
|
|
|
+ differential input mode and range bits in the ADC Command/
|
|
|
+ Status register.
|
|
|
+
|
|
|
+Parameters:
|
|
|
+ struct comedi_device *dev Pointer to current service structure
|
|
|
+ struct comedi_subdevice *s Pointer to current subdevice structure
|
|
|
+ unsigned int *chanlist Pointer to packed channel list
|
|
|
+ unsigned int n_chan Number of channels to scan
|
|
|
+
|
|
|
+Returns:Void
|
|
|
+
|
|
|
==============================================================================
|
|
|
*/
|
|
|
-
|
|
|
-#if 0
|
|
|
-static int check_channel_list(struct comedi_device *dev,
|
|
|
- struct comedi_subdevice *s,
|
|
|
- unsigned int *chanlist, unsigned int n_chan);
|
|
|
-#endif
|
|
|
static void setup_channel_list(struct comedi_device *dev,
|
|
|
struct comedi_subdevice *s,
|
|
|
- unsigned int *chanlist, unsigned int n_chan);
|
|
|
-static int icp_multi_reset(struct comedi_device *dev);
|
|
|
+ unsigned int *chanlist, unsigned int n_chan)
|
|
|
+{
|
|
|
+ unsigned int i, range, chanprog;
|
|
|
+ unsigned int diff;
|
|
|
|
|
|
-/*
|
|
|
-==============================================================================
|
|
|
- Functions
|
|
|
-==============================================================================
|
|
|
-*/
|
|
|
+#ifdef ICP_MULTI_EXTDEBUG
|
|
|
+ printk(KERN_DEBUG
|
|
|
+ "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
|
|
|
+#endif
|
|
|
+ devpriv->act_chanlist_len = n_chan;
|
|
|
+ devpriv->act_chanlist_pos = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < n_chan; i++) {
|
|
|
+ /* Get channel */
|
|
|
+ chanprog = CR_CHAN(chanlist[i]);
|
|
|
+
|
|
|
+ /* Determine if it is a differential channel (Bit 15 = 1) */
|
|
|
+ if (CR_AREF(chanlist[i]) == AREF_DIFF) {
|
|
|
+ diff = 1;
|
|
|
+ chanprog &= 0x0007;
|
|
|
+ } else {
|
|
|
+ diff = 0;
|
|
|
+ chanprog &= 0x000f;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clear channel, range and input mode bits
|
|
|
+ * in A/D command/status register */
|
|
|
+ devpriv->AdcCmdStatus &= 0xf00f;
|
|
|
+
|
|
|
+ /* Set channel number and differential mode status bit */
|
|
|
+ if (diff) {
|
|
|
+ /* Set channel number, bits 9-11 & mode, bit 6 */
|
|
|
+ devpriv->AdcCmdStatus |= (chanprog << 9);
|
|
|
+ devpriv->AdcCmdStatus |= ADC_DI;
|
|
|
+ } else
|
|
|
+ /* Set channel number, bits 8-11 */
|
|
|
+ devpriv->AdcCmdStatus |= (chanprog << 8);
|
|
|
+
|
|
|
+ /* Get range for current channel */
|
|
|
+ range = this_board->rangecode[CR_RANGE(chanlist[i])];
|
|
|
+ /* Set range. bits 4-5 */
|
|
|
+ devpriv->AdcCmdStatus |= range;
|
|
|
+
|
|
|
+ /* Output channel, range, mode to ICP Multi */
|
|
|
+ writew(devpriv->AdcCmdStatus,
|
|
|
+ devpriv->io_addr + ICP_MULTI_ADC_CSR);
|
|
|
+
|
|
|
+#ifdef ICP_MULTI_EXTDEBUG
|
|
|
+ printk(KERN_DEBUG
|
|
|
+ "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
|
|
|
+ devpriv->act_chanlist[i]);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
==============================================================================
|
|
@@ -762,84 +767,6 @@ static int check_channel_list(struct comedi_device *dev,
|
|
|
/*
|
|
|
==============================================================================
|
|
|
|
|
|
-Name: setup_channel_list
|
|
|
-
|
|
|
-Description:
|
|
|
- This function sets the appropriate channel selection,
|
|
|
- differential input mode and range bits in the ADC Command/
|
|
|
- Status register.
|
|
|
-
|
|
|
-Parameters:
|
|
|
- struct comedi_device *dev Pointer to current service structure
|
|
|
- struct comedi_subdevice *s Pointer to current subdevice structure
|
|
|
- unsigned int *chanlist Pointer to packed channel list
|
|
|
- unsigned int n_chan Number of channels to scan
|
|
|
-
|
|
|
-Returns:Void
|
|
|
-
|
|
|
-==============================================================================
|
|
|
-*/
|
|
|
-static void setup_channel_list(struct comedi_device *dev,
|
|
|
- struct comedi_subdevice *s,
|
|
|
- unsigned int *chanlist, unsigned int n_chan)
|
|
|
-{
|
|
|
- unsigned int i, range, chanprog;
|
|
|
- unsigned int diff;
|
|
|
-
|
|
|
-#ifdef ICP_MULTI_EXTDEBUG
|
|
|
- printk(KERN_DEBUG
|
|
|
- "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
|
|
|
-#endif
|
|
|
- devpriv->act_chanlist_len = n_chan;
|
|
|
- devpriv->act_chanlist_pos = 0;
|
|
|
-
|
|
|
- for (i = 0; i < n_chan; i++) {
|
|
|
- /* Get channel */
|
|
|
- chanprog = CR_CHAN(chanlist[i]);
|
|
|
-
|
|
|
- /* Determine if it is a differential channel (Bit 15 = 1) */
|
|
|
- if (CR_AREF(chanlist[i]) == AREF_DIFF) {
|
|
|
- diff = 1;
|
|
|
- chanprog &= 0x0007;
|
|
|
- } else {
|
|
|
- diff = 0;
|
|
|
- chanprog &= 0x000f;
|
|
|
- }
|
|
|
-
|
|
|
- /* Clear channel, range and input mode bits
|
|
|
- * in A/D command/status register */
|
|
|
- devpriv->AdcCmdStatus &= 0xf00f;
|
|
|
-
|
|
|
- /* Set channel number and differential mode status bit */
|
|
|
- if (diff) {
|
|
|
- /* Set channel number, bits 9-11 & mode, bit 6 */
|
|
|
- devpriv->AdcCmdStatus |= (chanprog << 9);
|
|
|
- devpriv->AdcCmdStatus |= ADC_DI;
|
|
|
- } else
|
|
|
- /* Set channel number, bits 8-11 */
|
|
|
- devpriv->AdcCmdStatus |= (chanprog << 8);
|
|
|
-
|
|
|
- /* Get range for current channel */
|
|
|
- range = this_board->rangecode[CR_RANGE(chanlist[i])];
|
|
|
- /* Set range. bits 4-5 */
|
|
|
- devpriv->AdcCmdStatus |= range;
|
|
|
-
|
|
|
- /* Output channel, range, mode to ICP Multi */
|
|
|
- writew(devpriv->AdcCmdStatus,
|
|
|
- devpriv->io_addr + ICP_MULTI_ADC_CSR);
|
|
|
-
|
|
|
-#ifdef ICP_MULTI_EXTDEBUG
|
|
|
- printk(KERN_DEBUG
|
|
|
- "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
|
|
|
- devpriv->act_chanlist[i]);
|
|
|
-#endif
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
-==============================================================================
|
|
|
-
|
|
|
Name: icp_multi_reset
|
|
|
|
|
|
Description:
|
|
@@ -895,23 +822,6 @@ static int icp_multi_reset(struct comedi_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
-==============================================================================
|
|
|
-
|
|
|
-Name: icp_multi_attach
|
|
|
-
|
|
|
-Description:
|
|
|
- This function sets up all the appropriate data for the current
|
|
|
- device.
|
|
|
-
|
|
|
-Parameters:
|
|
|
- struct comedi_device *dev Pointer to current device structure
|
|
|
- struct comedi_devconfig *it Pointer to current device configuration
|
|
|
-
|
|
|
-Returns:int 0 = success
|
|
|
-
|
|
|
-==============================================================================
|
|
|
-*/
|
|
|
static int icp_multi_attach(struct comedi_device *dev,
|
|
|
struct comedi_devconfig *it)
|
|
|
{
|
|
@@ -1097,25 +1007,8 @@ static int icp_multi_attach(struct comedi_device *dev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
-==============================================================================
|
|
|
-
|
|
|
-Name: icp_multi_detach
|
|
|
-
|
|
|
-Description:
|
|
|
- This function releases all the resources used by the current
|
|
|
- device.
|
|
|
-
|
|
|
-Parameters:
|
|
|
- struct comedi_device *dev Pointer to current device structure
|
|
|
-
|
|
|
-Returns:int 0 = success
|
|
|
-
|
|
|
-==============================================================================
|
|
|
-*/
|
|
|
static int icp_multi_detach(struct comedi_device *dev)
|
|
|
{
|
|
|
-
|
|
|
if (dev->private)
|
|
|
if (devpriv->valid)
|
|
|
icp_multi_reset(dev);
|
|
@@ -1135,6 +1028,38 @@ static int icp_multi_detach(struct comedi_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static const struct boardtype boardtypes[] = {
|
|
|
+ {
|
|
|
+ .name = "icp_multi",
|
|
|
+ .device_id = DEVICE_ID,
|
|
|
+ .iorange = IORANGE_ICP_MULTI,
|
|
|
+ .have_irq = 1,
|
|
|
+ .cardtype = TYPE_ICP_MULTI,
|
|
|
+ .n_aichan = 16,
|
|
|
+ .n_aichand = 8,
|
|
|
+ .n_aochan = 4,
|
|
|
+ .n_dichan = 16,
|
|
|
+ .n_dochan = 8,
|
|
|
+ .n_ctrs = 4,
|
|
|
+ .ai_maxdata = 0x0fff,
|
|
|
+ .ao_maxdata = 0x0fff,
|
|
|
+ .rangelist_ai = &range_analog,
|
|
|
+ .rangecode = range_codes_analog,
|
|
|
+ .rangelist_ao = &range_analog,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static struct comedi_driver icp_multi_driver = {
|
|
|
+ .driver_name = "icp_multi",
|
|
|
+ .module = THIS_MODULE,
|
|
|
+ .attach = icp_multi_attach,
|
|
|
+ .detach = icp_multi_detach,
|
|
|
+ .num_names = ARRAY_SIZE(boardtypes),
|
|
|
+ .board_name = &boardtypes[0].name,
|
|
|
+ .offset = sizeof(struct boardtype),
|
|
|
+};
|
|
|
+module_comedi_driver(icp_multi_driver);
|
|
|
+
|
|
|
MODULE_AUTHOR("Comedi http://www.comedi.org");
|
|
|
MODULE_DESCRIPTION("Comedi low-level driver");
|
|
|
MODULE_LICENSE("GPL");
|