diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/comedi/drivers/icp_multi.c | 279 |
1 files changed, 102 insertions, 177 deletions
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 67b6f5aa1885..0f63fc04b5fd 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c | |||
@@ -121,15 +121,6 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; | |||
121 | 121 | ||
122 | /* | 122 | /* |
123 | ============================================================================== | 123 | ============================================================================== |
124 | Forward declarations | ||
125 | ============================================================================== | ||
126 | */ | ||
127 | static int icp_multi_attach(struct comedi_device *dev, | ||
128 | struct comedi_devconfig *it); | ||
129 | static int icp_multi_detach(struct comedi_device *dev); | ||
130 | |||
131 | /* | ||
132 | ============================================================================== | ||
133 | Data & Structure declarations | 124 | Data & Structure declarations |
134 | ============================================================================== | 125 | ============================================================================== |
135 | */ | 126 | */ |
@@ -154,48 +145,6 @@ struct boardtype { | |||
154 | const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ | 145 | const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ |
155 | }; | 146 | }; |
156 | 147 | ||
157 | static const struct boardtype boardtypes[] = { | ||
158 | {"icp_multi", /* Driver name */ | ||
159 | DEVICE_ID, /* PCI device ID */ | ||
160 | IORANGE_ICP_MULTI, /* I/O range length */ | ||
161 | 1, /* 1=Card supports interrupts */ | ||
162 | TYPE_ICP_MULTI, /* Card type = ICP MULTI */ | ||
163 | 16, /* Num of A/D channels */ | ||
164 | 8, /* Num of A/D channels in diff mode */ | ||
165 | 4, /* Num of D/A channels */ | ||
166 | 16, /* Num of digital inputs */ | ||
167 | 8, /* Num of digital outputs */ | ||
168 | 4, /* Num of counters */ | ||
169 | 0x0fff, /* Resolution of A/D */ | ||
170 | 0x0fff, /* Resolution of D/A */ | ||
171 | &range_analog, /* Rangelist for A/D */ | ||
172 | range_codes_analog, /* Range codes for programming */ | ||
173 | &range_analog}, /* Rangelist for D/A */ | ||
174 | }; | ||
175 | |||
176 | static struct comedi_driver driver_icp_multi = { | ||
177 | .driver_name = "icp_multi", | ||
178 | .module = THIS_MODULE, | ||
179 | .attach = icp_multi_attach, | ||
180 | .detach = icp_multi_detach, | ||
181 | .num_names = ARRAY_SIZE(boardtypes), | ||
182 | .board_name = &boardtypes[0].name, | ||
183 | .offset = sizeof(struct boardtype), | ||
184 | }; | ||
185 | |||
186 | static int __init driver_icp_multi_init_module(void) | ||
187 | { | ||
188 | return comedi_driver_register(&driver_icp_multi); | ||
189 | } | ||
190 | |||
191 | static void __exit driver_icp_multi_cleanup_module(void) | ||
192 | { | ||
193 | comedi_driver_unregister(&driver_icp_multi); | ||
194 | } | ||
195 | |||
196 | module_init(driver_icp_multi_init_module); | ||
197 | module_exit(driver_icp_multi_cleanup_module); | ||
198 | |||
199 | struct icp_multi_private { | 148 | struct icp_multi_private { |
200 | struct pcilst_struct *card; /* pointer to card */ | 149 | struct pcilst_struct *card; /* pointer to card */ |
201 | char valid; /* card is usable */ | 150 | char valid; /* card is usable */ |
@@ -220,25 +169,81 @@ struct icp_multi_private { | |||
220 | 169 | ||
221 | /* | 170 | /* |
222 | ============================================================================== | 171 | ============================================================================== |
223 | More forward declarations | 172 | |
173 | Name: setup_channel_list | ||
174 | |||
175 | Description: | ||
176 | This function sets the appropriate channel selection, | ||
177 | differential input mode and range bits in the ADC Command/ | ||
178 | Status register. | ||
179 | |||
180 | Parameters: | ||
181 | struct comedi_device *dev Pointer to current service structure | ||
182 | struct comedi_subdevice *s Pointer to current subdevice structure | ||
183 | unsigned int *chanlist Pointer to packed channel list | ||
184 | unsigned int n_chan Number of channels to scan | ||
185 | |||
186 | Returns:Void | ||
187 | |||
224 | ============================================================================== | 188 | ============================================================================== |
225 | */ | 189 | */ |
226 | |||
227 | #if 0 | ||
228 | static int check_channel_list(struct comedi_device *dev, | ||
229 | struct comedi_subdevice *s, | ||
230 | unsigned int *chanlist, unsigned int n_chan); | ||
231 | #endif | ||
232 | static void setup_channel_list(struct comedi_device *dev, | 190 | static void setup_channel_list(struct comedi_device *dev, |
233 | struct comedi_subdevice *s, | 191 | struct comedi_subdevice *s, |
234 | unsigned int *chanlist, unsigned int n_chan); | 192 | unsigned int *chanlist, unsigned int n_chan) |
235 | static int icp_multi_reset(struct comedi_device *dev); | 193 | { |
194 | unsigned int i, range, chanprog; | ||
195 | unsigned int diff; | ||
236 | 196 | ||
237 | /* | 197 | #ifdef ICP_MULTI_EXTDEBUG |
238 | ============================================================================== | 198 | printk(KERN_DEBUG |
239 | Functions | 199 | "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan); |
240 | ============================================================================== | 200 | #endif |
241 | */ | 201 | devpriv->act_chanlist_len = n_chan; |
202 | devpriv->act_chanlist_pos = 0; | ||
203 | |||
204 | for (i = 0; i < n_chan; i++) { | ||
205 | /* Get channel */ | ||
206 | chanprog = CR_CHAN(chanlist[i]); | ||
207 | |||
208 | /* Determine if it is a differential channel (Bit 15 = 1) */ | ||
209 | if (CR_AREF(chanlist[i]) == AREF_DIFF) { | ||
210 | diff = 1; | ||
211 | chanprog &= 0x0007; | ||
212 | } else { | ||
213 | diff = 0; | ||
214 | chanprog &= 0x000f; | ||
215 | } | ||
216 | |||
217 | /* Clear channel, range and input mode bits | ||
218 | * in A/D command/status register */ | ||
219 | devpriv->AdcCmdStatus &= 0xf00f; | ||
220 | |||
221 | /* Set channel number and differential mode status bit */ | ||
222 | if (diff) { | ||
223 | /* Set channel number, bits 9-11 & mode, bit 6 */ | ||
224 | devpriv->AdcCmdStatus |= (chanprog << 9); | ||
225 | devpriv->AdcCmdStatus |= ADC_DI; | ||
226 | } else | ||
227 | /* Set channel number, bits 8-11 */ | ||
228 | devpriv->AdcCmdStatus |= (chanprog << 8); | ||
229 | |||
230 | /* Get range for current channel */ | ||
231 | range = this_board->rangecode[CR_RANGE(chanlist[i])]; | ||
232 | /* Set range. bits 4-5 */ | ||
233 | devpriv->AdcCmdStatus |= range; | ||
234 | |||
235 | /* Output channel, range, mode to ICP Multi */ | ||
236 | writew(devpriv->AdcCmdStatus, | ||
237 | devpriv->io_addr + ICP_MULTI_ADC_CSR); | ||
238 | |||
239 | #ifdef ICP_MULTI_EXTDEBUG | ||
240 | printk(KERN_DEBUG | ||
241 | "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, | ||
242 | devpriv->act_chanlist[i]); | ||
243 | #endif | ||
244 | } | ||
245 | |||
246 | } | ||
242 | 247 | ||
243 | /* | 248 | /* |
244 | ============================================================================== | 249 | ============================================================================== |
@@ -762,84 +767,6 @@ static int check_channel_list(struct comedi_device *dev, | |||
762 | /* | 767 | /* |
763 | ============================================================================== | 768 | ============================================================================== |
764 | 769 | ||
765 | Name: setup_channel_list | ||
766 | |||
767 | Description: | ||
768 | This function sets the appropriate channel selection, | ||
769 | differential input mode and range bits in the ADC Command/ | ||
770 | Status register. | ||
771 | |||
772 | Parameters: | ||
773 | struct comedi_device *dev Pointer to current service structure | ||
774 | struct comedi_subdevice *s Pointer to current subdevice structure | ||
775 | unsigned int *chanlist Pointer to packed channel list | ||
776 | unsigned int n_chan Number of channels to scan | ||
777 | |||
778 | Returns:Void | ||
779 | |||
780 | ============================================================================== | ||
781 | */ | ||
782 | static void setup_channel_list(struct comedi_device *dev, | ||
783 | struct comedi_subdevice *s, | ||
784 | unsigned int *chanlist, unsigned int n_chan) | ||
785 | { | ||
786 | unsigned int i, range, chanprog; | ||
787 | unsigned int diff; | ||
788 | |||
789 | #ifdef ICP_MULTI_EXTDEBUG | ||
790 | printk(KERN_DEBUG | ||
791 | "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan); | ||
792 | #endif | ||
793 | devpriv->act_chanlist_len = n_chan; | ||
794 | devpriv->act_chanlist_pos = 0; | ||
795 | |||
796 | for (i = 0; i < n_chan; i++) { | ||
797 | /* Get channel */ | ||
798 | chanprog = CR_CHAN(chanlist[i]); | ||
799 | |||
800 | /* Determine if it is a differential channel (Bit 15 = 1) */ | ||
801 | if (CR_AREF(chanlist[i]) == AREF_DIFF) { | ||
802 | diff = 1; | ||
803 | chanprog &= 0x0007; | ||
804 | } else { | ||
805 | diff = 0; | ||
806 | chanprog &= 0x000f; | ||
807 | } | ||
808 | |||
809 | /* Clear channel, range and input mode bits | ||
810 | * in A/D command/status register */ | ||
811 | devpriv->AdcCmdStatus &= 0xf00f; | ||
812 | |||
813 | /* Set channel number and differential mode status bit */ | ||
814 | if (diff) { | ||
815 | /* Set channel number, bits 9-11 & mode, bit 6 */ | ||
816 | devpriv->AdcCmdStatus |= (chanprog << 9); | ||
817 | devpriv->AdcCmdStatus |= ADC_DI; | ||
818 | } else | ||
819 | /* Set channel number, bits 8-11 */ | ||
820 | devpriv->AdcCmdStatus |= (chanprog << 8); | ||
821 | |||
822 | /* Get range for current channel */ | ||
823 | range = this_board->rangecode[CR_RANGE(chanlist[i])]; | ||
824 | /* Set range. bits 4-5 */ | ||
825 | devpriv->AdcCmdStatus |= range; | ||
826 | |||
827 | /* Output channel, range, mode to ICP Multi */ | ||
828 | writew(devpriv->AdcCmdStatus, | ||
829 | devpriv->io_addr + ICP_MULTI_ADC_CSR); | ||
830 | |||
831 | #ifdef ICP_MULTI_EXTDEBUG | ||
832 | printk(KERN_DEBUG | ||
833 | "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, | ||
834 | devpriv->act_chanlist[i]); | ||
835 | #endif | ||
836 | } | ||
837 | |||
838 | } | ||
839 | |||
840 | /* | ||
841 | ============================================================================== | ||
842 | |||
843 | Name: icp_multi_reset | 770 | Name: icp_multi_reset |
844 | 771 | ||
845 | Description: | 772 | Description: |
@@ -895,23 +822,6 @@ static int icp_multi_reset(struct comedi_device *dev) | |||
895 | return 0; | 822 | return 0; |
896 | } | 823 | } |
897 | 824 | ||
898 | /* | ||
899 | ============================================================================== | ||
900 | |||
901 | Name: icp_multi_attach | ||
902 | |||
903 | Description: | ||
904 | This function sets up all the appropriate data for the current | ||
905 | device. | ||
906 | |||
907 | Parameters: | ||
908 | struct comedi_device *dev Pointer to current device structure | ||
909 | struct comedi_devconfig *it Pointer to current device configuration | ||
910 | |||
911 | Returns:int 0 = success | ||
912 | |||
913 | ============================================================================== | ||
914 | */ | ||
915 | static int icp_multi_attach(struct comedi_device *dev, | 825 | static int icp_multi_attach(struct comedi_device *dev, |
916 | struct comedi_devconfig *it) | 826 | struct comedi_devconfig *it) |
917 | { | 827 | { |
@@ -1097,25 +1007,8 @@ static int icp_multi_attach(struct comedi_device *dev, | |||
1097 | return 0; | 1007 | return 0; |
1098 | } | 1008 | } |
1099 | 1009 | ||
1100 | /* | ||
1101 | ============================================================================== | ||
1102 | |||
1103 | Name: icp_multi_detach | ||
1104 | |||
1105 | Description: | ||
1106 | This function releases all the resources used by the current | ||
1107 | device. | ||
1108 | |||
1109 | Parameters: | ||
1110 | struct comedi_device *dev Pointer to current device structure | ||
1111 | |||
1112 | Returns:int 0 = success | ||
1113 | |||
1114 | ============================================================================== | ||
1115 | */ | ||
1116 | static int icp_multi_detach(struct comedi_device *dev) | 1010 | static int icp_multi_detach(struct comedi_device *dev) |
1117 | { | 1011 | { |
1118 | |||
1119 | if (dev->private) | 1012 | if (dev->private) |
1120 | if (devpriv->valid) | 1013 | if (devpriv->valid) |
1121 | icp_multi_reset(dev); | 1014 | icp_multi_reset(dev); |
@@ -1135,6 +1028,38 @@ static int icp_multi_detach(struct comedi_device *dev) | |||
1135 | return 0; | 1028 | return 0; |
1136 | } | 1029 | } |
1137 | 1030 | ||
1031 | static const struct boardtype boardtypes[] = { | ||
1032 | { | ||
1033 | .name = "icp_multi", | ||
1034 | .device_id = DEVICE_ID, | ||
1035 | .iorange = IORANGE_ICP_MULTI, | ||
1036 | .have_irq = 1, | ||
1037 | .cardtype = TYPE_ICP_MULTI, | ||
1038 | .n_aichan = 16, | ||
1039 | .n_aichand = 8, | ||
1040 | .n_aochan = 4, | ||
1041 | .n_dichan = 16, | ||
1042 | .n_dochan = 8, | ||
1043 | .n_ctrs = 4, | ||
1044 | .ai_maxdata = 0x0fff, | ||
1045 | .ao_maxdata = 0x0fff, | ||
1046 | .rangelist_ai = &range_analog, | ||
1047 | .rangecode = range_codes_analog, | ||
1048 | .rangelist_ao = &range_analog, | ||
1049 | }, | ||
1050 | }; | ||
1051 | |||
1052 | static struct comedi_driver icp_multi_driver = { | ||
1053 | .driver_name = "icp_multi", | ||
1054 | .module = THIS_MODULE, | ||
1055 | .attach = icp_multi_attach, | ||
1056 | .detach = icp_multi_detach, | ||
1057 | .num_names = ARRAY_SIZE(boardtypes), | ||
1058 | .board_name = &boardtypes[0].name, | ||
1059 | .offset = sizeof(struct boardtype), | ||
1060 | }; | ||
1061 | module_comedi_driver(icp_multi_driver); | ||
1062 | |||
1138 | MODULE_AUTHOR("Comedi http://www.comedi.org"); | 1063 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
1139 | MODULE_DESCRIPTION("Comedi low-level driver"); | 1064 | MODULE_DESCRIPTION("Comedi low-level driver"); |
1140 | MODULE_LICENSE("GPL"); | 1065 | MODULE_LICENSE("GPL"); |