]> rtime.felk.cvut.cz Git - mf6xx.git/blob - src/hudaqlib/PCI1753.c
QEMU mf624.c formatted to make QEMU checkpatch.pl mostly happy.
[mf6xx.git] / src / hudaqlib / PCI1753.c
1 /****************************************************************/\r
2 /**@file PCI1753.c:\r
3  * Description: API layer for Advantech PCI1753 card.           *\r
4  * Dependency: Windows 32 or Linux                              *               \r
5  *                Copyright 2006-2009 Jaroslav Fojtik           *\r
6  * Note: Windows 64 will not work                               *\r
7  ****************************************************************/\r
8 \r
9 #if defined(_WIN32) || defined(_WIN64)\r
10 #include <windows.h>\r
11 #include <intrin.h>\r
12 #define outb(Port,Data) __outbyte(Port,Data)\r
13 #define outw(Port,Data) __outword(Port,Data)\r
14 #define inb(Port)         __inbyte(Port)\r
15 #else\r
16 #include <sys/io.h>\r
17 #endif\r
18 #include <malloc.h>\r
19 #include <math.h>\r
20 \r
21 #include "hudaqlib.h"\r
22 #include "hudaq_internal.h"\r
23 \r
24 \r
25 #define DI_CHANNELS   12        ///< Amount of Digital Outputs\r
26 #define DO_CHANNELS   12        ///< Amount of Digital Inputs\r
27 #define DA_CHANNELS   0         ///< Amount of Analog Outputs\r
28 #define AD_CHANNELS   0         ///< Amount of Analog Inputs\r
29 #define ENC_CHANNELS  0         ///< Amount of Encoders\r
30 #define CTR_CHANNELS  0         ///< Amount of counters\r
31 #define STEP_CHANNELS 0         ///< Amount of steppers\r
32 \r
33 \r
34 /** Cache of PCI1753 state */\r
35 typedef struct\r
36 {\r
37         UserDataHeader Hdr;                   ///< General device setup\r
38 \r
39         unsigned __int8 pconfig[4];             ///< Port configuration register\r
40         __int8 InterruptControl[4];\r
41         unsigned __int8 DoutCache[DO_CHANNELS];\r
42         __int8 PatternMatch;\r
43         __int8 PatternEnable;\r
44         __int8 ChangeEnableState;\r
45 } PCI1753_Private;\r
46 \r
47 \r
48 /** Symbolic aliases for available registers inside BADR0 read. */\r
49 typedef enum\r
50 {\r
51         A0         = 0,\r
52         B0         = 1,\r
53         C0         = 2,\r
54         Cfg0         = 3,\r
55         A1         = 4,\r
56         B1         = 5,\r
57         C1         = 6,\r
58         Cfg1         = 7,\r
59         A2         = 8,\r
60         B2         = 9,\r
61         C2         = 10,\r
62         Cfg3         = 11,\r
63         A3         = 12,\r
64         B3         = 13,\r
65         C3         = 14,\r
66         Cfg4         = 15,\r
67         IrqCtrR    = 16,\r
68         PatternMatch = 20,\r
69         PatternEnable= 24,\r
70         ChEnableState= 28,\r
71 } IO0IN;\r
72 \r
73 static __int8 Ports[DI_CHANNELS] = {A0, B0, C0, A1, B1, C1, A2, B2, C2, A3, B3, C3};\r
74 \r
75 \r
76 /** write to memory mapped device byte wise, bytes are stored on every 4th position. */\r
77 static __inline void StoreByte(size_t Ptr, int Offset, unsigned __int8 value)\r
78 {\r
79         //printf("%X %X\n",Ptr+Offset, value);\r
80         outb(value, Ptr+Offset);\r
81 }\r
82 \r
83 /** write to IO device byte through cache. */\r
84 static __inline void StoreCachedByte(size_t Ptr, int Offset, unsigned __int8 value, unsigned __int8 *CachedValue)\r
85 {\r
86         if (*CachedValue != value)\r
87         {\r
88                 *CachedValue = value;\r
89                 StoreByte(Ptr,Offset,value);\r
90         }\r
91 }\r
92 \r
93 /** Read from memory mapped device byte wise, bytes are stored on every 4th position. */\r
94 static __inline unsigned __int8 GetByte(size_t Ptr, int Offset)\r
95 {\r
96         return inb(Ptr+Offset);\r
97 }\r
98 \r
99 \r
100 /****************************************************************\r
101  *                                                              *\r
102  *                 DIGITAL INPUTS & OUTPUTS                     *\r
103  *                                                              *\r
104  ****************************************************************/\r
105 \r
106 \r
107 /** Get data from digital input. */\r
108 static int PCI1753DIRead(const DeviceRecord *DevRecord, unsigned channel)\r
109 {\r
110         if (channel>=DI_CHANNELS) return HUDAQBADARG;\r
111         return GetByte(DevRecord->DrvRes.Resources.IOResources[0].Base,Ports[channel]);\r
112 }\r
113 \r
114 \r
115 /** Write data to digital output. */\r
116 static HUDAQSTATUS PCI1753DOWrite(const DeviceRecord *DevRecord, unsigned channel, unsigned value)\r
117 {\r
118         if (channel>=DO_CHANNELS) return HUDAQBADARG;\r
119         StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Ports[channel], value,\r
120                         & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel] );\r
121         return HUDAQSUCCESS;\r
122 }\r
123 \r
124 \r
125 static HUDAQSTATUS PCI1753DIReadMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, unsigned *values)\r
126 {\r
127         unsigned FlagX = 0;\r
128         unsigned i;\r
129         size_t Base;\r
130         unsigned __int8 Cache[DI_CHANNELS+1];  //allocate more bytes for padding ind\r
131 \r
132         if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;\r
133         if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;\r
134 \r
135         Base = DevRecord->DrvRes.Resources.IOResources[0].Base;\r
136 \r
137         /* schedule what to read */\r
138         for(i=0; i<number; i++)\r
139         {\r
140                 if (channels[i]<DI_CHANNELS)\r
141                 {\r
142                         FlagX |= 1<<(channels[i]);\r
143                 }\r
144                 else\r
145                 {\r
146                         values[i] = 0;\r
147                         FlagX |= 0x8000;\r
148                 }\r
149         }\r
150 \r
151         /* Read isolated DIs */\r
152         for(i=0; i<DI_CHANNELS; i++)\r
153         {\r
154                 if(FlagX & (1<<i))\r
155                 {\r
156                         Cache[i] = GetByte(Base,Ports[i]);\r
157                 }\r
158         }  \r
159 \r
160         /* Final store od numbers read */\r
161         for(i=0; i<number; i++)\r
162         {\r
163                 if(channels[i]<DI_CHANNELS)\r
164                 {\r
165                         values[i] = Cache[channels[i]];\r
166                 }\r
167         }      \r
168 \r
169         if(FlagX == 0x8000) return HUDAQFAILURE;        //no valid value returned\r
170         if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not\r
171         return HUDAQSUCCESS;                    //all values are valid (or no channel asked)\r
172 }\r
173 \r
174 \r
175 static HUDAQSTATUS PCI1753DOWriteMultiple(const DeviceRecord *DevRecord, unsigned number, const unsigned *channels, const unsigned *values)\r
176 {\r
177         unsigned FlagX = 0;\r
178         unsigned i,j;\r
179         size_t Base;\r
180         unsigned __int8 *Cache;\r
181 \r
182         if (number==0 || channels==NULL || values==NULL) return HUDAQBADARG;\r
183         if(DevRecord->pCT->HudaqDIRead==NULL) return HUDAQFAILURE;\r
184 \r
185         Base = DevRecord->DrvRes.Resources.IOResources[0].Base;\r
186         Cache = ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache;\r
187 \r
188         /* schedule what to write */\r
189         for(i=0; i<number; i++)\r
190         {\r
191                 if (channels[i]<DI_CHANNELS)\r
192                 {\r
193                         if(Cache[i] != values[i])\r
194                         {\r
195                                 FlagX |= 1<<(channels[i]);\r
196                                 Cache[i] = values[i];\r
197                         }\r
198                 }\r
199                 else\r
200                 {\r
201                         FlagX |= 0x8000;\r
202                 }\r
203         }\r
204 \r
205         /* Write DOs couples */\r
206         for(i=0; i<12; i=i+3)\r
207         {      \r
208                 j = 3 << i;\r
209                 if((FlagX & j) == j)\r
210                 {\r
211                         outw(*(__int16 *)&(Cache[i]), Base+Ports[i]);\r
212                         FlagX &= ~j;\r
213                 }  \r
214         }    \r
215 \r
216         /* Final store of DOs */\r
217         for(i=0; i<DI_CHANNELS; i++)\r
218         {\r
219                 if(FlagX & (1<<i))\r
220                 {\r
221                         StoreByte(Base, Ports[i], Cache[i]);\r
222                 }\r
223         }  \r
224 \r
225         if(FlagX == 0x8000) return HUDAQFAILURE;        //no valid value returned\r
226         if(FlagX & 0x8000) return HUDAQPARTIAL; //several values are valid and several are not\r
227         return HUDAQSUCCESS;                    //all values are valid (or no channel asked)\r
228 }\r
229 \r
230 \r
231 /** Write one bit to digital output. */\r
232 static void PCI1753DOWriteBit(const DeviceRecord *DevRecord, unsigned channel, unsigned bit, int value)\r
233 {\r
234         __int8 DoutByte;\r
235 \r
236         if (channel>=DO_CHANNELS) return;       /* HUDAQBADARG */\r
237         if (bit>=8) return;   //there are only 8 bits available in each channel in PCI1753\r
238 \r
239         DoutByte = (((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel]);\r
240         if (value) DoutByte |= (1<<bit);\r
241         else DoutByte &= ~(1<<bit);\r
242 \r
243         StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Ports[channel], DoutByte,\r
244                         & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel] );\r
245 }\r
246 \r
247 \r
248 static void PCI1753DOWriteMultipleBits(const DeviceRecord *DevRecord, unsigned channel, unsigned mask, unsigned value)\r
249 {\r
250         __int8 DoutByte;\r
251 \r
252         if (channel>=DO_CHANNELS) return;\r
253 \r
254         DoutByte = (((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel]);\r
255         DoutByte = (DoutByte & ~mask) | (value & mask);\r
256 \r
257         StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Ports[channel], DoutByte,\r
258                         & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->DoutCache[channel] );\r
259 }\r
260 \r
261 \r
262 static double PCI1753DIOGetParameter(unsigned channel, HudaqParameter param)\r
263 {\r
264         switch((int)param)\r
265         {\r
266                 case HudaqDINUMBITS:\r
267                         return (channel<DI_CHANNELS) ? 8 : WRONG_VALUE;\r
268                 case HudaqDONUMBITS:\r
269                         return (channel<DO_CHANNELS) ? 8 : WRONG_VALUE;\r
270                 case HudaqDINUMCHANNELS:\r
271                         return DI_CHANNELS;\r
272                 case HudaqDONUMCHANNELS:\r
273                         return DO_CHANNELS;\r
274         }\r
275 \r
276         return WRONG_VALUE;\r
277 }\r
278 \r
279 \r
280 static HUDAQSTATUS PCI1753DIOSetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, int value)\r
281 {\r
282         unsigned __int8 chval;\r
283 \r
284         switch((int)param)\r
285         {\r
286                 case HudaqDINUMBITS:\r
287                         if(channel>=DI_CHANNELS) return WRONG_VALUE;\r
288                         return (value==8) ? 0 : WRONG_VALUE;\r
289                 case HudaqDONUMBITS:\r
290                         if(channel>=DI_CHANNELS) return WRONG_VALUE;\r
291                         return (value==8) ? 0 : WRONG_VALUE;\r
292                 case HudaqDINUMCHANNELS:\r
293                         return DI_CHANNELS;\r
294                 case HudaqDONUMCHANNELS:\r
295                         return DO_CHANNELS;\r
296                 case HudaqDOMODE:\r
297                         if(channel>=DO_CHANNELS) return WRONG_VALUE;\r
298                         chval = ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->pconfig[channel/3];\r
299                         //printf("chval =  %d\n",chval);          \r
300                         switch(channel%3)\r
301                         {\r
302                                 case 0: if(value==1) chval &= ~0x10;\r
303                                                 if(value==0) chval |= 0x10;\r
304                                         break;\r
305                                 case 1: if(value==1) chval &= ~0x02;\r
306                                                 if(value==0) chval |= 0x02;\r
307                                         break;\r
308                                 case 2: if(value==1) chval &= ~0x0A;\r
309                                                 if(value==0) chval |= 0x0A;\r
310                                         break;\r
311                         }\r
312                         StoreCachedByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Cfg0+4*(channel/3), chval,\r
313                                         & ((PCI1753_Private *)(DevRecord->DrvRes.DriverData))->pconfig[channel/3] );\r
314                         return HUDAQSUCCESS;\r
315         }\r
316 \r
317         return WRONG_VALUE;\r
318 }\r
319 \r
320 /********************************************************************/\r
321 \r
322 /* Initialization procedure for AD612 card. */\r
323 static int InitPCI1753(DeviceRecord *DevRecord, int IniOptions)\r
324 {\r
325         PCI1753_Private *Cache;\r
326         int i;\r
327 \r
328         if (DevRecord==NULL) return -1;\r
329 \r
330         if (DevRecord->DrvRes.Resources.NumIOResources<1) return -2;  //insufficient amount of resources\r
331         Cache = DevRecord->DrvRes.DriverData;\r
332         if (Cache==NULL) return -3;\r
333         if (DevRecord->DrvRes.DriverDataSize<sizeof(PCI1753_Private)) return -4;\r
334 \r
335         DevRecord->pCT = &CTPCI1753;\r
336 \r
337         if ((IniOptions & HudaqOpenNOINIT)==0)\r
338         {                           //initialize hardware only if no other application is running\r
339                 /* Initialization of DI and DO. */\r
340                 Cache->InterruptControl[0] = 0x8A;      /* Clear ISRs */\r
341                 Cache->InterruptControl[1] = 0x80;\r
342                 Cache->InterruptControl[2] = 0x80;\r
343                 Cache->InterruptControl[3] = 0x80;\r
344                 for(i=0; i<4; i++)\r
345                         StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, IrqCtrR+i, Cache->InterruptControl[i]);\r
346 \r
347                 for(i=0; i<4; i++)\r
348                 {\r
349                         Cache->pconfig[i] = 0x1B;\r
350                         StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, Cfg0+4*i, Cache->pconfig[i]);\r
351                 }\r
352 \r
353                 Cache->PatternMatch = 0;\r
354                 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, PatternMatch, Cache->PatternMatch);\r
355                 Cache->PatternEnable = 0;\r
356                 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, PatternEnable, Cache->PatternEnable);\r
357                 Cache->ChangeEnableState = 0;\r
358                 StoreByte(DevRecord->DrvRes.Resources.IOResources[0].Base, ChEnableState, Cache->ChangeEnableState);\r
359         }\r
360 \r
361         return 1; //success\r
362 }\r
363 \r
364 /** Internal cleanup procedure for PCI1753 */\r
365 static void DonePCI1753(DeviceRecord *DevRecord)\r
366 {\r
367         if (DevRecord==NULL) return;\r
368 \r
369         DevRecord->pCT = &CtDummy;\r
370 }\r
371 \r
372 \r
373 \r
374 /****************************************************************\r
375  *                                                              *\r
376  *                    GET/SET PARAMETERS                        *\r
377  *                                                              *\r
378  ****************************************************************/\r
379 \r
380 static HUDAQSTATUS PCI1753SetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param, double value)\r
381 {\r
382         switch(param & HudaqSubsystemMASK)\r
383         {\r
384                 case HudaqDI:\r
385                 case HudaqDO:  return PCI1753DIOSetParameter(DevRecord,channel,param,value);\r
386                                //  case HudaqAI:  \r
387                                //  case HudaqAO:  \r
388                                //  case HudaqEnc: \r
389                                //  case HudaqPWM:\r
390                                //  case HudaqCtr: \r
391                                //  case HudaqStep:\r
392         }\r
393         return HUDAQNOTSUPPORTED;\r
394 }\r
395 \r
396 static double PCI1753GetParameter(const DeviceRecord *DevRecord, unsigned channel, HudaqParameter param)\r
397 {\r
398         switch(param & HudaqSubsystemMASK)\r
399         {\r
400                 case HudaqDI:\r
401                 case HudaqDO:  return PCI1753DIOGetParameter(channel,param);\r
402                                //case HudaqAI:  \r
403                                //case HudaqAO:  \r
404                                //case HudaqEnc:\r
405                                //case HudaqPWM:\r
406                                //case HudaqCtr:\r
407                                //case HudaqStep:\r
408         }\r
409         return WRONG_VALUE;\r
410 }\r
411 \r
412 \r
413 const CallTable CTPCI1753 =\r
414 {\r
415         "PCI1753", 0x13FE, 0x1753,\r
416         InitPCI1753,\r
417         DonePCI1753,\r
418 \r
419         PCI1753SetParameter,\r
420         PCI1753GetParameter,\r
421         NULL,\r
422 \r
423         // INITIALIZE DI callers\r
424         PCI1753DIRead,\r
425         GenericDIReadBit,           //Generic implementation\r
426         PCI1753DIReadMultiple,\r
427         // INITIALIZE DO callers\r
428         PCI1753DOWrite,\r
429         PCI1753DOWriteBit,\r
430         PCI1753DOWriteMultipleBits,\r
431         PCI1753DOWriteMultiple,\r
432         // INITIALIZE AI callers\r
433         NULL,\r
434         NULL,\r
435         // INITIALIZE AO callers\r
436         NULL,\r
437         NULL,\r
438         // INITIALIZE Enc callers\r
439         NULL,                       // Not available\r
440         NULL,\r
441         // INITIALIZE Ctr callers\r
442         NULL,                       // Not available\r
443         NULL,\r
444         // INITIALIZE PWM callers\r
445         NULL,                       // Not available\r
446         NULL,\r
447         NULL,\r
448         // INITIALIZE Step callers\r
449         NULL,                       // Not available\r
450 };\r
451 \r