Semistubs for _ismbcdigit,_ismbcspace,_mbslwr,_mbsnbcmp,_mbsspn.
[wine] / msdos / ppdev.c
1 /*
2  * Parallel-port device support
3  */
4
5 #include "config.h"
6
7 #include "debugtools.h"
8
9 DEFAULT_DEBUG_CHANNEL(int);
10
11 #ifdef  HAVE_PPDEV
12
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <sys/ioctl.h>
18 #include <errno.h>
19 #include <linux/ppdev.h>
20
21 #include "winerror.h"
22 #include "winreg.h"
23
24
25 typedef struct _PPDEVICESTRUCT{
26   int fd; /* NULL if device not available */
27   char *devicename;
28   int userbase; /* where wine thinks the ports are*/
29   DWORD lastaccess; /* or NULL if release */
30   int timeout; /* time in second of inactivity to release the port*/
31 } PPDeviceStruct;
32
33 static PPDeviceStruct PPDeviceList[5];
34 static int PPDeviceNum=0;
35
36 static int IO_pp_sort(const void *p1,const  void *p2)
37 {
38   return ((PPDeviceStruct*)p1)->userbase - ((PPDeviceStruct*)p2)->userbase;
39 }
40
41 /* IO_pp_init 
42  *
43  * Read the ppdev entries from wine.conf, open the device and check
44  * for nescessary IOCTRL
45  * Report verbose about possible errors
46  */
47 char IO_pp_init(void)
48 {
49     char name[80];
50     char buffer[1024];
51     HKEY hkey;
52     char temp[256];
53     int i,idx=0,fd,res,userbase,nports=0;
54     char * timeout;
55     char ret=1;
56     int lasterror;
57
58     TRACE("\n");
59     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppdev", &hkey ) != ERROR_SUCCESS)
60       return 1;
61
62     for (;;)
63     {
64         DWORD type, count = sizeof(buffer), name_len = sizeof(name);
65
66         if (RegEnumValueA( hkey, idx, name, &name_len, NULL, &type, buffer, &count )!= ERROR_SUCCESS) 
67           break;
68         
69         idx++;
70         if(nports >4)
71           {
72             FIXME("Make the PPDeviceList larger then 5 elements\n");
73             break;
74           }
75         TRACE("Device '%s' at virtual userbase '%s'\n", buffer,name);
76         timeout = strchr(buffer,',');
77         if (timeout)
78           *timeout++=0;
79         fd=open(buffer,O_RDWR);
80         lasterror=errno;
81         if (fd == -1)
82           {
83             WARN("Configuration: No access to %s Cause: %s\n",buffer,strerror(lasterror));
84             WARN("Rejecting configuration item\n");
85             if (lasterror == ENODEV)
86               FIXME("Is the ppdev module loaded?\n");
87             continue;
88           }
89         userbase = strtol(name,(char **)NULL, 16);
90         if ( errno == ERANGE)
91           {
92             WARN("Configuration: Invalid base %s for %s\n",name,buffer);
93             WARN("Rejecting configuration item\n");
94             continue;
95           }
96         if (ioctl (fd,PPEXCL,0)) 
97           {
98             ERR("PPEXCL IOCTL rejected for device %s\n",buffer);
99             ERR("Check that PPDEV module is loaded!\n");
100             ERR("Perhaps the device is already in use or non-existant\n");
101             continue;
102           }
103         if (ioctl (fd,PPCLAIM,0)) 
104           {
105             ERR("PPCLAIM rejected %s\n",buffer);
106             ERR("Perhaps the device is already in use or non-existant\n");
107             continue;
108           }
109         if (nports > 0)
110           {
111             for (i=0; i<= nports; i++)
112               {
113                 if (PPDeviceList[i].userbase == userbase)
114                   {
115                     WARN("Configuration: %s uses the same virtual ports as %s\n",
116                          buffer,PPDeviceList[0].devicename);
117                     WARN("Configuration: Rejecting configuration item");
118                     userbase = 0;
119                     break;
120                   }
121               }
122             if (!userbase) continue;
123           }
124         /* Check for the minimum required IOCTLS */
125         if ((ioctl(fd,PPRDATA,&res))||
126             (ioctl(fd,PPRCONTROL,&res))||
127             (ioctl(fd,PPRCONTROL,&res)))
128           {
129             ERR("PPUSER IOCTL not available for parport device %s\n",temp);
130             continue;
131           }
132         PPDeviceList[nports].devicename = malloc(sizeof(buffer)+1);
133         if (!PPDeviceList[nports].devicename)
134           {
135             ERR("No (more)space for devicename\n");
136             break;
137           }
138         strcpy(PPDeviceList[nports].devicename,buffer);
139         PPDeviceList[nports].fd = fd;
140         PPDeviceList[nports].userbase = userbase;
141         PPDeviceList[nports].lastaccess=GetTickCount();
142         if (timeout)
143           {
144             PPDeviceList[nports].timeout = strtol(timeout,(char **)NULL, 10);
145             if (errno == ERANGE)
146               {
147                 WARN("Configuration:Invalid timeout %s in configuration for %s, Setting to 0\n",
148                      timeout,buffer);
149                 PPDeviceList[nports].timeout = 0;
150               }
151           }
152         else
153           PPDeviceList[nports].timeout = 0;
154         nports++;
155     }
156     TRACE("found %d ports\n",nports);
157     RegCloseKey( hkey );
158
159     PPDeviceNum= nports;
160     if (nports > 1)
161       /* sort in accending order for userbase for faster access*/
162       qsort (PPDeviceList,PPDeviceNum,sizeof(PPDeviceStruct),IO_pp_sort);
163     
164     if (nports)
165       ret=0;
166     for (idx= 0;idx<PPDeviceNum; idx++)
167       TRACE("found device %s userbase %x fd %x timeout %d\n",
168             PPDeviceList[idx].devicename, PPDeviceList[idx].userbase,
169             PPDeviceList[idx].fd,PPDeviceList[idx].timeout);
170     /* FIXME:
171        register a timer callback perhaps every 30 second to release unused ports
172        Set lastaccess = 0 as indicator when port was released
173     */
174     return ret;
175 }
176
177 /* IO_pp_do_access
178  *
179  * Do the actual IOCTL
180  * Return NULL on success
181  */
182 static int IO_pp_do_access(int idx,int ppctl, DWORD* res)
183 {
184     if (!PPDeviceList[idx].lastaccess)
185       /* TIMER callback has released the device after some time of inactivity
186           Reclaim the device
187           !!!!!!THIS MAY UNINTERRUPTIPLE BLOCK IF SOME OTHER DEVICE
188            !!!!!! HAS CLAIMED THE SAME PORT
189       */
190       if (ioctl(PPDeviceList[idx].fd,PPCLAIM,0))
191        {
192          ERR("Can't reclaim device %s, PPUSER/PPDEV handling confused\n",
193              PPDeviceList[idx].devicename);
194          return 1;
195        }
196     PPDeviceList[idx].lastaccess=GetTickCount();
197     return ioctl(PPDeviceList[idx].fd,ppctl,res);
198 }
199
200 /* IO_pp_inp
201  *
202  * Check if we can satisfy the INP command with some of the configured PPDEV deviced
203  * Return NULL on success
204  */
205 int IO_pp_inp(int port, DWORD* res)
206 {
207     int idx,j=0;
208     
209     for (idx=0;idx<PPDeviceNum ;idx++)
210       {
211        j = port - PPDeviceList[idx].userbase;
212        if (j <0) return 1;
213        switch (j)
214          {
215          case 0:
216            return IO_pp_do_access(idx,PPRDATA,res);
217          case 1:
218            return IO_pp_do_access(idx,PPRSTATUS,res);
219          case 2:
220            return IO_pp_do_access(idx,PPRCONTROL,res);
221          case 0x400:
222          case 0x402:
223          case 3:
224          case 4:
225          case 0x401:
226            FIXME("Port 0x%x not accessible for reading with ppdev\n",port);
227            FIXME("If this is causing problems, try direct port access\n");
228            return 1;
229          default:
230            break;
231          }
232       }
233     return 1;
234 }
235
236 /* IO_pp_outp
237  *
238  * Check if we can satisfy the INP command with some of the configured PPDEV deviced
239  * Return NULL on success
240  */
241 BOOL IO_pp_outp(int port, DWORD* res)
242 {
243     int idx,j=0;
244     
245     for (idx=0;idx<PPDeviceNum ;idx++)
246       {
247        j = port - PPDeviceList[idx].userbase;
248        if (j <0) return 1;
249        switch (j)
250          {
251          case 0:
252            return IO_pp_do_access(idx,PPWDATA,res);
253          case 2:
254            return IO_pp_do_access(idx,PPWCONTROL,res);
255          case 1:
256          case 0x400:
257          case 0x402:
258          case 3:
259          case 4:
260          case 0x401:
261            FIXME("Port %d not accessible for writing with ppdev\n",port);
262            FIXME("If this is causing problems, try direct port access\n");
263            return 1;
264          default:
265            break;
266          }
267       }
268     return TRUE;
269 }
270
271
272 #else /* HAVE_PPDEV */
273
274 char IO_pp_init(void)
275 {
276   return 1;
277 }
278
279 int IO_pp_inp(int port, DWORD* res)
280 {
281   return 1;
282 }
283
284 BOOL IO_pp_outp(int port, DWORD* res)
285 {
286   return TRUE;
287 }
288 #endif  /* HAVE_PPDEV */