2001-05-26 12:47:34 +00:00
|
|
|
/*
|
|
|
|
Snapscan 1212U modifications for the Snapscan SANE backend
|
|
|
|
|
|
|
|
Copyright (C) 2000 Henrik Johansson
|
|
|
|
|
|
|
|
Henrik Johansson (henrikjo@post.urfors.se)
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
|
|
MA 02111-1307, USA.
|
|
|
|
|
|
|
|
This file implements USB equivalents to the SCSI routines used by the Snapscan
|
|
|
|
backend.
|
|
|
|
|
|
|
|
History
|
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
0.1 2000-02-01
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
First version released
|
|
|
|
|
|
|
|
0.2 2000-02-12
|
|
|
|
|
|
|
|
The Send Diagnostics SCSI command seems to hang some 1212U scanners.
|
|
|
|
Bypassing this command fixes the problem. This bug was reported by
|
|
|
|
Dmitri (dmitri@advantrix.com).
|
|
|
|
|
|
|
|
0.3 2000-02-13
|
|
|
|
|
|
|
|
The "Set window" command returns with status "Device busy" when the
|
|
|
|
scanner is busy. One consequence is that some frontends exits with an
|
|
|
|
error message if it's started when the scanner is warming up.
|
|
|
|
A solution was suggested by Dmitri (dmitri@advantrix.com)
|
|
|
|
The idea is that a SCSI command which returns "device busy" is stored
|
|
|
|
in a "TODO" queue. The send command function is modified to first send
|
|
|
|
commands in the queue before the intended command.
|
|
|
|
So far this strategy has worked flawlessly. Thanks Dmitri!
|
|
|
|
*/
|
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
/* $Id$
|
|
|
|
SnapScan backend scan data sources */
|
|
|
|
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#include <sys/sem.h>
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
#include "snapscan-usb.h"
|
|
|
|
|
|
|
|
/* Global variables */
|
|
|
|
|
|
|
|
static int sem_id;
|
|
|
|
static struct sembuf sem_wait = { 0, -1, 0 };
|
|
|
|
static struct sembuf sem_signal = { 0, 1, 0 };
|
|
|
|
|
|
|
|
static SANE_Status snapscani_usb_cmd(int fd, const void *src, size_t src_size,
|
2001-10-09 09:45:21 +00:00
|
|
|
void *dst, size_t * dst_size)
|
2001-05-26 12:47:34 +00:00
|
|
|
{
|
|
|
|
static const char me[] = "snapscani_usb_cmd";
|
|
|
|
int status;
|
|
|
|
|
|
|
|
DBG (DL_CALL_TRACE, "%s(%d,0x%x,%d,0x%x,0x%x (%d))\n", me,
|
2001-10-09 09:45:21 +00:00
|
|
|
fd,(int)src,src_size,(int)dst,(int)dst_size,dst_size ? *dst_size : 0);
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
while(bqhead) {
|
2001-10-09 09:45:21 +00:00
|
|
|
status = atomic_usb_cmd(fd, bqhead->src, bqhead->src_size, NULL, NULL);
|
|
|
|
if(status == SANE_STATUS_DEVICE_BUSY) {
|
|
|
|
if(is_queueable(src)) {
|
|
|
|
enqueue_bq(fd,src,src_size);
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
} else {
|
|
|
|
sleep(1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dequeue_bq();
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
status = atomic_usb_cmd(fd,src,src_size,dst,dst_size);
|
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
if ((status == SANE_STATUS_DEVICE_BUSY) && is_queueable(src) ) {
|
|
|
|
enqueue_bq(fd,src,src_size);
|
|
|
|
return SANE_STATUS_GOOD;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
2001-10-09 09:45:21 +00:00
|
|
|
|
|
|
|
return status;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static SANE_Status atomic_usb_cmd(int fd, const void *src, size_t src_size,
|
2001-10-09 09:45:21 +00:00
|
|
|
void *dst, size_t * dst_size)
|
2001-05-26 12:47:34 +00:00
|
|
|
{
|
|
|
|
static const char me[] = "atomic_usb_cmd";
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
int status;
|
|
|
|
sigset_t all,oldset;
|
|
|
|
|
|
|
|
DBG (DL_CALL_TRACE, "%s(%d,0x%x,%d,0x%x,0x%x (%d))\n", me,
|
2001-10-09 09:45:21 +00:00
|
|
|
fd,(int)src,src_size,(int)dst,(int)dst_size,dst_size ? *dst_size : 0);
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
/* Prevent the calling process from being killed */
|
|
|
|
sigfillset(&all);
|
|
|
|
sigprocmask(SIG_BLOCK, &all, &oldset);
|
|
|
|
|
|
|
|
/* Make sure we are alone */
|
|
|
|
semop(sem_id, &sem_wait, 1);
|
|
|
|
|
|
|
|
status = usb_cmd(fd,src,src_size,dst,dst_size);
|
|
|
|
|
|
|
|
semop(sem_id, &sem_signal, 1);
|
|
|
|
|
|
|
|
/* Now it is ok to be killed */
|
|
|
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
2001-10-09 09:45:21 +00:00
|
|
|
|
|
|
|
return status;
|
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
static SANE_Status snapscani_usb_open(const char *dev, int *fdp)
|
2001-05-26 12:47:34 +00:00
|
|
|
{
|
2001-10-09 09:45:21 +00:00
|
|
|
return usb_open(dev,fdp);
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void snapscani_usb_close(int fd) {
|
|
|
|
usb_close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int usb_cmdlen(int cmd)
|
|
|
|
{
|
|
|
|
switch(cmd) {
|
|
|
|
case TEST_UNIT_READY:
|
|
|
|
case INQUIRY:
|
|
|
|
case SCAN:
|
|
|
|
case REQUEST_SENSE:
|
|
|
|
case RESERVE_UNIT:
|
|
|
|
case RELEASE_UNIT:
|
|
|
|
case SEND_DIAGNOSTIC:
|
2001-10-09 09:45:21 +00:00
|
|
|
return 6;
|
2001-05-26 12:47:34 +00:00
|
|
|
case SEND:
|
|
|
|
case SET_WINDOW:
|
|
|
|
case READ:
|
|
|
|
case GET_DATA_BUFFER_STATUS:
|
2001-10-09 09:45:21 +00:00
|
|
|
return 10;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *usb_debug_data(char *str,const char *data, int len) {
|
|
|
|
char tmpstr[10];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
str[0]=0;
|
|
|
|
for(i=0; i < (len < 10 ? len : 10); i++) {
|
2001-10-09 09:45:21 +00:00
|
|
|
sprintf(tmpstr," 0x%02x",((int)data[i]) & 0xff);
|
|
|
|
if(i%16 == 0 && i != 0)
|
|
|
|
strcat(str,"\n");
|
|
|
|
strcat(str,tmpstr);
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
if(i < len)
|
2001-10-09 09:45:21 +00:00
|
|
|
strcat(str," ...");
|
2001-05-26 12:47:34 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
static SANE_Status usb_open(const char *dev, int *fdp)
|
2001-05-26 12:47:34 +00:00
|
|
|
{
|
2001-10-09 09:45:21 +00:00
|
|
|
static const char me[] = "usb_open";
|
2001-05-26 12:47:34 +00:00
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
DBG (DL_CALL_TRACE, "%s(%s)\n", me, dev);
|
2001-05-26 12:47:34 +00:00
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
if((sem_id = semget( ftok(dev,0x1234), 1, IPC_CREAT | 0660 )) == -1) {
|
|
|
|
DBG (DL_MAJOR_ERROR, "%s: Can't get semaphore\n", me);
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
}
|
|
|
|
semop(sem_id, &sem_signal, 1);
|
|
|
|
|
|
|
|
*fdp = open(dev, O_RDWR);
|
|
|
|
if( *fdp < 0)
|
|
|
|
return SANE_STATUS_INVAL;
|
|
|
|
return SANE_STATUS_GOOD;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void usb_close(int fd) {
|
2001-10-09 09:45:21 +00:00
|
|
|
static const char me[] = "usb_close";
|
|
|
|
|
|
|
|
DBG (DL_CALL_TRACE, "%s(%d)\n", me, fd);
|
|
|
|
semctl(sem_id, 0, IPC_RMID, 0);
|
|
|
|
close(fd);
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
static int usb_status(char *status_buf) {
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = (status_buf[1] & STATUS_MASK) >> 1;
|
|
|
|
|
|
|
|
switch(status) {
|
|
|
|
case GOOD:
|
2001-10-09 09:45:21 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
2001-05-26 12:47:34 +00:00
|
|
|
case CHECK_CONDITION:
|
|
|
|
case BUSY:
|
2001-10-09 09:45:21 +00:00
|
|
|
return SANE_STATUS_DEVICE_BUSY;
|
2001-05-26 12:47:34 +00:00
|
|
|
default:
|
2001-10-09 09:45:21 +00:00
|
|
|
return SANE_STATUS_IO_ERROR;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define RETURN_ON_FAILURE(x) if((status = x) != SANE_STATUS_GOOD) return status;
|
|
|
|
|
|
|
|
static SANE_Status usb_write(int fd, const void *buf, int n) {
|
|
|
|
char dbgmsg[16384];
|
|
|
|
int r;
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
static const char me[] = "usb_write";
|
|
|
|
DBG(DL_DATA_TRACE, "%s: writing: %s\n",me,usb_debug_data(dbgmsg,buf,n));
|
|
|
|
|
|
|
|
if((r=write(fd,buf,n)) != n) {
|
2001-10-09 09:45:21 +00:00
|
|
|
DBG (DL_MAJOR_ERROR, "%s Only %d bytes written\n",me,r);
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SANE_Status usb_read(int fd, void *buf, int n) {
|
|
|
|
char dbgmsg[16384];
|
|
|
|
int r;
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
static const char me[] = "usb_read";
|
|
|
|
|
|
|
|
/* USB driver appears to block in all cases when asking for data
|
|
|
|
* except if the device says its not ready. In this case, we
|
|
|
|
* attempt to block ourselves to act like the sane SCSI driver.
|
|
|
|
* This relies on the USB driver to eventually report something
|
|
|
|
* besides EAGAIN if there is a serious problem.
|
|
|
|
*/
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if((r=read(fd,buf,n)) != n && !(r == -1 && errno == EAGAIN)) {
|
2001-10-09 09:45:21 +00:00
|
|
|
DBG (DL_MAJOR_ERROR, "%s Only %d bytes read\n",me,r);
|
|
|
|
return SANE_STATUS_IO_ERROR;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
if (r == -1 && errno == EAGAIN)
|
|
|
|
{
|
2001-10-09 09:45:21 +00:00
|
|
|
DBG (DL_MAJOR_ERROR, "%s: Got an EAGAIN\n",me);
|
|
|
|
usleep(10000);
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
} while (r == -1 && errno == EAGAIN);
|
|
|
|
|
|
|
|
DBG(DL_DATA_TRACE, "%s: reading: %s\n",me,usb_debug_data(dbgmsg,buf,n));
|
|
|
|
return SANE_STATUS_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static SANE_Status usb_read_status(int fd, int *scsistatus, int *transaction_status)
|
2001-10-09 09:45:21 +00:00
|
|
|
{
|
2001-05-26 12:47:34 +00:00
|
|
|
unsigned char status_buf[8];
|
|
|
|
int scsistat;
|
|
|
|
int status;
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
RETURN_ON_FAILURE(usb_read(fd,status_buf,8));
|
|
|
|
|
|
|
|
if(transaction_status)
|
2001-10-09 09:45:21 +00:00
|
|
|
*transaction_status = status_buf[0];
|
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
scsistat = (status_buf[1] & STATUS_MASK) >> 1;
|
|
|
|
|
|
|
|
if(scsistatus)
|
2001-10-09 09:45:21 +00:00
|
|
|
*scsistatus = scsistat;
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
switch(scsistat) {
|
|
|
|
case GOOD:
|
2001-10-09 09:45:21 +00:00
|
|
|
return SANE_STATUS_GOOD;
|
2001-05-26 12:47:34 +00:00
|
|
|
case CHECK_CONDITION:
|
|
|
|
case BUSY:
|
2001-10-09 09:45:21 +00:00
|
|
|
return SANE_STATUS_DEVICE_BUSY;
|
2001-05-26 12:47:34 +00:00
|
|
|
default:
|
2001-10-09 09:45:21 +00:00
|
|
|
return SANE_STATUS_IO_ERROR;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static SANE_Status usb_cmd(int fd, const void *src, size_t src_size,
|
2001-10-09 09:45:21 +00:00
|
|
|
void *dst, size_t * dst_size)
|
2001-05-26 12:47:34 +00:00
|
|
|
{
|
|
|
|
static const char me[] = "usb_cmd";
|
|
|
|
int status,tstatus;
|
|
|
|
int cmdlen,datalen;
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
DBG (DL_CALL_TRACE, "%s(%d,0x%x,%d,0x%x,0x%x (%d))\n", me,
|
|
|
|
fd,(int)src,src_size,(int)dst,(int)dst_size,dst_size ? *dst_size : 0);
|
|
|
|
|
|
|
|
|
|
|
|
/* Since the "Send Diagnostic" command isn't supported by
|
|
|
|
all Snapscan USB-scanners it's disabled .
|
|
|
|
*/
|
2001-10-10 07:30:06 +00:00
|
|
|
if(((const char *)src)[0] == SEND_DIAGNOSTIC)
|
2001-05-26 12:47:34 +00:00
|
|
|
return(SANE_STATUS_GOOD);
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-10-10 07:30:06 +00:00
|
|
|
cmdlen = usb_cmdlen(*((const char *)src));
|
2001-05-26 12:47:34 +00:00
|
|
|
datalen = src_size - cmdlen;
|
|
|
|
|
|
|
|
DBG(DL_DATA_TRACE, "%s: cmdlen=%d, datalen=%d\n",me,cmdlen,datalen);
|
|
|
|
|
|
|
|
/* Send command to scanner */
|
|
|
|
RETURN_ON_FAILURE( usb_write(fd,src,cmdlen) );
|
|
|
|
|
|
|
|
/* Read status */
|
|
|
|
RETURN_ON_FAILURE( usb_read_status(fd, NULL, &tstatus) );
|
|
|
|
|
|
|
|
/* Send data only if the scanner is expecting it */
|
|
|
|
if(datalen > 0 && (tstatus == TRANSACTION_WRITE)) {
|
2001-10-09 09:45:21 +00:00
|
|
|
/* Send data to scanner */
|
2001-10-10 07:30:06 +00:00
|
|
|
RETURN_ON_FAILURE( usb_write(fd, ((const SANE_Byte *) src) + cmdlen, datalen) );
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
/* Read status */
|
|
|
|
RETURN_ON_FAILURE( usb_read_status(fd, NULL, &tstatus) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Receive data only when new data is waiting */
|
|
|
|
if(dst_size && *dst_size && (tstatus == TRANSACTION_READ)) {
|
|
|
|
RETURN_ON_FAILURE( usb_read(fd,dst,*dst_size) );
|
|
|
|
|
|
|
|
/* Read status */
|
|
|
|
RETURN_ON_FAILURE( usb_read_status(fd, NULL, &tstatus) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tstatus != TRANSACTION_COMPLETED) {
|
|
|
|
if(tstatus == TRANSACTION_WRITE)
|
2001-10-09 09:45:21 +00:00
|
|
|
DBG(DL_MAJOR_ERROR,
|
|
|
|
"%s: The transaction should now be completed, but the scanner is expecting more data" ,me);
|
2001-05-26 12:47:34 +00:00
|
|
|
else
|
2001-10-09 09:45:21 +00:00
|
|
|
DBG(DL_MAJOR_ERROR,
|
|
|
|
"%s: The transaction should now be completed, but the scanner has more data to send" ,me);
|
2001-05-26 12:47:34 +00:00
|
|
|
return SANE_STATUS_IO_ERROR;
|
|
|
|
}
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Busy queue data structures and function implementations*/
|
|
|
|
|
|
|
|
static int is_queueable(const char *src)
|
|
|
|
{
|
|
|
|
switch(src[0]) {
|
|
|
|
case SEND:
|
|
|
|
case SET_WINDOW:
|
|
|
|
case SEND_DIAGNOSTIC:
|
2001-10-09 09:45:21 +00:00
|
|
|
return 1;
|
2001-05-26 12:47:34 +00:00
|
|
|
default:
|
2001-10-09 09:45:21 +00:00
|
|
|
return 0;
|
2001-05-26 12:47:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct usb_busy_queue *bqhead=NULL,*bqtail=NULL;
|
|
|
|
int bqelements=0;
|
|
|
|
|
|
|
|
static int enqueue_bq(int fd,const void *src, size_t src_size)
|
|
|
|
{
|
|
|
|
static const char me[] = "enqueue_bq";
|
|
|
|
struct usb_busy_queue *bqe;
|
2001-10-09 09:45:21 +00:00
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
DBG (DL_CALL_TRACE, "%s(%d,%p,%d)\n", me, fd,src,src_size);
|
|
|
|
|
|
|
|
if((bqe = malloc(sizeof(struct usb_busy_queue))) == NULL)
|
2001-10-09 09:45:21 +00:00
|
|
|
return -1;
|
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
if((bqe->src = malloc(src_size)) == NULL)
|
2001-10-09 09:45:21 +00:00
|
|
|
return -1;
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
memcpy(bqe->src,src,src_size);
|
|
|
|
bqe->src_size=src_size;
|
|
|
|
|
|
|
|
bqe->next=NULL;
|
|
|
|
|
|
|
|
if(bqtail) {
|
2001-10-09 09:45:21 +00:00
|
|
|
bqtail->next=bqe;
|
|
|
|
bqtail = bqe;
|
2001-05-26 12:47:34 +00:00
|
|
|
} else
|
2001-10-09 09:45:21 +00:00
|
|
|
bqhead = bqtail = bqe;
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
bqelements++;
|
|
|
|
DBG(DL_DATA_TRACE, "%s: Busy queue: elements=%d, bqhead=%p, bqtail=%p\n",
|
2001-10-09 09:45:21 +00:00
|
|
|
me,bqelements,bqhead,bqtail);
|
2001-05-26 12:47:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-10-09 09:45:21 +00:00
|
|
|
static void dequeue_bq()
|
2001-05-26 12:47:34 +00:00
|
|
|
{
|
|
|
|
static const char me[] = "dequeue_bq";
|
|
|
|
struct usb_busy_queue *tbqe;
|
|
|
|
|
|
|
|
DBG (DL_CALL_TRACE, "%s()\n", me);
|
|
|
|
|
|
|
|
if(!bqhead)
|
2001-10-09 09:45:21 +00:00
|
|
|
return;
|
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
tbqe = bqhead;
|
|
|
|
bqhead = bqhead->next;
|
|
|
|
if(!bqhead)
|
2001-10-09 09:45:21 +00:00
|
|
|
bqtail=NULL;
|
|
|
|
|
2001-05-26 12:47:34 +00:00
|
|
|
if(tbqe->src)
|
2001-10-09 09:45:21 +00:00
|
|
|
free(tbqe->src);
|
2001-05-26 12:47:34 +00:00
|
|
|
free(tbqe);
|
|
|
|
|
|
|
|
bqelements--;
|
|
|
|
DBG(DL_DATA_TRACE, "%s: Busy queue: elements=%d, bqhead=%p, bqtail=%p\n",
|
2001-10-09 09:45:21 +00:00
|
|
|
me,bqelements,bqhead,bqtail);
|
2001-05-26 12:47:34 +00:00
|
|
|
|
|
|
|
}
|
2001-10-09 09:45:21 +00:00
|
|
|
/*
|
|
|
|
* $Log$
|
2001-10-10 07:30:06 +00:00
|
|
|
* Revision 1.3 2001/10/10 07:30:06 oliverschwartz
|
|
|
|
* fix compiler warnings
|
|
|
|
*
|
|
|
|
* Revision 1.13 2001/10/09 22:34:23 oliverschwartz
|
|
|
|
* fix compiler warnings
|
2001-10-09 09:45:21 +00:00
|
|
|
*
|
|
|
|
* Revision 1.12 2001/09/18 15:01:07 oliverschwartz
|
|
|
|
* - Read scanner id string again after firmware upload
|
|
|
|
* to indentify correct model
|
|
|
|
* - Make firmware upload work for AGFA scanners
|
|
|
|
* - Change copyright notice
|
|
|
|
*
|
|
|
|
* */
|