1 /*****************************************************************************\
3 pp.c - parallel port support for multi-point transport driver
5 (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 of the Software, and to permit persons to whom the Software is furnished to do
12 so, subject to the following conditions:
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 Client/Server generic message format (see messaging-protocol.doc):
25 \*****************************************************************************/
32 mud_device_vf __attribute__ ((visibility ("hidden"))) pp_mud_device_vf =
38 .get_device_id = pp_get_device_id,
39 .get_device_status = pp_get_device_status,
40 .channel_open = pp_channel_open,
41 .channel_close = pp_channel_close,
42 .channel_write = musb_channel_write,
43 .channel_read = musb_channel_read
46 static mud_channel_vf pp_raw_channel_vf =
48 .open = pp_raw_channel_open,
49 .close = pp_raw_channel_close,
50 .channel_write = musb_raw_channel_write,
51 .channel_read = musb_raw_channel_read
54 static mud_channel_vf pp_mlc_channel_vf =
56 .open = pp_mlc_channel_open,
57 .close = pp_mlc_channel_close,
58 .channel_write = musb_mlc_channel_write,
59 .channel_read = musb_mlc_channel_read
62 static mud_channel_vf pp_dot4_channel_vf =
64 .open = pp_dot4_channel_open,
65 .close = pp_dot4_channel_close,
66 .channel_write = musb_dot4_channel_write,
67 .channel_read = musb_dot4_channel_read
70 static int frob_control(int fd, unsigned char mask, unsigned char val)
72 struct ppdev_frob_struct frob;
74 /* Convert ieee1284 control values to PC-style (invert Strobe, AutoFd and Select) . */
75 frob.val = val ^ (mask & (PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT));
78 return ioctl(fd, PPFCONTROL, &frob);
81 static unsigned char read_status(int fd)
84 if (ioctl(fd, PPRSTATUS, &status))
85 BUG("read_status error: %m\n");
87 /* Convert PC-style status values to ieee1284 (invert Busy). */
88 return (status ^ PARPORT_STATUS_BUSY);
91 static int wait_status(int fd, unsigned char mask, unsigned char val, int usec)
93 struct timeval tmo, now;
98 gettimeofday (&tmo, NULL);
100 tmo.tv_sec += tmo.tv_usec / 1000000;
101 tmo.tv_usec %= 1000000;
104 min.tv_nsec = 5000000; /* 5ms */
108 status = read_status(fd);
109 if ((status & mask) == val)
111 // bug("found status=%x mask=%x val=%x cnt=%d: %s %d\n", status, mask, val, cnt, __FILE__, __LINE__);
115 // nanosleep(&min, NULL);
116 gettimeofday(&now, NULL);
117 if ((now.tv_sec > tmo.tv_sec) || (now.tv_sec == tmo.tv_sec && now.tv_usec > tmo.tv_usec))
119 DBG("wait_status timeout status=%x mask=%x val=%x us=%d\n", status, mask, val, usec);
120 return -1; /* timeout */
125 static int wait(int usec)
127 struct timeval tmo, now;
130 gettimeofday (&tmo, NULL);
132 tmo.tv_sec += tmo.tv_usec / 1000000;
133 tmo.tv_usec %= 1000000;
138 gettimeofday(&now, NULL);
139 if ((now.tv_sec > tmo.tv_sec) || (now.tv_sec == tmo.tv_sec && now.tv_usec > tmo.tv_usec))
141 return 0; /* timeout */
146 static int ecp_is_fwd(int fd)
148 unsigned char status;
150 status = read_status(fd);
151 if ((status & PARPORT_STATUS_PAPEROUT) == PARPORT_STATUS_PAPEROUT)
156 static int ecp_is_rev(int fd)
158 unsigned char status;
160 status = read_status(fd);
161 if ((status & PARPORT_STATUS_PAPEROUT) == 0)
166 static int ecp_rev_to_fwd(int fd)
173 /* Event 47: write NReverseRequest/nInit=1 */
174 frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
176 /* Event 48: wait PeriphClk/nAck=1, PeriphAck/Busy=0 */
177 // wait_status(fd, PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_BUSY, PARPORT_STATUS_PAPEROUT, SIGNAL_TIMEOUT);
179 /* Event 49: wait nAckReverse/PError=1 */
180 wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
182 ioctl(fd, PPDATADIR, &dir);
187 static int ecp_fwd_to_rev(int fd)
194 /* Event 33: NPeriphRequest/nFault=0, PeriphAck/Busy=0 */
195 wait_status(fd, PARPORT_STATUS_BUSY | PARPORT_STATUS_ERROR, 0, PP_DEVICE_TIMEOUT);
197 /* Event 38: write HostAck/nAutoFd=0 */
198 ioctl(fd, PPDATADIR, &dir);
199 frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
200 wait(PP_SETUP_TIMEOUT);
202 /* Event 39: write NReverseRequest/nInit=0 (start bus reversal) */
203 frob_control(fd, PARPORT_CONTROL_INIT, 0);
205 /* Event 40: wait nAckReverse/PError=0 */
206 wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
211 static int ecp_write_addr(int fd, unsigned char data)
214 unsigned d=(data | 0x80); /* set channel address bit */
218 /* Event 33: PeriphAck/Busy=0 */
219 if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_SIGNAL_TIMEOUT))
221 BUG("ecp_write_addr transfer stalled\n");
227 /* Event 34: write HostAck/nAutoFD=0 (channel command), data */
228 frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
229 ioctl(fd, PPWDATA, &d);
231 /* Event 35: write HostClk/NStrobe=0 */
232 frob_control(fd, PARPORT_CONTROL_STROBE, 0);
234 /* Event 36: wait PeriphAck/Busy=1 */
235 if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
238 /* Event 72: write NReverseRequest/nInit=0 (Host Transfer Recovery) */
239 frob_control(fd, PARPORT_CONTROL_INIT, 0);
241 /* Event 73: wait nAckReverse/PError=0 */
242 wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
244 /* Event 74: write NReverseRequest/nInit=1 */
245 frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
247 /* Event 75: wait nAckReverse/PError=1 */
248 wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
253 BUG("ecp_write_addr transfer stalled\n");
256 BUG("ecp_write_addr host transfer recovery cnt=%d\n", cnt);
257 continue; /* retry */
266 /* Event 37: write HostClk/NStrobe=1 */
267 frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
272 static int ecp_write_data(int fd, unsigned char data)
276 // ecp_rev_to_fwd(fd);
278 /* Event 33: check PeriphAck/Busy=0 */
279 if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_SIGNAL_TIMEOUT))
281 BUG("ecp_write_data transfer stalled\n");
287 /* Event 34: write HostAck/nAutoFD=1 (channel data), data */
288 frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
289 ioctl(fd, PPWDATA, &data);
291 /* Event 35: write HostClk/NStrobe=0 */
292 frob_control(fd, PARPORT_CONTROL_STROBE, 0);
294 /* Event 36: wait PeriphAck/Busy=1 */
295 if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
298 /* Event 72: write NReverseRequest/nInit=0 (Host Transfer Recovery) */
299 frob_control(fd, PARPORT_CONTROL_INIT, 0);
301 /* Event 73: wait nAckReverse/PError=0 */
302 wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
304 /* Event 74: write NReverseRequest/nInit=1 */
305 frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
307 /* Event 75: wait nAckReverse/PError=1 */
308 wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
313 BUG("ecp_write_data transfer stalled\n");
316 BUG("ecp_write_data host transfer recovery cnt=%d\n", cnt);
317 continue; /* retry */
326 /* Event 37: write HostClk/NStrobe=1 */
327 frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
332 static int ecp_read_data(int fd, unsigned char *data)
336 // ecp_fwd_to_rev(fd);
338 /* Event 43: wait PeriphClk/NAck=0 */
339 if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
344 ioctl(fd, PPRDATA, data);
346 /* Event 44: write HostAck/nAutoFd=1 */
347 frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
349 /* Event 45: wait PeriphClk/NAck=1 */
350 wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
352 /* Event 46: write HostAck/nAutoFd=0 */
353 frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
362 static int ecp_read(int fd, void *buffer, int size, int usec)
365 unsigned char *p = (unsigned char *)buffer;
371 if (ecp_read_data(fd, p+i) != 1)
373 usec-=PP_SIGNAL_TIMEOUT;
378 return -ETIMEDOUT; /* timeout */
385 static int ecp_write(int fd, const void *buffer, int size)
388 unsigned char *p = (unsigned char *)buffer;
389 static int timeout=0;
394 return -1; /* report timeout */
399 for (i=0; i < size; i++)
401 if (ecp_write_data(fd, p[i]) != 1)
404 timeout=1; /* save timeout, report bytes written */
406 i=-1; /* report timeout */
413 static int nibble_read_data(int fd, unsigned char *data)
416 unsigned char nibble;
418 /* Event 7: write HostBusy/nAutoFd=0 */
419 frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
421 /* Event 8: peripheral sets low-order nibble. */
423 /* Event 9: wait PtrClk/NAck=0 */
424 if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
429 nibble = read_status(fd) >> 3;
430 nibble = ((nibble & 0x10) >> 1) | (nibble & 0x7);
433 /* Event 10: write HostBusy/nAutoFd=1 */
434 frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
436 /* Event 11: wait PtrClk/NAck=1 */
437 wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
439 /* Event 7: write HostBusy/nAutoFd=0 */
440 frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
442 /* Event 8: peripheral sets high-order nibble. */
444 /* Event 9: wait PtrClk/NAck=0 */
445 if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
450 nibble = read_status(fd) >> 3;
451 nibble = ((nibble & 0x10) >> 1) | (nibble & 0x7);
452 *data |= (nibble<<4);
454 /* Event 10: write HostBusy/nAutoFd=1 */
455 frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
457 /* Event 11: wait PtrClk/NAck=1 */
458 wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
467 static int nibble_read(int fd, int flag, void *buffer, int size, int usec)
470 unsigned char *p = (unsigned char *)buffer;
471 int m = IEEE1284_MODE_NIBBLE | flag;
472 int mc = IEEE1284_MODE_COMPAT;
473 unsigned char status;
475 ioctl (fd, PPNEGOT, &mc);
476 if (ioctl (fd, PPNEGOT, &m))
478 DBG("nibble_read negotiation failed: %m\n");
484 if (nibble_read_data(fd, p+i) != 1)
486 usec-=PP_SIGNAL_TIMEOUT;
491 return -ETIMEDOUT; /* timeout */
497 status = read_status(fd);
498 if (status & PARPORT_STATUS_ERROR)
500 /* Event 7: write HostBusy/nAutoFd=0, idle phase */
501 frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
510 static int compat_write_data(int fd, unsigned char data)
515 if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_DEVICE_TIMEOUT))
517 BUG("compat_write_data transfer stalled\n");
521 ioctl(fd, PPWDATA, &data);
522 wait(PP_SETUP_TIMEOUT);
524 /* write NStrobe=0 */
525 frob_control(fd, PARPORT_CONTROL_STROBE, 0);
528 if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
530 BUG("compat_write_data transfer stalled\n");
534 /* write nStrobe=1 */
535 frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
543 static int compat_write(int fd, const void *buffer, int size)
546 unsigned char *p = (unsigned char *)buffer;
547 int m = IEEE1284_MODE_COMPAT;
548 static int timeout=0;
553 return -1; /* report timeout */
556 if (ioctl(fd, PPNEGOT, &m))
558 BUG("compat_write failed: %m\n");
562 for (i=0; i < size; i++)
564 if (compat_write_data(fd, p[i]) != 1)
567 timeout=1; /* save timeout, report bytes written */
569 i=-1; /* report timeout */
578 static int claim_pp(int fd)
582 /* Claim parallel port (can block forever). */
583 if (ioctl(fd, PPCLAIM))
585 BUG("failed claim_pp fd=%d: %m\n", fd);
589 DBG("claimed pp fd=%d\n", fd);
597 static int release_pp(int fd)
599 int stat=1, m=IEEE1284_MODE_COMPAT;
601 /* Restore compat_mode (default), otherwise close(fd) may block restoring compat_mode. */
602 if (ioctl(fd, PPNEGOT, &m))
604 BUG("failed release_pp fd=%d: %m\n", fd);
608 ioctl(fd, PPRELEASE);
610 DBG("released pp fd=%d\n", fd);
618 static int device_id(int fd, char *buffer, int size)
622 maxSize = (size > 1024) ? 1024 : size; /* RH8 has a size limit for device id */
624 len = nibble_read(fd, IEEE1284_DEVICEID, buffer, maxSize, 0);
627 BUG("unable to read device-id ret=%d\n", len);
632 len = size-1; /* leave byte for zero termination */
635 memcpy(buffer, buffer+2, len); /* remove length */
638 DBG("read actual device_id successfully fd=%d len=%d\n", fd, len);
641 return len; /* length does not include zero termination */
644 static int device_status(int fd, unsigned int *status)
647 unsigned char byte = NFAULT_BIT; /* set default */
649 m = IEEE1284_MODE_COMPAT;
650 if (ioctl (fd, PPNEGOT, &m))
652 BUG("unable to read device_status: %m\n");
653 stat = HPMUD_R_IO_ERROR;
656 byte = read_status(fd);
658 *status = (unsigned int)byte;
660 DBG("read actual device_status successfully fd=%d\n", fd);
666 /* Create channel object given the requested socket id and service name. */
667 static int new_channel(mud_device *pd, int index, const char *sn)
671 /* Check for existing name service already open. */
672 if (pd->channel[index].client_cnt)
675 if (index == HPMUD_EWS_CHANNEL)
677 pd->channel[index].client_cnt++; /* allow multiple clients for separate USB interfaces only */
679 DBG("reused %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
683 BUG("%s channel=%d is busy, used by [%d], clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].pid, pd->channel[index].client_cnt, pd->channel_cnt);
687 if (pd->io_mode == HPMUD_RAW_MODE || pd->io_mode == HPMUD_UNI_MODE)
688 pd->channel[index].vf = pp_raw_channel_vf;
689 else if (pd->io_mode == HPMUD_MLC_GUSHER_MODE || pd->io_mode == HPMUD_MLC_MISER_MODE)
690 pd->channel[index].vf = pp_mlc_channel_vf;
692 pd->channel[index].vf = pp_dot4_channel_vf;
694 pd->channel[index].index = index;
695 pd->channel[index].client_cnt = 1;
696 pd->channel[index].sockid = index; /* static socket id is valid for MLC but not 1284.4 */
697 pd->channel[index].pid = getpid();
698 pd->channel[index].dindex = pd->index;
699 pd->channel[index].fd = -1;
700 strcpy(pd->channel[index].sn, sn);
704 DBG("new %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
710 /* Remove channel object given the channel decriptor. */
711 static int del_channel(mud_device *pd, mud_channel *pc)
715 if (pc->client_cnt <= 0)
719 DBG("removed %s channel=%d clientCnt=%d channelCnt=%d\n", pc->sn, pc->index, pc->client_cnt, pd->channel_cnt);
723 /*********************************************************************************************************************************
724 * Parallel port mud_device functions.
727 int __attribute__ ((visibility ("hidden"))) pp_write(int fd, const void *buf, int size, int usec)
731 ioctl(fd, PPGETMODE, &m);
733 if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
735 len = ecp_write(fd, buf, size);
739 len = compat_write(fd, buf, size);
742 DBG("write fd=%d len=%d size=%d\n", fd, len, size);
743 DBG_DUMP(buf, len < 32 ? len : 32);
748 int __attribute__ ((visibility ("hidden"))) pp_read(int fd, void *buf, int size, int usec)
751 // int sec = usec/1000000;
753 ioctl(fd, PPGETMODE, &m);
755 if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
757 len = ecp_read(fd, buf, size, usec);
761 len = nibble_read(fd, 0, buf, size, usec);
764 DBG("read fd=%d len=%d size=%d usec=%d\n", fd, len, size, usec);
765 DBG_DUMP(buf, len < 32 ? len : 32);
770 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_open(mud_device *pd)
772 char dev[255], uriModel[128], model[128];
774 enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
776 pthread_mutex_lock(&pd->mutex);
778 hpmud_get_uri_model(pd->uri, uriModel, sizeof(uriModel));
782 /* First client, open actual kernal device, use blocking i/o. */
783 hpmud_get_uri_datalink(pd->uri, dev, sizeof(dev));
784 if ((fd = open(dev, O_RDWR | O_NOCTTY)) < 0)
786 BUG("unable to open %s: %m\n", pd->uri);
790 /* Open can succeed with no connected device, see if this is a valid device. */
791 if (ioctl(fd, PPGETMODES, &m))
793 BUG("unable to open %s: %m\n", pd->uri);
797 /* Claim parallel port (can block forever). */
801 len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy and cache it */
803 if (len > 0 && is_hp(pd->id))
814 /* Make sure uri model matches device id model. */
815 hpmud_get_model(pd->id, model, sizeof(model));
816 if (strcmp(uriModel, model) != 0)
818 stat = HPMUD_R_INVALID_DEVICE_NODE; /* probably a laserjet, or different device plugged in */
819 BUG("invalid model %s != %s\n", uriModel, model);
826 pthread_mutex_unlock(&pd->mutex);
830 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_close(mud_device *pd)
832 enum HPMUD_RESULT stat = HPMUD_R_OK;
834 pthread_mutex_lock(&pd->mutex);
842 pthread_mutex_unlock(&pd->mutex);
847 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_id(mud_device *pd, char *buf, int size, int *len)
849 int m, fd = pd->open_fd;
850 enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
854 pthread_mutex_lock(&pd->mutex);
858 stat = HPMUD_R_INVALID_STATE;
859 BUG("invalid get_device_id state\n");
863 if (pd->io_mode == HPMUD_UNI_MODE)
865 *len = strlen(pd->id); /* use cached copy */
866 DBG("using cached device_id io_mode=%d\n", pd->io_mode);
870 ioctl(fd, PPGETMODE, &m);
871 if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
873 *len = strlen(pd->id); /* channel is busy, return cached copy. */
874 DBG("using cached device_id m=%x\n", m);
878 if (pd->channel_cnt == 0)
880 /* Device not in use. Claim it, but release for other processes. */
883 *len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy */
888 /* Device already claimed by open_channel. */
889 *len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy */
896 memcpy(buf, pd->id, *len > size ? size : *len);
901 pthread_mutex_unlock(&pd->mutex);
905 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_status(mud_device *pd, unsigned int *status)
908 enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
911 pthread_mutex_lock(&pd->mutex);
915 stat = HPMUD_R_INVALID_STATE;
916 BUG("invalid get_device_id state\n");
920 if (pd->io_mode == HPMUD_UNI_MODE)
922 *status = NFAULT_BIT; /* fake status */
923 DBG("using cached device_status io_mode=%d\n", pd->io_mode);
927 ioctl(fd, PPGETMODE, &m);
928 if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
930 *status = NFAULT_BIT; /* channel is busy, fake 8-bit status */
931 DBG("using cached device_status m=%x\n", m);
935 if (pd->channel_cnt == 0)
937 /* Device not in use. Claim it, but release for other processes. */
940 r = device_status(fd, status);
945 /* Device already claimed by open_channel. */
946 r = device_status(fd, status);
957 pthread_mutex_unlock(&pd->mutex);
961 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_open(mud_device *pd, const char *sn, HPMUD_CHANNEL *cd)
964 enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
966 /* Check for valid service requests. */
967 if ((stat = service_to_channel(pd, sn, &index)) != HPMUD_R_OK)
970 pthread_mutex_lock(&pd->mutex);
972 if (new_channel(pd, index, sn))
974 stat = HPMUD_R_DEVICE_BUSY;
978 if ((stat = (pd->channel[index].vf.open)(&pd->channel[index])) != HPMUD_R_OK) /* call transport specific open */
979 del_channel(pd, &pd->channel[index]); /* open failed, cleanup */
984 pthread_mutex_unlock(&pd->mutex);
990 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_close(mud_device *pd, mud_channel *pc)
992 enum HPMUD_RESULT stat = HPMUD_R_OK;
994 pthread_mutex_lock(&pd->mutex);
995 stat = (pc->vf.close)(pc); /* call trasport specific close */
997 pthread_mutex_unlock(&pd->mutex);
1002 /*******************************************************************************************************************************
1003 * Parallel port raw_channel functions.
1006 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_open(mud_channel *pc)
1008 mud_device *pd = &msp->device[pc->dindex];
1009 if (claim_pp(pd->open_fd))
1010 return HPMUD_R_IO_ERROR;
1011 pc->fd = pd->open_fd;
1015 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_close(mud_channel *pc)
1023 /*******************************************************************************************************************************
1024 * Parallel port mlc_channel functions.
1027 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_open(mud_channel *pc)
1029 mud_device *pd = &msp->device[pc->dindex];
1030 enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
1033 /* Initialize MLC transport if this is the first MLC channel. */
1034 if (pd->channel_cnt==1)
1036 if (claim_pp(pd->open_fd))
1039 /* Negotiate ECP mode. */
1040 m = IEEE1284_MODE_ECPSWE;
1041 if (ioctl(pd->open_fd, PPNEGOT, &m))
1043 BUG("unable to negotiate %s ECP mode: %m\n", pd->uri);
1047 /* Enable MLC mode with ECP channel-77. */
1048 ecp_write_addr(pd->open_fd, 78);
1049 ecp_write(pd->open_fd, "\0", 1);
1050 ecp_write_addr(pd->open_fd, 77);
1052 /* MLC initialize */
1053 if (MlcInit(pc, pd->open_fd) != 0)
1056 /* Reset transport attributes for all channels. */
1057 for (i=0; i<HPMUD_CHANNEL_MAX; i++)
1058 memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
1060 pd->mlc_fd = pd->open_fd;
1063 } /* if (pDev->ChannelCnt==1) */
1065 if (MlcConfigSocket(pc, pd->mlc_fd))
1068 if (MlcOpenChannel(pc, pd->mlc_fd))
1071 pc->rcnt = pc->rindex = 0;
1079 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_close(mud_channel *pc)
1081 mud_device *pd = &msp->device[pc->dindex];
1082 enum HPMUD_RESULT stat = HPMUD_R_OK;
1087 if (MlcCloseChannel(pc, pd->mlc_fd))
1088 stat = HPMUD_R_IO_ERROR;
1091 /* Remove MLC transport if this is the last MLC channel. */
1092 if (pd->channel_cnt==1)
1096 if (MlcExit(pc, pd->mlc_fd))
1097 stat = HPMUD_R_IO_ERROR;
1101 ecp_write_addr(pd->mlc_fd, 78); /* disable MLC mode with ECP channel-78 */
1102 ecp_write(pd->mlc_fd, "\0", 1);
1104 m = IEEE1284_MODE_NIBBLE;
1105 ioctl(pd->mlc_fd, PPNEGOT, &m);
1106 release_pp(pd->mlc_fd);
1108 /* Delay for batch scanning. */
1115 /*******************************************************************************************************************************
1116 * Parallel port dot4_channel functions.
1119 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_open(mud_channel *pc)
1121 mud_device *pd = &msp->device[pc->dindex];
1122 enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
1125 /* Initialize MLC transport if this is the first MLC channel. */
1126 if (pd->channel_cnt==1)
1128 if (claim_pp(pd->open_fd))
1131 /* Negotiate ECP mode. */
1132 m = IEEE1284_MODE_ECPSWE;
1133 if (ioctl(pd->open_fd, PPNEGOT, &m))
1135 BUG("unable to negotiate %s ECP mode: %m\n", pd->uri);
1139 /* Enable MLC mode with ECP channel-77. */
1140 ecp_write_addr(pd->open_fd, 78);
1141 ecp_write(pd->open_fd, "\0", 1);
1142 ecp_write_addr(pd->open_fd, 77);
1144 /* DOT4 initialize */
1145 if (Dot4Init(pc, pd->open_fd) != 0)
1148 /* Reset transport attributes for all channels. */
1149 for (i=0; i<HPMUD_CHANNEL_MAX; i++)
1150 memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
1152 pd->mlc_fd = pd->open_fd;
1155 } /* if (pDev->ChannelCnt==1) */
1157 if (Dot4GetSocket(pc, pd->mlc_fd))
1160 if (Dot4OpenChannel(pc, pd->mlc_fd))
1163 pc->rcnt = pc->rindex = 0;
1171 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_close(mud_channel *pc)
1173 mud_device *pd = &msp->device[pc->dindex];
1174 enum HPMUD_RESULT stat = HPMUD_R_OK;
1179 if (Dot4CloseChannel(pc, pd->mlc_fd))
1180 stat = HPMUD_R_IO_ERROR;
1183 /* Remove MLC transport if this is the last MLC channel. */
1184 if (pd->channel_cnt==1)
1188 if (Dot4Exit(pc, pd->mlc_fd))
1189 stat = HPMUD_R_IO_ERROR;
1193 ecp_write_addr(pd->mlc_fd, 78); /* disable MLC mode with ECP channel-78 */
1194 ecp_write(pd->mlc_fd, "\0", 1);
1196 m = IEEE1284_MODE_NIBBLE;
1197 ioctl(pd->mlc_fd, PPNEGOT, &m);
1198 release_pp(pd->mlc_fd);
1200 /* Delay for batch scanning. */
1207 /*******************************************************************************************************************************
1208 * Parallel port probe devices, walk the parallel port bus(s) looking for HP products.
1211 int __attribute__ ((visibility ("hidden"))) pp_probe_devices(char *lst, int lst_size, int *cnt)
1213 struct hpmud_model_attributes ma;
1214 char dev[HPMUD_LINE_SIZE];
1218 int i, size=0, fd, m;
1220 for (i=0; i < 4; i++)
1222 sprintf(dev, "/dev/parport%d", i);
1224 if ((fd = open(dev, O_RDONLY | O_NOCTTY)) < 0)
1227 /* Silently check the port for valid device (no syslog errors). */
1228 if (ioctl(fd, PPGETMODES, &m) == 0)
1230 if (claim_pp(fd) == 0)
1232 if (device_id(fd, id, sizeof(id)) > 0 && is_hp(id))
1234 hpmud_get_model(id, model, sizeof(model));
1235 hpmud_get_raw_model(id, rmodel, sizeof(rmodel));
1236 snprintf(dev, sizeof(dev), "hp:/par/%s?device=/dev/parport%d", model, i);
1238 /* See if device is supported by hplip. */
1239 hpmud_query_model(dev, &ma);
1240 if (ma.support != HPMUD_SUPPORT_TYPE_HPLIP)
1242 BUG("ignoring %s support=%d\n", dev, ma.support);
1243 continue; /* ignor, not supported */
1246 if (strncasecmp(rmodel, "hp ", 3) == 0)
1247 size += sprintf(lst+size,"direct %s \"HP %s\" \"HP %s LPT parport%d HPLIP\" \"%s\"\n", dev, &rmodel[3], &rmodel[3], i, id);
1249 size += sprintf(lst+size,"direct %s \"HP %s\" \"HP %s LPT parport%d HPLIP\" \"%s\"\n", dev, rmodel, rmodel, i, id);
1256 BUG("unable to probe %s: %m\n", dev); /* device is busy */
1264 enum HPMUD_RESULT hpmud_make_par_uri(const char *dnode, char *uri, int uri_size, int *bytes_read)
1268 enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
1271 DBG("[%d] hpmud_make_par_uri() dnode=%s\n", getpid(), dnode);
1277 if ((fd = open(dnode, O_RDONLY | O_NOCTTY)) < 0)
1279 BUG("unable to open %s: %m\n", dnode);
1283 if (ioctl(fd, PPGETMODES, &m))
1285 BUG("unable to make uri %s: %m\n", dnode);
1291 BUG("unable to make uri %s: %m\n", dnode); /* device is busy */
1295 if (device_id(fd, id, sizeof(id)) > 0 && is_hp(id))
1297 hpmud_get_model(id, model, sizeof(model));
1298 *bytes_read = snprintf(uri, uri_size, "hp:/par/%s?device=%s", model, dnode);
1310 #endif /* HAVE_PPORT */