From be8c5c494fae03b31ad93d4152581301674d65be Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Thu, 18 Jul 2013 08:46:44 -0400 Subject: [PATCH] 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) --- Makefile | 9 +- backend_common.c | 280 +++++++++++++++++++++++++++++++++---------- backend_common.h | 131 ++++++++++++++++++++ sony_updr150_print.c | 245 +++++++++++-------------------------- 4 files changed, 421 insertions(+), 244 deletions(-) create mode 100644 backend_common.h diff --git a/Makefile b/Makefile index 318d874..2fc9b23 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/backend_common.c b/backend_common.c index 6d7de9d..ff072ea 100644 --- a/backend_common.c +++ b/backend_common.c @@ -25,70 +25,13 @@ * */ -#include -#include +#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; +} + diff --git a/backend_common.h b/backend_common.h new file mode 100644 index 0000000..6b3a70f --- /dev/null +++ b/backend_common.h @@ -0,0 +1,131 @@ +/* + * CUPS Backend common code + * + * (c) 2013 Solomon Peachy + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#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 */ diff --git a/sony_updr150_print.c b/sony_updr150_print.c index 8ef242a..73fd05f 100644 --- a/sony_updr150_print.c +++ b/sony_updr150_print.c @@ -35,173 +35,73 @@ #include #include -#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