1 /*
2 Snapscan 1212U modifications for the Snapscan SANE backend
3
4 Copyright (C) 2000 Henrik Johansson
5
6 Henrik Johansson (henrikjo@post.urfors.se)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>.
20
21 As a special exception, the authors of SANE give permission for
22 additional uses of the libraries contained in this release of SANE.
23
24 The exception is that, if you link a SANE library with other files
25 to produce an executable, this does not by itself cause the
26 resulting executable to be covered by the GNU General Public
27 License. Your use of that executable is in no way restricted on
28 account of linking the SANE library code into it.
29
30 This exception does not, however, invalidate any other reasons why
31 the executable file might be covered by the GNU General Public
32 License.
33
34 If you submit changes to SANE to the maintainers to be included in
35 a subsequent release, you agree by submitting the changes that
36 those changes may be distributed with this exception intact.
37
38 If you write modifications of your own for SANE, it is your choice
39 whether to permit this exception to apply to your modifications.
40 If you do not wish that, delete this exception notice.
41
42 This file implements USB equivalents to the SCSI routines used by the Snapscan
43 backend.
44
45 History
46
47 0.1 2000-02-01
48
49 First version released
50
51 0.2 2000-02-12
52
53 The Send Diagnostics SCSI command seems to hang some 1212U scanners.
54 Bypassing this command fixes the problem. This bug was reported by
55 Dmitri (dmitri@advantrix.com).
56
57 0.3 2000-02-13
58
59 The "Set window" command returns with status "Device busy" when the
60 scanner is busy. One consequence is that some frontends exits with an
61 error message if it's started when the scanner is warming up.
62 A solution was suggested by Dmitri (dmitri@advantrix.com)
63 The idea is that a SCSI command which returns "device busy" is stored
64 in a "TODO" queue. The send command function is modified to first send
65 commands in the queue before the intended command.
66 So far this strategy has worked flawlessly. Thanks Dmitri!
67 */
68
69 /*
70 SnapScan backend scan data sources
71 */
72
73 #include "snapscan-usb.h"
74 #include "snapscan-mutex.c"
75
76 #ifndef SHM_R
77 #define SHM_R 0
78 #endif
79
80 #ifndef SHM_W
81 #define SHM_W 0
82 #endif
83
84 /* Global variables */
85
86 static snapscan_mutex_t snapscan_mutex;
87 static sense_handler_type usb_sense_handler;
88 static void* usb_pss;
89
90 struct urb_counters_t {
91 unsigned long read_urbs;
92 unsigned long write_urbs;
93 };
94
95 static struct urb_counters_t* urb_counters = NULL;
96
97 /* Forward declarations */
98 static SANE_Status usb_request_sense(SnapScan_Scanner *pss);
99
snapscani_usb_cmd(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size)100 static SANE_Status snapscani_usb_cmd(int fd, const void *src, size_t src_size,
101 void *dst, size_t * dst_size)
102 {
103 static const char me[] = "snapscani_usb_cmd";
104 int status;
105
106 DBG (DL_CALL_TRACE, "%s(%d,0x%lx,%lu,0x%lx,0x%lx (%lu))\n", me,
107 fd, (u_long) src,(u_long) src_size,(u_long) dst, (u_long) dst_size,(u_long) (dst_size ? *dst_size : 0));
108
109 while(bqhead) {
110 status = atomic_usb_cmd(fd, bqhead->src, bqhead->src_size, NULL, NULL);
111 if(status == SANE_STATUS_DEVICE_BUSY) {
112 if(is_queueable(src)) {
113 enqueue_bq(fd,src,src_size);
114 return SANE_STATUS_GOOD;
115 } else {
116 sleep(1);
117 continue;
118 }
119 }
120 dequeue_bq();
121 }
122
123 status = atomic_usb_cmd(fd,src,src_size,dst,dst_size);
124
125 if ((status == SANE_STATUS_DEVICE_BUSY) && is_queueable(src) ) {
126 enqueue_bq(fd,src,src_size);
127 return SANE_STATUS_GOOD;
128 }
129
130 return status;
131 }
132
atomic_usb_cmd(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size)133 static SANE_Status atomic_usb_cmd(int fd, const void *src, size_t src_size,
134 void *dst, size_t * dst_size)
135 {
136 static const char me[] = "atomic_usb_cmd";
137
138 int status;
139 sigset_t all,oldset;
140
141 DBG (DL_CALL_TRACE, "%s(%d,0x%lx,%lu,0x%lx,0x%lx (%lu))\n", me,
142 fd, (u_long) src,(u_long) src_size,(u_long) dst, (u_long) dst_size,(u_long) (dst_size ? *dst_size : 0));
143
144 /* Prevent the calling process from being killed */
145 sigfillset(&all);
146 sigprocmask(SIG_BLOCK, &all, &oldset);
147
148 /* Make sure we are alone */
149 snapscani_mutex_lock(&snapscan_mutex);
150
151 status = usb_cmd(fd,src,src_size,dst,dst_size);
152
153 snapscani_mutex_unlock(&snapscan_mutex);
154
155 /* Now it is ok to be killed */
156 sigprocmask(SIG_SETMASK, &oldset, NULL);
157
158 return status;
159
160 }
161
snapscani_usb_open(const char * dev,int * fdp,sense_handler_type sense_handler,void * pss)162 static SANE_Status snapscani_usb_open(const char *dev, int *fdp,
163 sense_handler_type sense_handler, void* pss)
164 {
165 static const char me[] = "snapscani_usb_open";
166
167 DBG (DL_CALL_TRACE, "%s(%s)\n", me, dev);
168
169 if(!snapscani_mutex_open(&snapscan_mutex, dev)) {
170 DBG (DL_MAJOR_ERROR, "%s: Can't get semaphore\n", me);
171 return SANE_STATUS_INVAL;
172 }
173 usb_sense_handler=sense_handler;
174 usb_pss = pss;
175 urb_counters->read_urbs = 0;
176 urb_counters->write_urbs = 0;
177 return sanei_usb_open(dev, fdp);
178 }
179
180
snapscani_usb_close(int fd)181 static void snapscani_usb_close(int fd) {
182 static const char me[] = "snapscani_usb_close";
183 SANE_Word vendor_id, product_id;
184
185 DBG (DL_CALL_TRACE, "%s(%d)\n", me, fd);
186 DBG (DL_DATA_TRACE,"1st read %ld write %ld\n", urb_counters->read_urbs, urb_counters->write_urbs);
187
188 /* Check if URB counting is needed. If yes, ensure the number of sent and
189 received URBs is even.
190 Odd number of URBs only cause problems with libusb and certain
191 scanner models. On other scanner models, sending additional commands
192 seems to cause problems (e.g. 1212u_2).
193 If sanei_usb_get_vendor_product returns an error there's probably no
194 libusb, so everything's fine.
195 */
196 if (sanei_usb_get_vendor_product(fd, &vendor_id, &product_id) == SANE_STATUS_GOOD)
197 {
198 /* Exclude 1212u_2 */
199 if (!((vendor_id == USB_VENDOR_AGFA) && (product_id == USB_PRODUCT_1212U2)))
200 {
201 if ((urb_counters->read_urbs & 0x01) && (urb_counters->write_urbs & 0x01))
202 {
203 char cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
204
205 snapscani_usb_cmd (fd, cmd, sizeof (cmd), NULL, 0);
206 }
207 else if (urb_counters->read_urbs & 0x01)
208 {
209 size_t read_bytes;
210 char cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
211 char cmd2[] = {INQUIRY, 0, 0, 0, 120, 0};
212 char data[120];
213
214 read_bytes = 120;
215 snapscani_usb_cmd (fd, cmd2, sizeof (cmd2), data, &read_bytes);
216 snapscani_usb_cmd (fd, cmd, sizeof (cmd), NULL, 0);
217 }
218 else if (urb_counters->write_urbs & 0x01)
219 {
220 size_t read_bytes;
221 char cmd[] = {INQUIRY, 0, 0, 0, 120, 0};
222 char data[120];
223
224 read_bytes = 120;
225 snapscani_usb_cmd (fd, cmd, sizeof (cmd), data, &read_bytes);
226 }
227 DBG (DL_DATA_TRACE,"2nd read %ld write %ld\n", urb_counters->read_urbs,
228 urb_counters->write_urbs);
229 }
230 }
231 urb_counters->read_urbs = 0;
232 urb_counters->write_urbs = 0;
233 snapscani_mutex_close(&snapscan_mutex);
234 sanei_usb_close(fd);
235 }
236
usb_cmdlen(int cmd)237 static int usb_cmdlen(int cmd)
238 {
239 switch(cmd) {
240 case TEST_UNIT_READY:
241 case INQUIRY:
242 case SCAN:
243 case REQUEST_SENSE:
244 case RESERVE_UNIT:
245 case RELEASE_UNIT:
246 case SEND_DIAGNOSTIC:
247 return 6;
248 case SEND:
249 case SET_WINDOW:
250 case READ:
251 case GET_DATA_BUFFER_STATUS:
252 return 10;
253 }
254 return 0;
255 }
256
usb_debug_data(char * str,const char * data,int len)257 static char *usb_debug_data(char *str,const char *data, int len) {
258 char tmpstr[10];
259 int i;
260
261 str[0]=0;
262 for(i=0; i < (len < 10 ? len : 10); i++) {
263 sprintf(tmpstr," 0x%02x",((int)data[i]) & 0xff);
264 if(i%16 == 0 && i != 0)
265 strcat(str,"\n");
266 strcat(str,tmpstr);
267 }
268 if(i < len)
269 strcat(str," ...");
270 return str;
271 }
272
273 #define RETURN_ON_FAILURE(x) if((status = x) != SANE_STATUS_GOOD) return status;
274
usb_write(int fd,const void * buf,size_t n)275 static SANE_Status usb_write(int fd, const void *buf, size_t n) {
276 char dbgmsg[16384];
277 SANE_Status status;
278 size_t bytes_written = n;
279
280 static const char me[] = "usb_write";
281 DBG(DL_DATA_TRACE, "%s: writing: %s\n",me,usb_debug_data(dbgmsg,buf,n));
282
283 status = sanei_usb_write_bulk(fd, (const SANE_Byte*)buf, &bytes_written);
284 if(bytes_written != n) {
285 DBG (DL_MAJOR_ERROR, "%s Only %lu bytes written\n",me, (u_long) bytes_written);
286 status = SANE_STATUS_IO_ERROR;
287 }
288 urb_counters->write_urbs += (bytes_written + 7) / 8;
289 DBG (DL_DATA_TRACE, "Written %lu bytes\n", (u_long) bytes_written);
290 return status;
291 }
292
usb_read(SANE_Int fd,void * buf,size_t n)293 static SANE_Status usb_read(SANE_Int fd, void *buf, size_t n) {
294 char dbgmsg[16384];
295 static const char me[] = "usb_read";
296 SANE_Status status;
297 size_t bytes_read = n;
298
299 status = sanei_usb_read_bulk(fd, (SANE_Byte*)buf, &bytes_read);
300 if (bytes_read != n) {
301 DBG (DL_MAJOR_ERROR, "%s Only %lu bytes read\n",me, (u_long) bytes_read);
302 status = SANE_STATUS_IO_ERROR;
303 }
304 urb_counters->read_urbs += ((63 + bytes_read) / 64);
305 DBG(DL_DATA_TRACE, "%s: reading: %s\n",me,usb_debug_data(dbgmsg,buf,n));
306 DBG(DL_DATA_TRACE, "Read %lu bytes\n", (u_long) bytes_read);
307 return status;
308 }
309
usb_read_status(int fd,int * scsistatus,int * transaction_status,char command)310 static SANE_Status usb_read_status(int fd, int *scsistatus, int *transaction_status,
311 char command)
312 {
313 static const char me[] = "usb_read_status";
314 unsigned char status_buf[8];
315 int scsistat;
316 int status;
317
318 RETURN_ON_FAILURE(usb_read(fd,status_buf,8));
319
320 if(transaction_status)
321 *transaction_status = status_buf[0];
322
323 scsistat = (status_buf[1] & STATUS_MASK) >> 1;
324
325 if(scsistatus)
326 *scsistatus = scsistat;
327
328 switch(scsistat) {
329 case GOOD:
330 return SANE_STATUS_GOOD;
331 case CHECK_CONDITION:
332 if (usb_pss != NULL) {
333 if (command != REQUEST_SENSE) {
334 return usb_request_sense(usb_pss);
335 }
336 else {
337 /* Avoid recursive calls of usb_request_sense */
338 return SANE_STATUS_GOOD;
339 }
340 } else {
341 DBG (DL_MAJOR_ERROR, "%s: scanner structure not set, returning default error\n",
342 me);
343 return SANE_STATUS_DEVICE_BUSY;
344 }
345 break;
346 case BUSY:
347 return SANE_STATUS_DEVICE_BUSY;
348 default:
349 return SANE_STATUS_IO_ERROR;
350 }
351 }
352
353
usb_cmd(int fd,const void * src,size_t src_size,void * dst,size_t * dst_size)354 static SANE_Status usb_cmd(int fd, const void *src, size_t src_size,
355 void *dst, size_t * dst_size)
356 {
357 static const char me[] = "usb_cmd";
358 int status,tstatus;
359 int cmdlen,datalen;
360 char command;
361
362 DBG (DL_CALL_TRACE, "%s(%d,0x%lx,%lu,0x%lx,0x%lx (%lu))\n", me,
363 fd, (u_long) src,(u_long) src_size,(u_long) dst, (u_long) dst_size,(u_long) (dst_size ? *dst_size : 0));
364
365 /* Since the "Send Diagnostic" command isn't supported by
366 all Snapscan USB-scanners it's disabled .
367 */
368 command = ((const char *)src)[0];
369 if(command == SEND_DIAGNOSTIC)
370 return(SANE_STATUS_GOOD);
371
372 cmdlen = usb_cmdlen(*((const char *)src));
373 datalen = src_size - cmdlen;
374
375 DBG(DL_DATA_TRACE, "%s: cmdlen=%d, datalen=%d\n",me,cmdlen,datalen);
376
377 /* Send command to scanner */
378 RETURN_ON_FAILURE( usb_write(fd,src,cmdlen) );
379
380 /* Read status */
381 RETURN_ON_FAILURE( usb_read_status(fd, NULL, &tstatus, command) );
382
383 /* Send data only if the scanner is expecting it */
384 if(datalen > 0 && (tstatus == TRANSACTION_WRITE)) {
385 /* Send data to scanner */
386 RETURN_ON_FAILURE( usb_write(fd, ((const SANE_Byte *) src) + cmdlen, datalen) );
387
388 /* Read status */
389 RETURN_ON_FAILURE( usb_read_status(fd, NULL, &tstatus, command) );
390 }
391
392 /* Receive data only when new data is waiting */
393 if(dst_size && *dst_size && (tstatus == TRANSACTION_READ)) {
394 RETURN_ON_FAILURE( usb_read(fd,dst,*dst_size) );
395
396 /* Read status */
397 RETURN_ON_FAILURE( usb_read_status(fd, NULL, &tstatus, command) );
398 }
399
400 if(tstatus != TRANSACTION_COMPLETED) {
401 if(tstatus == TRANSACTION_WRITE)
402 DBG(DL_MAJOR_ERROR,
403 "%s: The transaction should now be completed, but the scanner is expecting more data" ,me);
404 else
405 DBG(DL_MAJOR_ERROR,
406 "%s: The transaction should now be completed, but the scanner has more data to send" ,me);
407 return SANE_STATUS_IO_ERROR;
408 }
409
410 return status;
411 }
412
413 /* Busy queue data structures and function implementations*/
414
is_queueable(const char * src)415 static int is_queueable(const char *src)
416 {
417 switch(src[0]) {
418 case SEND:
419 case SET_WINDOW:
420 case SEND_DIAGNOSTIC:
421 return 1;
422 default:
423 return 0;
424 }
425 }
426
427 static struct usb_busy_queue *bqhead=NULL,*bqtail=NULL;
428 static int bqelements=0;
429
enqueue_bq(int fd,const void * src,size_t src_size)430 static int enqueue_bq(int fd,const void *src, size_t src_size)
431 {
432 static const char me[] = "enqueue_bq";
433 struct usb_busy_queue *bqe;
434
435 DBG (DL_CALL_TRACE, "%s(%d,%p,%lu)\n", me, fd,src, (u_long) src_size);
436
437 if((bqe = malloc(sizeof(struct usb_busy_queue))) == NULL)
438 return -1;
439
440 if((bqe->src = malloc(src_size)) == NULL)
441 return -1;
442
443 memcpy(bqe->src,src,src_size);
444 bqe->src_size=src_size;
445
446 bqe->next=NULL;
447
448 if(bqtail) {
449 bqtail->next=bqe;
450 bqtail = bqe;
451 } else
452 bqhead = bqtail = bqe;
453
454 bqelements++;
455 DBG(DL_DATA_TRACE, "%s: Busy queue: elements=%d, bqhead=%p, bqtail=%p\n",
456 me,bqelements,(void*)bqhead,(void*)bqtail);
457 return 0;
458 }
459
dequeue_bq()460 static void dequeue_bq()
461 {
462 static const char me[] = "dequeue_bq";
463 struct usb_busy_queue *tbqe;
464
465 DBG (DL_CALL_TRACE, "%s()\n", me);
466
467 if(!bqhead)
468 return;
469
470 tbqe = bqhead;
471 bqhead = bqhead->next;
472 if(!bqhead)
473 bqtail=NULL;
474
475 if(tbqe->src)
476 free(tbqe->src);
477 free(tbqe);
478
479 bqelements--;
480 DBG(DL_DATA_TRACE, "%s: Busy queue: elements=%d, bqhead=%p, bqtail=%p\n",
481 me,bqelements,(void*)bqhead,(void*)bqtail);
482 }
483
usb_request_sense(SnapScan_Scanner * pss)484 static SANE_Status usb_request_sense(SnapScan_Scanner *pss) {
485 static const char *me = "usb_request_sense";
486 size_t read_bytes = 0;
487 u_char cmd[] = {REQUEST_SENSE, 0, 0, 0, 20, 0};
488 u_char data[20];
489 SANE_Status status;
490
491 read_bytes = 20;
492
493 DBG (DL_CALL_TRACE, "%s\n", me);
494 status = usb_cmd (pss->fd, cmd, sizeof (cmd), data, &read_bytes);
495 if (status != SANE_STATUS_GOOD)
496 {
497 DBG (DL_MAJOR_ERROR, "%s: usb command error: %s\n",
498 me, sane_strstatus (status));
499 }
500 else
501 {
502 if (usb_sense_handler) {
503 status = usb_sense_handler (pss->fd, data, (void *) pss);
504 } else {
505 DBG (DL_MAJOR_ERROR, "%s: No sense handler for USB\n", me);
506 status = SANE_STATUS_UNSUPPORTED;
507 }
508 }
509 return status;
510 }
511
512 #if defined USE_PTHREAD || defined HAVE_OS2_H || defined __BEOS__
snapscani_usb_shm_init(void)513 static SANE_Status snapscani_usb_shm_init(void)
514 {
515 unsigned int shm_size = sizeof(struct urb_counters_t);
516 urb_counters = (struct urb_counters_t*) malloc(shm_size);
517 if (urb_counters == NULL)
518 {
519 return SANE_STATUS_NO_MEM;
520 }
521 memset(urb_counters, 0, shm_size);
522 return SANE_STATUS_GOOD;
523
524 }
525
snapscani_usb_shm_exit(void)526 static void snapscani_usb_shm_exit(void)
527 {
528 if (urb_counters)
529 {
530 free ((void*)urb_counters);
531 urb_counters = NULL;
532 }
533 }
534 #else
535 #include <sys/ipc.h>
536 #include <sys/shm.h>
snapscani_usb_shm_init(void)537 static SANE_Status snapscani_usb_shm_init(void)
538 {
539 unsigned int shm_size = sizeof(struct urb_counters_t);
540 void* shm_area = NULL;
541 int shm_id = shmget (IPC_PRIVATE, shm_size, IPC_CREAT | SHM_R | SHM_W);
542 if (shm_id == -1)
543 {
544 DBG (DL_MAJOR_ERROR, "snapscani_usb_shm_init: cannot create shared memory segment: %s\n",
545 strerror (errno));
546 return SANE_STATUS_NO_MEM;
547 }
548
549 shm_area = shmat (shm_id, NULL, 0);
550 if (shm_area == (void *) -1)
551 {
552 DBG (DL_MAJOR_ERROR, "snapscani_usb_shm_init: cannot attach to shared memory segment: %s\n",
553 strerror (errno));
554 shmctl (shm_id, IPC_RMID, NULL);
555 return SANE_STATUS_NO_MEM;
556 }
557
558 if (shmctl (shm_id, IPC_RMID, NULL) == -1)
559 {
560 DBG (DL_MAJOR_ERROR, "snapscani_usb_shm_init: cannot remove shared memory segment id: %s\n",
561 strerror (errno));
562 shmdt (shm_area);
563 shmctl (shm_id, IPC_RMID, NULL);
564 return SANE_STATUS_NO_MEM;
565 }
566 urb_counters = (struct urb_counters_t*) shm_area;
567 memset(urb_counters, 0, shm_size);
568 return SANE_STATUS_GOOD;
569 }
570
snapscani_usb_shm_exit(void)571 static void snapscani_usb_shm_exit(void)
572 {
573 if (urb_counters)
574 {
575 shmdt (urb_counters);
576 urb_counters = NULL;
577 }
578 }
579 #endif
580 /*
581 * Revision 1.22 2006/01/26 17:42:30 hmg-guest
582 * Added #defines for SHM_R/W for cygwin (patch from Philip Aston <philipa@mail.com>).
583 *
584 * Revision 1.21 2005/11/02 19:22:06 oliver-guest
585 * Fixes for Benq 5000
586 *
587 * Revision 1.20 2005/07/18 17:37:37 oliver-guest
588 * ZETA changes for SnapScan backend
589 *
590 * Revision 1.19 2004/10/03 17:34:36 hmg-guest
591 * 64 bit platform fixes (bug #300799).
592 *
593 * Revision 1.18 2004/06/16 19:52:26 oliver-guest
594 * Don't enforce even number of URB packages on 1212u_2. Fixes bug #300753.
595 *
596 * Revision 1.17 2004/06/06 14:50:36 oliver-guest
597 * Use shared memory functions only when needed
598 *
599 * Revision 1.16 2004/05/26 22:37:01 oliver-guest
600 * Use shared memory for urb counters in snapscan backend
601 *
602 * Revision 1.15 2004/04/09 11:59:02 oliver-guest
603 * Fixes for pthread implementation
604 *
605 * Revision 1.14 2004/04/08 22:48:13 oliver-guest
606 * Use URB counting in snapscan-usb.c (thanks to Jose Alberto Reguero)
607 *
608 * Revision 1.13 2003/11/08 09:50:27 oliver-guest
609 * Fix TPO scanning range for Epson 1670
610 *
611 * Revision 1.12 2003/07/26 17:16:55 oliverschwartz
612 * Changed licence to GPL + SANE exception for snapscan-usb.[ch]
613 *
614 * Revision 1.11 2002/07/12 23:29:06 oliverschwartz
615 * SnapScan backend 1.4.15
616 *
617 * Revision 1.21 2002/07/12 22:52:42 oliverschwartz
618 * use sanei_usb_read_bulk() and sanei_usb_write_bulk()
619 *
620 * Revision 1.20 2002/04/27 14:36:25 oliverschwartz
621 * Pass a char as 'proj' argument for ftok()
622 *
623 * Revision 1.19 2002/04/10 21:00:33 oliverschwartz
624 * Make bqelements static
625 *
626 * Revision 1.18 2002/03/24 12:16:09 oliverschwartz
627 * Better error report in usb_read
628 *
629 * Revision 1.17 2002/02/05 19:32:39 oliverschwartz
630 * Only define union semun if not already defined in <sys/sem.h>. Fixes
631 * compilation bugs on Irix and FreeBSD. Fixed by Henning Meier-Geinitz.
632 *
633 * Revision 1.16 2002/01/14 21:11:56 oliverschwartz
634 * Add workaround for bug semctl() call in libc for PPC
635 *
636 * Revision 1.15 2001/12/09 23:06:44 oliverschwartz
637 * - use sense handler for USB if scanner reports CHECK_CONDITION
638 *
639 * Revision 1.14 2001/11/16 20:23:16 oliverschwartz
640 * Merge with sane-1.0.6
641 * - Check USB vendor IDs to avoid hanging scanners
642 * - fix bug in dither matrix computation
643 *
644 * Revision 1.13 2001/10/09 22:34:23 oliverschwartz
645 * fix compiler warnings
646 *
647 * Revision 1.12 2001/09/18 15:01:07 oliverschwartz
648 * - Read scanner id string again after firmware upload
649 * to identify correct model
650 * - Make firmware upload work for AGFA scanners
651 * - Change copyright notice
652 *
653 * */
654