Tizen 2.1 base
[platform/upstream/hplip.git] / scan / sane / scl.c
1 /************************************************************************************\
2
3   scl.c - HP SANE backend for multi-function peripherals (libsane-hpaio)
4
5   (c) 2001-2006 Copyright Hewlett-Packard Development Company, LP
6
7   Permission is hereby granted, free of charge, to any person obtaining a copy 
8   of this software and associated documentation files (the "Software"), to deal 
9   in the Software without restriction, including without limitation the rights 
10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
11   of the Software, and to permit persons to whom the Software is furnished to do 
12   so, subject to the following conditions:
13
14   The above copyright notice and this permission notice shall be included in all
15   copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
19   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
20   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
21   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24   Contributing Authors: David Paschal, Don Welch, David Suffield 
25
26 \************************************************************************************/
27
28 #include <errno.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include "hpmud.h"
32 #include "io.h"
33 #include "common.h"
34 #include "scl.h"
35 #include "hpaio.h"
36
37 #define DEBUG_DECLARE_ONLY
38 #include "sanei_debug.h"
39
40 static int SclBufferIsPartialReply( unsigned char * data, int datalen )
41 {
42     int i = 0, value = 0;
43     unsigned char d;  
44
45     if( i >= datalen )
46     {
47         return 0;
48     }
49     if( data[i++] != 27 )
50     {
51         return 0;
52     }
53     if( i >= datalen )
54     {
55         return 0;
56     }
57     if( data[i++] != '*' )
58     {
59         return 0;
60     }
61     if( i >= datalen )
62     {
63         return 0;
64     }
65     if( data[i++] != 's' )
66     {
67         return 0;
68     }
69     while( 42 )
70     {
71         if( i >= datalen )
72         {
73             return 0;
74         }
75         d = data[i] - '0';
76         if( d > 9 )
77         {
78             break;
79         }
80         i++;
81     }
82     d = data[i++];
83     if( d<'a' || d>'z' )
84     {
85         return 0;
86     }
87     while( 42 )
88     {
89         if( i >= datalen )
90         {
91             return 0;
92         }
93         d = data[i] - '0';
94         if( d > 9 )
95         {
96             break;
97         }
98         i++;
99         value = ( value * 10 ) + d;
100     }
101     if( i >= datalen )
102     {
103         return 0;
104     }
105     if( data[i++] != 'W' )
106     {
107         return 0;
108     }
109     value = i + value - datalen;
110     if( value < 0 )
111     {
112         value = 0;
113     }
114     return value;
115 }
116
117
118 static int SclChannelRead(int deviceid, int channelid, char * buffer, int countdown, int isSclResponse)
119 {
120     char * bufferStart = buffer;
121     int bufferLen = countdown, countup = 0, len;
122     enum HPMUD_RESULT stat;
123
124     if(!isSclResponse)
125     {
126         stat = hpmud_read_channel(deviceid, channelid, buffer, bufferLen, EXCEPTION_TIMEOUT, &len);  
127         return len;
128     }
129
130     while(1)
131     {
132         stat = hpmud_read_channel(deviceid, channelid, buffer, countdown, EXCEPTION_TIMEOUT, &len);                                      
133
134         if(stat != HPMUD_R_OK)
135         {
136             break;
137         }
138         countup += len;
139
140         countdown = SclBufferIsPartialReply( (unsigned char *)bufferStart, countup );
141         
142         if( countup + countdown > bufferLen )
143         {
144             countdown = bufferLen - countup;
145         }
146         if( countdown <= 0 )
147         {
148             break;
149         }
150
151         buffer += len;
152         //startTimeout = continueTimeout;
153     }
154
155     if(!countup)
156     {
157         return len;
158     }
159     return countup;
160
161 }
162
163 SANE_Status __attribute__ ((visibility ("hidden"))) SclSendCommand(int deviceid, int channelid, int cmd, int param)
164 {
165     char buffer[LEN_SCL_BUFFER];
166     int datalen, len;
167     char punc = SCL_CMD_PUNC( cmd );
168     char letter1 = SCL_CMD_LETTER1( cmd),letter2 = SCL_CMD_LETTER2( cmd );
169
170     if( cmd == SCL_CMD_RESET )
171     {
172         datalen = snprintf( buffer, LEN_SCL_BUFFER, "\x1B%c", letter2 );
173     }
174     else
175     {
176         if( cmd == SCL_CMD_CLEAR_ERROR_STACK )
177         {
178             datalen = snprintf( buffer,
179                                 LEN_SCL_BUFFER,
180                                 "\x1B%c%c%c",
181                                 punc,
182                                 letter1,
183                                 letter2 );
184         }
185         else
186         {
187             datalen = snprintf( buffer,
188                                 LEN_SCL_BUFFER,
189                                 "\x1B%c%c%d%c",
190                                 punc,
191                                 letter1,
192                                 param,
193                                 letter2 );
194         }
195     }
196
197     hpmud_write_channel(deviceid, channelid, buffer, datalen, EXCEPTION_TIMEOUT, &len);
198
199     DBG(6, "SclSendCommand: size=%d bytes_wrote=%d: %s %d\n", datalen, len, __FILE__, __LINE__);
200     if (DBG_LEVEL >= 6)
201        sysdump(buffer, datalen);
202
203     if(len != datalen)
204     {
205         return SANE_STATUS_IO_ERROR;
206     }
207
208     return SANE_STATUS_GOOD;
209 }
210
211 SANE_Status __attribute__ ((visibility ("hidden"))) SclInquire(int deviceid, int channelid, int cmd, int param, int * pValue, char * buffer, int maxlen)
212 {
213     SANE_Status retcode;
214     int lenResponse, len, value;
215     char _response[LEN_SCL_BUFFER + 1], * response = _response;
216     char expected[LEN_SCL_BUFFER], expectedChar;
217
218     if( !pValue )
219     {
220         pValue = &value;
221     }
222     if( buffer && maxlen > 0 )
223     {
224         memset( buffer, 0, maxlen );
225     }
226     memset( _response, 0, LEN_SCL_BUFFER + 1 );
227
228     /* Send inquiry command. */
229     if( ( retcode = SclSendCommand( deviceid, channelid, cmd, param ) ) != SANE_STATUS_GOOD )
230     {
231         return retcode;
232     }
233
234     /* Figure out what format of response we expect. */
235     expectedChar = SCL_CMD_LETTER2( cmd ) - 'A' + 'a' - 1;
236     if( expectedChar == 'q' )
237     {
238         expectedChar--;
239     }
240     len = snprintf( expected,
241                     LEN_SCL_BUFFER,
242                     "\x1B%c%c%d%c",
243                     SCL_CMD_PUNC( cmd ),
244                     SCL_CMD_LETTER1( cmd ),
245                     param,
246                     expectedChar );
247
248     /* Read the response. */
249     lenResponse = SclChannelRead( deviceid, channelid, response, LEN_SCL_BUFFER, 1 );
250                                       
251     DBG(6, "SclChannelRead: len=%d: %s %d\n", lenResponse, __FILE__, __LINE__);
252     if (DBG_LEVEL >= 6)
253        sysdump(response, lenResponse);
254
255     /* Validate the first part of the response. */
256     if( lenResponse <= len || memcmp( response, expected, len ) )
257     {
258         bug("invalid SclInquire(cmd=%x,param=%d) exp(len=%d)/act(len=%d): %s %d\n", cmd, param, len, lenResponse, __FILE__, __LINE__);
259         bug("exp:\n");
260         bugdump(expected, len);
261         bug("act:\n");
262         bugdump(response, lenResponse);
263         return SANE_STATUS_IO_ERROR;
264     }
265     response += len;
266     lenResponse -= len;
267
268     /* Null response? */
269     if( response[0] == 'N' )
270     {
271         DBG(6, "SclInquire null response. %s %d\n", __FILE__, __LINE__);
272         return SANE_STATUS_UNSUPPORTED;
273     }
274
275     /* Parse integer part of non-null response.
276      * If this is a binary-data response, then this value is the
277      * length of the binary-data portion. */
278     if( sscanf( response, "%d%n", pValue, &len ) != 1 )
279     {
280         bug("invalid SclInquire(cmd=%x,param=%d) integer response: %s %d\n", cmd, param, __FILE__, __LINE__);
281         return SANE_STATUS_IO_ERROR;
282     }
283
284     /* Integer response? */
285     if( response[len] == 'V' )
286     {
287         return SANE_STATUS_GOOD;
288     }
289
290     /* Binary-data response? */
291     if( response[len] != 'W' )
292     {
293         bug("invalid SclInquire(cmd=%x,param=%d) unexpected character '%c': %s %d\n", cmd, param, response[len], __FILE__, __LINE__);
294         return SANE_STATUS_IO_ERROR;
295     }
296     response += len + 1;
297     lenResponse -= len + 1;
298
299     /* Make sure we got the right length of binary data. */
300     if( lenResponse<0 || lenResponse != *pValue || lenResponse>maxlen )
301     {
302         bug("invalid SclInquire(cmd=%x,param=%d) binary data lenResponse=%d *pValue=%d maxlen=%d: %s %d\n", 
303                              cmd, param, lenResponse, *pValue, maxlen, __FILE__, __LINE__);
304         return SANE_STATUS_IO_ERROR;
305     }
306
307     /* Copy binary data into user's buffer. */
308     if( buffer )
309     {
310         maxlen = *pValue;
311         memcpy( buffer, response, maxlen );
312     }
313
314     return SANE_STATUS_GOOD;
315 }
316
317 /*
318  * Phase 2 partial rewrite. des 9/26/07
319  */
320
321 SANE_Status __attribute__ ((visibility ("hidden"))) scl_send_cmd(HPAIO_RECORD *hpaio, const char *buf, int size)
322 {
323     int len;
324     
325     hpmud_write_channel(hpaio->deviceid, hpaio->scan_channelid, buf, size, EXCEPTION_TIMEOUT, &len);
326
327     DBG(6, "scl cmd sent size=%d bytes_wrote=%d: %s %d\n", size, len, __FILE__, __LINE__);
328     if (DBG_LEVEL >= 6)
329        sysdump(buf, size);
330
331     if(len != size)
332     {
333         return SANE_STATUS_IO_ERROR;
334     }
335
336     return SANE_STATUS_GOOD;
337 }
338
339 SANE_Status __attribute__ ((visibility ("hidden"))) scl_query_int(HPAIO_RECORD *hpaio, const char *buf, int size, int *result)
340 {
341     char rbuf[256];
342     int len, stat;
343     char *tail;
344
345     *result=0;
346
347     if ((stat = scl_send_cmd(hpaio, buf, size)) != SANE_STATUS_GOOD)
348     {
349         return stat;
350     }
351
352     if ((stat = hpmud_read_channel(hpaio->deviceid, hpaio->scan_channelid, rbuf, sizeof(rbuf), EXCEPTION_TIMEOUT, &len)) != HPMUD_R_OK)
353     {
354         return SANE_STATUS_IO_ERROR;
355     }
356
357     DBG(6, "scl response size=%d: %s %d\n", len, __FILE__, __LINE__);
358     if (DBG_LEVEL >= 6)
359        sysdump(buf, size);
360
361     /* Null response? */
362     if(rbuf[len-1] == 'N')
363     {
364         DBG(6, "scl null response: %s %d\n", __FILE__, __LINE__);
365         return SANE_STATUS_UNSUPPORTED;
366     }
367         
368     /* Integer response? */
369     if(rbuf[len-1] != 'V' )
370     {
371         bug("invalid scl integer response: %s %d\n", __FILE__, __LINE__);
372         return SANE_STATUS_IO_ERROR;
373     }
374
375     *result = strtol(&rbuf[size], &tail, 10);
376
377     return SANE_STATUS_GOOD;
378 }
379