unification: Rearrange internals quite a lot.

Only Sony UP-DR150 driver is converted.

Still to-do in common code:
	* Backend selection based on URI (ie CUPS mode)
	* Backend selection based on BACKEND or argv[0] (ie standalone mode)
This commit is contained in:
Solomon Peachy 2013-07-18 08:46:44 -04:00
parent 7f4123d5eb
commit be8c5c494f
4 changed files with 421 additions and 244 deletions

View file

@ -2,9 +2,14 @@ CFLAGS = -Wall
LDFLAGS = -lusb-1.0
CUPS_BACKEND_DIR = /usr/lib/cups/backend
DEPS = backend_common.c
DEPS = backend_common.c backend_common.h
all: canon-selphy_print kodak-1400_print kodak-6800_print shinko-s2145_print sony-updr150_print
#all: canon-selphy_print kodak-1400_print kodak-6800_print shinko-s2145_print sony-updr150_print
all: gutenprint
gutenprint: sony_updr150_print.c $(DEPS)
gcc -o $@ $< backend_common.c $(LDFLAGS) $(CFLAGS)
canon-selphy_print: selphy_print.c $(DEPS)
gcc -o $@ $< $(LDFLAGS) $(CFLAGS)

View file

@ -25,70 +25,13 @@
*
*/
#include <libusb-1.0/libusb.h>
#include <arpa/inet.h>
#include "backend_common.h"
#define BACKEND_VERSION "0.6"
#define STR_LEN_MAX 64
#define DEBUG( ... ) fprintf(stderr, "DEBUG: " __VA_ARGS__ )
#define DEBUG2( ... ) fprintf(stderr, __VA_ARGS__ )
#define INFO( ... ) fprintf(stderr, "INFO: " __VA_ARGS__ )
#define ERROR( ... ) do { fprintf(stderr, "ERROR: " __VA_ARGS__ ); sleep(1); } while (0)
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define le32_to_cpu(__x) __x
#define le16_to_cpu(__x) __x
#define be16_to_cpu(__x) ntohs(__x)
#define be32_to_cpu(__x) ntohl(__x)
#else
#define le32_to_cpu(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define le16_to_cpu(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ff) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00) >> 8) | \
})
#define be32_to_cpu(__x) __x
#define be16_to_cpu(__x) __x
#ifndef URI_PREFIX
#define URI_PREFIX "gutenprint+usb"
#endif
#define cpu_to_le16 le16_to_cpu
#define cpu_to_le32 le32_to_cpu
#define cpu_to_be16 be16_to_cpu
#define cpu_to_be32 be32_to_cpu
/* To enumerate supported devices */
struct device_id {
uint16_t vid;
uint16_t pid;
int type;
char *manuf_str;
};
enum {
P_ES1 = 0,
P_ES2_20,
P_ES3_30,
P_ES40_CP790,
P_CP_XXX,
P_CP10,
P_KODAK_6800,
P_KODAK_1400_805,
P_SHINKO_S2145,
P_SONY_UPDR150,
P_END,
};
#define USB_VID_CANON 0x04a9
#define USB_PID_CANON_CP10 0x304A
#define USB_PID_CANON_CP100 0x3063
@ -227,8 +170,8 @@ done:
}
static int send_data(struct libusb_device_handle *dev, uint8_t endp,
uint8_t *buf, int len)
int send_data(struct libusb_device_handle *dev, uint8_t endp,
uint8_t *buf, int len)
{
int num;
@ -248,7 +191,7 @@ static int send_data(struct libusb_device_handle *dev, uint8_t endp,
return 0;
}
static int terminate = 0;
int terminate = 0;
static void sigterm_handler(int signum) {
terminate = 1;
@ -369,7 +312,7 @@ static int find_and_enumerate(struct libusb_context *ctx,
if (desc.idVendor == devices[j].vid &&
desc.idProduct == devices[j].pid) {
match = 1;
if (printer_type == devices[j].type)
if (printer_type && printer_type == devices[j].type)
found = i;
break;
}
@ -383,7 +326,7 @@ static int find_and_enumerate(struct libusb_context *ctx,
if (vid == desc.idVendor &&
pid == desc.idProduct) {
match = 1;
if (printer_type == type)
if (printer_type && printer_type == type)
found = i;
}
}
@ -400,3 +343,210 @@ static int find_and_enumerate(struct libusb_context *ctx,
return found;
}
static struct dyesub_backend *backends[] = {
&updr150_backend,
NULL,
};
/* MAIN */
int main (int argc, char **argv)
{
struct libusb_context *ctx;
struct libusb_device **list;
struct libusb_device_handle *dev;
struct libusb_config_descriptor *config;
struct dyesub_backend *backend;
void * backend_ctx = NULL;
uint8_t endp_up = 0;
uint8_t endp_down = 0;
int data_fd = fileno(stdin);
int i;
int claimed;
int ret = 0;
int iface = 0;
int found = -1;
int copies = 1;
char *uri = getenv("DEVICE_URI");
char *use_serno = NULL;
DEBUG("Gutenprint DyeSub CUPS Backend version %s\n",
BACKEND_VERSION);
/* Cmdline help */
if (argc < 2) {
DEBUG("Global Usage:\n\t%s [ infile | - ]\n\t%s job user title num-copies options [ filename ]\n\n",
argv[0], argv[0]);
for (i = 0; ; i++) {
backend = backends[i];
if (!backend)
break;
DEBUG("%s CUPS backend version %s\n",
backend->name, backend->version);
if (backend->cmdline_usage) {
DEBUG(" Usage:\n");
backend->cmdline_usage(backend->uri_prefix);
} else {
DEBUG(" (Global Usage Only)\n");
}
}
libusb_init(&ctx);
find_and_enumerate(ctx, &list, NULL, P_SONY_UPDR150, 1);
libusb_free_device_list(list, 1);
libusb_exit(ctx);
exit(1);
}
// XXX detect from getenv("BACKEND");
// XXX otherwise...
backend = &updr150_backend; // XXX detect.
/* Are we running as a CUPS backend? */
if (uri) {
if (argv[4])
copies = atoi(argv[4]);
if (argv[6]) { /* IOW, is it specified? */
data_fd = open(argv[6], O_RDONLY);
if (data_fd < 0) {
perror("ERROR:Can't open input file");
exit(1);
}
}
/* Ensure we're using BLOCKING I/O */
i = fcntl(data_fd, F_GETFL, 0);
if (i < 0) {
perror("ERROR:Can't open input");
exit(1);
}
i &= ~O_NONBLOCK;
i = fcntl(data_fd, F_SETFL, 0);
if (i < 0) {
perror("ERROR:Can't open input");
exit(1);
}
/* Start parsing URI 'prefix://PID/SERIAL' */
if (strncmp(backend->uri_prefix, uri, strlen(backend->uri_prefix))) {
ERROR("Invalid URI prefix (%s)\n", uri);
exit(1);
}
use_serno = strchr(uri, '=');
if (!use_serno || !*(use_serno+1)) {
ERROR("Invalid URI (%s)\n", uri);
exit(1);
}
use_serno++;
} else {
use_serno = getenv("DEVICE");
/* Open Input File */
if (strcmp("-", argv[1])) {
data_fd = open(argv[1], O_RDONLY);
if (data_fd < 0) {
perror("ERROR:Can't open input file");
exit(1);
}
}
}
/* Ignore SIGPIPE */
signal(SIGPIPE, SIG_IGN);
signal(SIGTERM, sigterm_handler);
/* Libusb setup */
libusb_init(&ctx);
found = find_and_enumerate(ctx, &list, use_serno, P_SONY_UPDR150, 0);
if (found == -1) {
ERROR("Printer open failure (No suitable printers found!)\n");
ret = 3;
goto done;
}
ret = libusb_open(list[found], &dev);
if (ret) {
ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
ret = 4;
goto done;
}
claimed = libusb_kernel_driver_active(dev, iface);
if (claimed) {
ret = libusb_detach_kernel_driver(dev, iface);
if (ret) {
ERROR("Printer open failure (Could not detach printer from kernel)\n");
ret = 4;
goto done_close;
}
}
ret = libusb_claim_interface(dev, iface);
if (ret) {
ERROR("Printer open failure (Could not claim printer interface)\n");
ret = 4;
goto done_close;
}
ret = libusb_get_active_config_descriptor(list[found], &config);
if (ret) {
ERROR("Printer open failure (Could not fetch config descriptor)\n");
ret = 4;
goto done_close;
}
for (i = 0 ; i < config->interface[0].altsetting[0].bNumEndpoints ; i++) {
if ((config->interface[0].altsetting[0].endpoint[i].bmAttributes & 3) == LIBUSB_TRANSFER_TYPE_BULK) {
if (config->interface[0].altsetting[0].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
endp_up = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
else
endp_down = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
}
}
/* Initialize backend */
backend_ctx = backend->init(dev, endp_up, endp_down);
/* Read in data */
if (backend->read_parse(backend_ctx, data_fd))
exit(1);
close(data_fd);
/* Time for the main processing loop */
INFO("Printing started (%d copies)\n", copies);
ret = backend->main_loop(backend_ctx, copies);
if (ret)
goto done_claimed;
/* Done printing */
INFO("All printing done\n");
ret = 0;
done_claimed:
libusb_release_interface(dev, iface);
done_close:
#if 0
if (claimed)
libusb_attach_kernel_driver(dev, iface);
#endif
libusb_close(dev);
done:
if (backend && backend_ctx)
backend->teardown(backend_ctx);
libusb_free_device_list(list, 1);
libusb_exit(ctx);
return ret;
}

131
backend_common.h Normal file
View file

@ -0,0 +1,131 @@
/*
* CUPS Backend common code
*
* (c) 2013 Solomon Peachy <pizza@shaftnet.org>
*
* The latest version of this program can be found at:
*
* http://git.shaftnet.org/git/gitweb.cgi?p=selphy_print.git
*
* 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 3 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.
*
* [http://www.gnu.org/licenses/gpl-3.0.html]
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <libusb-1.0/libusb.h>
#include <arpa/inet.h>
#ifndef __BACKEND_COMMON_H
#define __BACKEND_COMMON_H
#define STR_LEN_MAX 64
#define DEBUG( ... ) fprintf(stderr, "DEBUG: " __VA_ARGS__ )
#define DEBUG2( ... ) fprintf(stderr, __VA_ARGS__ )
#define INFO( ... ) fprintf(stderr, "INFO: " __VA_ARGS__ )
#define ERROR( ... ) do { fprintf(stderr, "ERROR: " __VA_ARGS__ ); sleep(1); } while (0)
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define le32_to_cpu(__x) __x
#define le16_to_cpu(__x) __x
#define be16_to_cpu(__x) ntohs(__x)
#define be32_to_cpu(__x) ntohl(__x)
#else
#define le32_to_cpu(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define le16_to_cpu(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ff) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00) >> 8) | \
})
#define be32_to_cpu(__x) __x
#define be16_to_cpu(__x) __x
#endif
#define cpu_to_le16 le16_to_cpu
#define cpu_to_le32 le32_to_cpu
#define cpu_to_be16 be16_to_cpu
#define cpu_to_be32 be32_to_cpu
/* Backend Functions */
struct dyesub_backend {
char *name;
char *version;
char *uri_prefix;
void (*cmdline_usage)(char *caller);
void *(*init)(struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down);
void (*teardown)(void *ctx);
int (*read_parse)(void *ctx, int data_fd);
int (*main_loop)(void *ctx, int copies);
};
/* XXX
- Cmdline Args Present
- Cmdline Arg Handling
*/
/* To enumerate supported devices */
enum {
P_ANY = 0,
P_ES1,
P_ES2_20,
P_ES3_30,
P_ES40_CP790,
P_CP_XXX,
P_CP10,
P_KODAK_6800,
P_KODAK_1400_805,
P_SHINKO_S2145,
P_SONY_UPDR150,
P_END,
};
struct device_id {
uint16_t vid;
uint16_t pid;
int type; /* P_** */
char *manuf_str;
};
/* Exported functions */
int send_data(struct libusb_device_handle *dev, uint8_t endp,
uint8_t *buf, int len);
/* Exported data */
extern int terminate;
/* External data */
extern struct dyesub_backend updr150_backend;
#endif /* __BACKEND_COMMON_H */

View file

@ -35,173 +35,73 @@
#include <fcntl.h>
#include <signal.h>
#define VERSION "0.04"
#define URI_PREFIX "sonyupdr150://"
#define STR_LEN_MAX 64
#include "backend_common.h"
#include "backend_common.c"
/* Private data stucture */
struct updr150_ctx {
struct libusb_device_handle *dev;
uint8_t endp_up;
uint8_t endp_down;
uint8_t *databuf;
int datalen;
};
static void* updr150_init(struct libusb_device_handle *dev,
uint8_t endp_up, uint8_t endp_down)
{
struct updr150_ctx *ctx = malloc(sizeof(struct updr150_ctx));
if (!ctx)
return NULL;
memset(ctx, 0, sizeof(struct updr150_ctx));
ctx->endp_up = endp_up;
ctx->endp_down = endp_down;
return ctx;
}
static void updr150_teardown(void *vctx) {
struct updr150_ctx *ctx = vctx;
if (!ctx)
return;
if (ctx->databuf)
free(ctx->databuf);
free(ctx);
}
#define MAX_PRINTJOB_LEN 16736455
int main (int argc, char **argv)
{
struct libusb_context *ctx;
struct libusb_device **list;
struct libusb_device_handle *dev;
struct libusb_config_descriptor *config;
uint8_t endp_up = 0;
uint8_t endp_down = 0;
int data_fd = fileno(stdin);
static int updr150_read_parse(void *vctx, int data_fd) {
struct updr150_ctx *ctx = vctx;
int i;
int claimed;
int ret = 0;
int iface = 0;
int found = -1;
int copies = 1;
char *uri = getenv("DEVICE_URI");;
char *use_serno = NULL;
uint8_t *databuf = NULL;
int datalen = 0;
if (!ctx)
return 1;
DEBUG("Sony UP-DR150 CUPS backend version " VERSION "/" BACKEND_VERSION " \n");
/* Cmdline help */
if (argc < 2) {
DEBUG("Usage:\n\t%s [ infile | - ]\n\t%s job user title num-copies options [ filename ]\n\n",
argv[0], argv[0]);
libusb_init(&ctx);
find_and_enumerate(ctx, &list, NULL, P_SONY_UPDR150, 1);
libusb_free_device_list(list, 1);
libusb_exit(ctx);
exit(1);
}
/* Are we running as a CUPS backend? */
if (uri) {
if (argv[4])
copies = atoi(argv[4]);
if (argv[6]) { /* IOW, is it specified? */
data_fd = open(argv[6], O_RDONLY);
if (data_fd < 0) {
perror("ERROR:Can't open input file");
exit(1);
}
}
/* Ensure we're using BLOCKING I/O */
i = fcntl(data_fd, F_GETFL, 0);
if (i < 0) {
perror("ERROR:Can't open input");
exit(1);
}
i &= ~O_NONBLOCK;
i = fcntl(data_fd, F_SETFL, 0);
if (i < 0) {
perror("ERROR:Can't open input");
exit(1);
}
/* Start parsing URI 'selphy://PID/SERIAL' */
if (strncmp(URI_PREFIX, uri, strlen(URI_PREFIX))) {
ERROR("Invalid URI prefix (%s)\n", uri);
exit(1);
}
use_serno = strchr(uri, '=');
if (!use_serno || !*(use_serno+1)) {
ERROR("Invalid URI (%s)\n", uri);
exit(1);
}
use_serno++;
} else {
use_serno = getenv("DEVICE");
/* Open Input File */
if (strcmp("-", argv[1])) {
data_fd = open(argv[1], O_RDONLY);
if (data_fd < 0) {
perror("ERROR:Can't open input file");
exit(1);
}
}
}
/* Ignore SIGPIPE */
signal(SIGPIPE, SIG_IGN);
signal(SIGTERM, sigterm_handler);
/* Read in data */
databuf = malloc(MAX_PRINTJOB_LEN);
if (!databuf) {
ctx->databuf = malloc(MAX_PRINTJOB_LEN);
if (!ctx->databuf) {
ERROR("Memory allocation failure!\n");
exit(1);
return 2;
}
while((i = read(data_fd, databuf+datalen, 4096)) > 0) {
datalen += i;
while((i = read(data_fd, ctx->databuf + ctx->datalen, 4096)) > 0) {
ctx->datalen += i;
}
close(data_fd); /* We're done reading! */
return 0;
}
/* Libusb setup */
libusb_init(&ctx);
found = find_and_enumerate(ctx, &list, use_serno, P_SONY_UPDR150, 0);
static int updr150_main_loop(void *vctx, int copies) {
struct updr150_ctx *ctx = vctx;
int i, ret;
if (found == -1) {
ERROR("Printer open failure (No suitable printers found!)\n");
ret = 3;
goto done;
}
ret = libusb_open(list[found], &dev);
if (ret) {
ERROR("Printer open failure (Need to be root?) (%d)\n", ret);
ret = 4;
goto done;
}
claimed = libusb_kernel_driver_active(dev, iface);
if (claimed) {
ret = libusb_detach_kernel_driver(dev, iface);
if (ret) {
ERROR("Printer open failure (Could not detach printer from kernel)\n");
ret = 4;
goto done_close;
}
}
ret = libusb_claim_interface(dev, iface);
if (ret) {
ERROR("Printer open failure (Could not claim printer interface)\n");
ret = 4;
goto done_close;
}
ret = libusb_get_active_config_descriptor(list[found], &config);
if (ret) {
ERROR("Printer open failure (Could not fetch config descriptor)\n");
ret = 4;
goto done_close;
}
for (i = 0 ; i < config->interface[0].altsetting[0].bNumEndpoints ; i++) {
if ((config->interface[0].altsetting[0].endpoint[i].bmAttributes & 3) == LIBUSB_TRANSFER_TYPE_BULK) {
if (config->interface[0].altsetting[0].endpoint[i].bEndpointAddress & LIBUSB_ENDPOINT_IN)
endp_up = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
else
endp_down = config->interface[0].altsetting[0].endpoint[i].bEndpointAddress;
}
}
/* Time for the main processing loop */
INFO("Printing started (%d copies)\n", copies);
if (!ctx)
return 1;
top:
for (i = 0 ; i < datalen ; ) {
uint8_t *ptr = databuf + i;
for (i = 0 ; i < ctx->datalen ; ) {
uint8_t *ptr = ctx->databuf + i;
i += 4;
if (*ptr & 0xf0) {
switch (*ptr) {
@ -231,9 +131,9 @@ top:
uint32_t len = le32_to_cpu(*((uint32_t*)ptr));
DEBUG("Sending %d bytes to printer\n", len);
if ((ret = send_data(dev, endp_down,
databuf + i, len)))
goto done_claimed;
if ((ret = send_data(ctx->dev, ctx->endp_down,
ctx->databuf + i, len)))
return ret;
i += len;
}
}
@ -248,30 +148,21 @@ top:
goto top;
}
/* Done printing */
INFO("All printing done\n");
ret = 0;
done_claimed:
libusb_release_interface(dev, iface);
done_close:
#if 0
if (claimed)
libusb_attach_kernel_driver(dev, iface);
#endif
libusb_close(dev);
done:
if (databuf)
free(databuf);
libusb_free_device_list(list, 1);
libusb_exit(ctx);
return ret;
return 0;
}
/* Exported */
struct dyesub_backend updr150_backend = {
.name = "Sony UP-DR150",
.version = "0.05",
.uri_prefix = "sonyupdr150://",
// .cmdline_usage = updr150_cmdline,
.init = updr150_init,
.teardown = updr150_teardown,
.read_parse = updr150_read_parse,
.main_loop = updr150_main_loop,
};
/* Sony UP-DR150 Spool file format
The spool file is a series of 4-byte commands, followed by optional