/* * Hewlett-Packard Co. Inkjet Driver * Copyright (c) 2001, Hewlett-Packard Co. * * This ghostscript printer driver is the glue code for using the * HP Inkjet Server (hpijs). * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: gdevhpij.c,v 1.3.2.1 2002/04/10 09:33:25 giles Exp $ */ #include "gdevprn.h" #include "gdevpcl.h" #include "gxdevice.h" #include #include #include #include #include #include #include #include #include "gdevhpij.h" /* Structure for hpijs device. */ typedef struct gx_device_hpijs_s { gx_device_common; gx_prn_device_common; /* Additional parameters for hpijs */ int PrintMode; /* qrayscale=0, normal=1, photo=2, ??? */ SRVD sd; /* server descriptor */ gs_param_string DeviceName; } gx_device_hpijs; /* Default X and Y resolution. */ #ifndef X_DPI # define X_DPI 300 #endif #ifndef Y_DPI # define Y_DPI 300 #endif /* Margins are left, bottom, right, top. */ #define DESKJET_MARGINS_LETTER 0.25, 0.44, -0.25, 0.167 #define DESKJET_MARGINS_A4 0.125, 0.44, -0.125, 0.167 //#define DESKJET_MARGINS_LETTER 0.25, 0.44, 0, 0.167 //#define DESKJET_MARGINS_A4 0.125, 0.44, 0, 0.167 private int hpijs_print_page(gx_device_printer * pdev, FILE * prn_stream, const char *dname); private dev_proc_open_device(hpijs_open); private dev_proc_close_device(hpijs_close); private dev_proc_print_page(dj630_print_page); private dev_proc_print_page(dj6xx_print_page); private dev_proc_print_page(dj6xx_photo_print_page); private dev_proc_print_page(dj8xx_print_page); private dev_proc_print_page(dj9xx_print_page); private dev_proc_print_page(dj9xx_vip_print_page); private dev_proc_print_page(ap21xx_print_page); private dev_proc_print_page(hpijs_ext_print_page); private dev_proc_get_params(hpijs_get_params); private dev_proc_put_params(hpijs_put_params); private gx_device_procs prn_hpijs_procs = prn_color_params_procs(hpijs_open, gdev_prn_output_page, hpijs_close, gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb, hpijs_get_params, hpijs_put_params); gx_device_hpijs gs_DJ630_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "DJ630", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, dj630_print_page), 2 /* PrintMode default */ }; gx_device_hpijs gs_DJ6xx_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "DJ6xx", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, dj6xx_print_page), 1 /* PrintMode default */ }; gx_device_hpijs gs_DJ6xxP_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "DJ6xxP", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, dj6xx_photo_print_page), 1 /* PrintMode default */ }; gx_device_hpijs gs_DJ8xx_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "DJ8xx", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, dj8xx_print_page), 1 /* PrintMode default */ }; gx_device_hpijs gs_DJ9xx_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "DJ9xx", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, dj9xx_print_page), 1 /* PrintMode default */ }; gx_device_hpijs gs_DJ9xxVIP_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "DJ9xxVIP", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, dj9xx_vip_print_page), 1 /* PrintMode default */ }; gx_device_hpijs gs_AP21xx_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "AP21xx", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, ap21xx_print_page), 2 /* PrintMode default */ }; gx_device_hpijs gs_hpijs_device = { prn_device_std_body(gx_device_hpijs, prn_hpijs_procs, "hpijs", DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI, 0, 0, 0, 0, /* margins (lm,bm,rm,tm) */ 24, hpijs_ext_print_page), 1 /* PrintMode default */ }; static char s2c[80]; static char c2s[80]; private int bug(const char *fmt, ...) { char buf[256]; va_list args; int n; va_start(args, fmt); if ((n = vsnprintf(buf, 256, fmt, args)) == -1) buf[255] = 0; /* output was truncated */ fprintf(stderr, buf); syslog(LOG_WARNING, buf); fflush(stderr); va_end(args); return n; } /* Get packet from the server. */ private int hpijs_get_pk(PK * pk, int fd) { return read(fd, pk, PIPE_BUF - 1); } /* Write packet to the server. */ private int hpijs_put_pk(PK * pk, int fd) { return write(fd, pk, sizeof(PK)); } /* Write single command packet to server. */ private int hpijs_put_cmd(SRVD * sd, int cmd) { PK pk; pk.cmd = cmd; if (hpijs_put_pk(&pk, sd->fdc2s) < 0) { bug("unable to write fifo %d: %m\n", sd->client_to_srv); return -1; } if (hpijs_get_pk(&pk, sd->fds2c) < 0) /* ack */ { bug("unable to read fifo %d: %m\n", sd->client_to_srv); return -1; } return 0; } /* Init server discriptor. */ private int hpijs_init_sd(SRVD * sd) { sd->fds2c = -1; sd->fdc2s = -1; sd->shmid = -1; sd->shmbuf = NULL; sd->srv_to_client = NULL; sd->client_to_srv = NULL; return 0; } /* Close the server. */ private int hpijs_close_srv(SRVD * sd) { PK pk; if (sd->fdc2s >= 0) { /* Kill the server. */ pk.cmd = KILL; hpijs_put_pk(&pk, sd->fdc2s); } if (sd->shmbuf != NULL) { /* Detach and release shared memory. */ shmdt(sd->shmbuf); shmctl(sd->shmid, IPC_RMID, 0); } close(sd->fds2c); close(sd->fdc2s); remove(sd->srv_to_client); remove(sd->client_to_srv); return 0; } /* Spawn the server as a coprocess. */ private int hpijs_open_srv(SRVD * sd, FILE * prn_stream, int raster_width) { PK pk; int fd; mode_t mode = 0666; int pid; /* Make sure we can find the server. */ // if (access(SRVPATH, F_OK) < 0) // { // bug("unable to locate %s: %m\n", SRVPATH); // return -1; // } /* Assign fifo names for environment space, names must be const char. */ sprintf(s2c, "SRV_TO_CLIENT=/tmp/hpijs_s2c_%d", getpid()); sprintf(c2s, "CLIENT_TO_SRV=/tmp/hpijs_c2s_%d", getpid()); /* Put fifo names in envirmoment space for child process. */ putenv(s2c); putenv(c2s); /* Get local copy. */ sd->srv_to_client = getenv("SRV_TO_CLIENT"); sd->client_to_srv = getenv("CLIENT_TO_SRV"); /* Create actual fifos in filesystem. */ if ((mkfifo(sd->srv_to_client, mode)) < 0) { bug("unable to create fifo %s: %m\n", sd->srv_to_client); return -1; } if ((mkfifo(sd->client_to_srv, mode)) < 0) { bug("unable to create fifo %s: %m\n", sd->client_to_srv); goto BUGOUT; } /* Create shared memory for raster data. */ if ((sd->shmid = shmget(IPC_PRIVATE, raster_width, mode)) < 0) { bug("unable to create shared memory: %m\n"); goto BUGOUT; } /* Spawn the server. */ if ((pid = fork()) < 0) { bug("unable to fork server: %m\n"); goto BUGOUT; } else if (pid > 0) { /* parent */ /* Open fifos. */ if ((sd->fds2c = open(sd->srv_to_client, O_RDONLY)) < 0) { bug("unable to open fifo %d: %m\n", sd->srv_to_client); goto BUGOUT; } if ((sd->fdc2s = open(sd->client_to_srv, O_WRONLY)) < 0) { bug("unable to open fifo %d: %m\n", sd->client_to_srv); goto BUGOUT; } /* Attach to shared memory. */ if ((sd->shmbuf = shmat(sd->shmid, 0, 0)) < (char *) 0) { bug("unable to attach shared memory: %m\n"); goto BUGOUT; } /* Send shmid to server. */ pk.shm.cmd = SET_SHMID; pk.shm.id = sd->shmid; hpijs_put_pk(&pk, sd->fdc2s); hpijs_get_pk(&pk, sd->fds2c); return 0; BUGOUT: hpijs_close_srv(sd); return -1; } else { /* child */ /* Redirect print_stream to stdout. */ fd = fileno(prn_stream); if (fd != STDOUT_FILENO) { if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO) bug("unable redirect stdout: %m\n"); } if (execlp(SRVPATH, SNAME, (char *) 0) < 0) { bug("unable to exec %s: %m\n", SRVPATH); goto BUGOUT2; } exit(0); BUGOUT2: exit(EXIT_FAILURE); } return -1; } private int hpijs_spawn_srv(gx_device_hpijs *pdev, FILE * prn_stream, const char *dname) { PK pk; hpijs_init_sd(&pdev->sd); if (hpijs_open_srv(&pdev->sd, prn_stream, pdev->width * 3) < 0) { bug("unable to spawn server\n"); return -1; } pk.dev.cmd = SET_DEVICE_NAME; strcpy(pk.dev.name, dname); hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ pk.mode.cmd = SET_PRINTMODE; pk.mode.val = pdev->PrintMode; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ pk.paper.cmd = SET_PAPER; pk.paper.size = gdev_pcl_paper_size((gx_device *)pdev); hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ pk.res.cmd = SET_RESOLUTION; pk.res.x = pdev->x_pixels_per_inch; pk.res.y = pdev->y_pixels_per_inch; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ pk.ppr.cmd = SET_PIXELS_PER_ROW; pk.ppr.width = pdev->width; pk.ppr.outwidth = pdev->width; /* no simple pixel replication (scaling) */ hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ #ifdef zero_and_no_warning /* API Test code. */ pk.ppr.cmd = GET_PRINTMODE; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("printmode=%d\n", pk.mode.val); pk.ppr.cmd = GET_PRINTMODE_CNT; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("number of printmodes=%d\n", pk.mode.val); pk.ppr.cmd = GET_PAPER; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("paper size=%d\n", pk.paper.size); pk.ppr.cmd = GET_EFFECTIVE_RESOLUTION; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("eff resolution x=%d, y=%d\n", pk.res.x, pk.res.y); pk.ppr.cmd = GET_PIXELS_PER_ROW; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("input width=%d, outwidth=%d\n", pk.ppr.width, pk.ppr.outwidth); pk.ppr.cmd = GET_SRV_VERSION; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("hpijs server %s\n", pk.ver.str); pk.ppr.cmd = GET_PRINTABLE_AREA; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("printable width=%.2f, height=%.2f (inches)\n", pk.parea.width, pk.parea.height); pk.ppr.cmd = GET_PHYSICAL_PAGE_SIZE; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("physical page size x=%.2f, y=%.2f (inches)\n", pk.psize.x, pk.psize.y); pk.ppr.cmd = GET_PRINTABLE_START; hpijs_put_pk(&pk, pdev->sd.fdc2s); hpijs_get_pk(&pk, pdev->sd.fds2c); /* ack */ bug("printable start x=%.2f, y=%.2f (inches)\n", pk.pstart.x, pk.pstart.y); /* End API test code. */ #endif return 0; } private int hpijs_get_params(gx_device * pdev, gs_param_list * plist) { int code = gdev_prn_get_params(pdev, plist); int ecode; if (code < 0) return code; if ((ecode = param_write_int(plist, "PrintMode", &((gx_device_hpijs *)pdev)->PrintMode)) < 0) code = ecode; if ((ecode = param_write_string(plist, "DeviceName", &((gx_device_hpijs *)pdev)->DeviceName)) < 0) code = ecode; return code; } private int hpijs_put_params(gx_device * pdev, gs_param_list * plist) { int ecode = 0; int code; gs_param_name param_name; int pm = ((gx_device_hpijs *)pdev)->PrintMode; gs_param_string dname = ((gx_device_hpijs *)pdev)->DeviceName; switch (code = param_read_int(plist, (param_name = "PrintMode"), &pm)) { case 0: if (pm < 0 || pm > 6) ecode = gs_error_limitcheck; else break; goto jqe; default: ecode = code; jqe:param_signal_error(plist, param_name, ecode); case 1: break; } if ((code = param_read_string(plist, (param_name = "DeviceName"), &dname)) < 0) ecode = code; if (ecode < 0) return ecode; code = gdev_prn_put_params(pdev, plist); if (code < 0) return code; ((gx_device_hpijs *)pdev)->PrintMode = pm; ((gx_device_hpijs *)pdev)->DeviceName = dname; return 0; } private int hpijs_open(gx_device * pdev) { static const float dj_a4[4] = { DESKJET_MARGINS_A4 }; static const float dj_letter[4] = { DESKJET_MARGINS_LETTER }; const float *m = NULL; /* Make sure width does not exceed 8". */ if (pdev->width > (pdev->x_pixels_per_inch * 8)) gx_device_set_width_height(pdev, pdev->x_pixels_per_inch * 8, pdev->height); m = (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? dj_a4 : dj_letter); gx_device_set_margins(pdev, m, true); return gdev_prn_open(pdev); } private int hpijs_close(gx_device * pdev) { hpijs_close_srv(&((gx_device_hpijs *) pdev)->sd); return gdev_prn_close(pdev); } private int white(unsigned char *data, int size) { int clean = 1; int i; for (i = 0; i < size; i++) if (data[i] != 0xFF) { clean = 0; break; } return clean; } private int dj630_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "DJ630"); } private int dj6xx_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "DJ6xx"); } private int dj6xx_photo_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "DJ6xxPhoto"); } private int dj8xx_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "DJ8xx"); } private int dj9xx_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "DJ9xx"); } private int dj9xx_vip_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "DJ9xxVIP"); } private int ap21xx_print_page(gx_device_printer * pdev, FILE * prn_stream) { return hpijs_print_page(pdev, prn_stream, "AP21xx"); } private int hpijs_ext_print_page(gx_device_printer * pdev, FILE * prn_stream) { char name[DEVICE_NAME_MAX]; int len; len = ((gx_device_hpijs *)pdev)->DeviceName.size; if ((len == 0) || (len >= DEVICE_NAME_MAX)) return gs_note_error(gs_error_invalidaccess); strncpy(name, ((gx_device_hpijs *)pdev)->DeviceName.data, len); name[len]=0; return hpijs_print_page(pdev, prn_stream, name); } /* Send the page to the printer. */ private int hpijs_print_page(gx_device_printer * pdev, FILE * prn_stream, const char *dname) { int line_size; int last_row; int lnum, code = 0; int isnew; isnew = gdev_prn_file_is_new(pdev); if (isnew) { if (hpijs_spawn_srv((gx_device_hpijs *)pdev, prn_stream, dname) != 0) return gs_note_error(gs_error_invalidaccess); } line_size = gx_device_raster((gx_device *)pdev, 0); last_row = dev_print_scan_lines(pdev); for (lnum = 0; lnum < last_row; lnum++) { code = gdev_prn_copy_scan_lines(pdev, lnum, ((gx_device_hpijs *) pdev)->sd.shmbuf, line_size); if (code < 0) return -1; if (!white(((gx_device_hpijs *)pdev)->sd.shmbuf, line_size)) { if (hpijs_put_cmd(&((gx_device_hpijs *)pdev)->sd, SND_RASTER) == -1) return -1; } else { if (hpijs_put_cmd (&((gx_device_hpijs *)pdev)->sd, SND_NULL_RASTER) == -1) return -1; } } hpijs_put_cmd(&((gx_device_hpijs *)pdev)->sd, NEW_PAGE); return code; }