summaryrefslogtreecommitdiff
path: root/io
diff options
context:
space:
mode:
authorJinkun Jang <jinkun.jang@samsung.com>2013-03-13 01:42:35 +0900
committerJinkun Jang <jinkun.jang@samsung.com>2013-03-13 01:42:35 +0900
commit72835b3d805ac6c7cdaac7d3aff107567e938314 (patch)
tree0f2a04dc3d0672c0960a62804c6e7758673e393c /io
parenteb5e5ee9adb02776056d1b4494f66150a2fc45f1 (diff)
downloadhplip-72835b3d805ac6c7cdaac7d3aff107567e938314.tar.gz
hplip-72835b3d805ac6c7cdaac7d3aff107567e938314.tar.bz2
hplip-72835b3d805ac6c7cdaac7d3aff107567e938314.zip
Tizen 2.1 base
Diffstat (limited to 'io')
-rw-r--r--io/hpmud/dot4.c750
-rw-r--r--io/hpmud/dot4.h187
-rw-r--r--io/hpmud/hp-mkuri.c543
-rw-r--r--io/hpmud/hpmud.c699
-rw-r--r--io/hpmud/hpmud.h581
-rw-r--r--io/hpmud/hpmudi.h212
-rw-r--r--io/hpmud/jd.c906
-rw-r--r--io/hpmud/jd.h56
-rw-r--r--io/hpmud/list.h131
-rw-r--r--io/hpmud/mlc.c772
-rw-r--r--io/hpmud/mlc.h150
-rw-r--r--io/hpmud/model.c633
-rw-r--r--io/hpmud/musb.c2197
-rw-r--r--io/hpmud/musb.h121
-rw-r--r--io/hpmud/pml.c520
-rw-r--r--io/hpmud/pml.h77
-rw-r--r--io/hpmud/pp.c1310
-rw-r--r--io/hpmud/pp.h100
-rw-r--r--io/mudext/hpmudext.c495
19 files changed, 10440 insertions, 0 deletions
diff --git a/io/hpmud/dot4.c b/io/hpmud/dot4.c
new file mode 100644
index 0000000..ba56e53
--- /dev/null
+++ b/io/hpmud/dot4.c
@@ -0,0 +1,750 @@
+/*****************************************************************************\
+
+ dot4.c - 1284.4 support multi-point tranport driver
+
+ (c) 2005-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#include "hpmud.h"
+#include "hpmudi.h"
+
+/*
+ * This 1284.4 implementation does not support "Multiple Outstanding Transactions" which is optional.
+ */
+
+/* Write command reply back to peripheral. */
+static int Dot4ForwardReply(mud_channel *pc, int fd, unsigned char *buf, int size)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int len=0;
+
+ if ((len = (pd->vf.write)(fd, buf, size, HPMUD_EXCEPTION_TIMEOUT)) != size)
+ {
+ BUG("unable to Dot4ForwarReply: %m\n");
+ }
+ return len;
+}
+
+/* Execute command from peripheral. */
+static int Dot4ExecReverseCmd(mud_channel *pc, int fd, unsigned char *buf)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ mud_channel *out_of_bound_channel;
+ DOT4Cmd *pCmd;
+ DOT4Reply *pReply;
+ DOT4Credit *pCredit;
+ DOT4CreditReply *pCreditReply;
+ DOT4CreditRequest *pCreditReq;
+ DOT4CreditRequestReply *pCreditReqReply;
+ DOT4Error *pError;
+ int len, size;
+ unsigned char socket;
+ static int cnt;
+
+ pCmd = (DOT4Cmd *)buf;
+
+ /* See if this packet is a command packet. */
+ if (!(pCmd->h.psid == 0 && pCmd->h.ssid == 0))
+ {
+ if (pCmd->h.psid == pCmd->h.ssid)
+ {
+ /* Got a valid data packet handle it. This can happen when channel_read timeouts and p2hcredit=1. */
+ out_of_bound_channel = &pd->channel[pCmd->h.psid];
+
+ if (out_of_bound_channel->ta.p2hcredit <= 0)
+ {
+ BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
+ return 0;
+ }
+
+ size = ntohs(pCmd->h.length) - sizeof(DOT4Header);
+ if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
+ {
+ BUG("invalid data packet size=%d\n", size);
+ return 0;
+ }
+ memcpy(&out_of_bound_channel->rbuf[out_of_bound_channel->rcnt], buf+sizeof(MLCHeader), size);
+ out_of_bound_channel->rcnt += size;
+ if (pCmd->h.credit)
+ out_of_bound_channel->ta.h2pcredit += pCmd->h.credit; /* note, piggy back credit is 1 byte wide */
+ out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
+ }
+ else
+ {
+ len = ntohs(pCmd->h.length);
+ BUG("unsolicited data packet: psid=%x, ssid=%x, length=%d, credit=%d, status=%x\n", pCmd->h.psid,
+ pCmd->h.ssid, len, pCmd->h.credit, pCmd->h.control);
+ DBG_DUMP(buf, len);
+ }
+ return 0;
+ }
+
+ /* Process any command. */
+ switch (pCmd->cmd)
+ {
+ case DOT4_CREDIT:
+ pCredit = (DOT4Credit *)buf;
+ out_of_bound_channel = &pd->channel[pCredit->psocket];
+ out_of_bound_channel->ta.h2pcredit += ntohs(pCredit->credit);
+ pCreditReply = (DOT4CreditReply *)buf;
+ pCreditReply->h.length = htons(sizeof(DOT4CreditReply));
+ pCreditReply->h.credit = 1; /* transaction credit for next command */
+ pCreditReply->h.control = 0;
+ pCreditReply->cmd |= 0x80;
+ pCreditReply->result = 0;
+ pCreditReply->psocket = out_of_bound_channel->sockid;
+ pCreditReply->ssocket = out_of_bound_channel->sockid;
+ Dot4ForwardReply(pc, fd, (unsigned char *)pCreditReply, sizeof(DOT4CreditReply));
+ break;
+ case DOT4_CREDIT_REQUEST:
+ pCreditReq = (DOT4CreditRequest *)buf;
+ if (cnt++ < 5)
+ BUG("unexpected DOT4CreditRequest: cmd=%x, hid=%x, pid=%x, maxcredit=%d\n", pCreditReq->cmd,
+ pCreditReq->psocket, pCreditReq->ssocket, ntohs(pCreditReq->maxcredit));
+ socket = pCreditReq->ssocket;
+ pCreditReqReply = (DOT4CreditRequestReply *)buf;
+ pCreditReqReply->h.length = htons(sizeof(DOT4CreditRequestReply));
+ pCreditReqReply->h.credit = 1; /* transaction credit for next command */
+ pCreditReqReply->h.control = 0;
+ pCreditReqReply->cmd |= 0x80;
+ pCreditReqReply->result = 0;
+ pCreditReqReply->psocket = socket;
+ pCreditReqReply->ssocket = socket;
+ pCreditReqReply->credit = 0;
+ Dot4ForwardReply(pc, fd, (unsigned char *)pCreditReqReply, sizeof(DOT4CreditRequestReply));
+ break;
+ case DOT4_ERROR:
+ pError = (DOT4Error *)buf;
+ BUG("unexpected DOT4Error: cmd=%x, psocket=%d, ssocket=%d, error=%x\n", pError->cmd, pError->psocket, pError->ssocket, pError->error);
+ return 1;
+ default:
+ pReply = (DOT4Reply *)buf;
+ BUG("unexpected command: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ pReply->h.length = htons(sizeof(DOT4Reply));
+ pReply->h.credit = 1; /* transaction credit for next command */
+ pReply->h.control = 0;
+ pReply->cmd |= 0x80;
+ pReply->result = 1;
+ Dot4ForwardReply(pc, fd, (unsigned char *)pReply, sizeof(DOT4Reply));
+ break;
+ }
+ return 0;
+}
+
+/* Get command from peripheral and processes the reverse command. */
+int __attribute__ ((visibility ("hidden"))) Dot4ReverseCmd(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, size;
+ unsigned int pklen;
+ unsigned char *pBuf;
+ DOT4Reply *pPk;
+
+ pPk = (DOT4Reply *)buf;
+
+ pBuf = buf;
+
+ /* Read packet header. */
+ size = sizeof(DOT4Header);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read Dot4ReverseCmd header: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ /* Determine packet size. */
+ if ((pklen = ntohs(pPk->h.length)) > sizeof(buf))
+ {
+ BUG("invalid Dot4ReverseCmd packet size: size=%d\n", pklen);
+ stat = 1;
+ goto bugout;
+ }
+
+ /* Read packet data field. */
+ size = pklen - sizeof(DOT4Header);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read Dot4ReverseCmd data: %m exp=%zd act=%zd\n", pklen-sizeof(DOT4Header), pklen-sizeof(DOT4Header)-size);
+ stat = 1;
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ stat = Dot4ExecReverseCmd(pc, fd, buf);
+
+bugout:
+ return stat;
+}
+
+/*
+ * Get command reply from peripheral. Waits for reply then returns. Processes any reverse commands
+ * while waiting for a reply.
+ */
+static int Dot4ReverseReply(mud_channel *pc, int fd, unsigned char *buf, int bufsize)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int stat=0, len, size, pklen;
+ unsigned char *pBuf;
+ DOT4Reply *pPk;
+
+ pPk = (DOT4Reply *)buf;
+
+ while (1)
+ {
+ pBuf = buf;
+
+ /* Read packet header. */
+ size = sizeof(DOT4Header);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, 4000000)) < 0) /* wait 4 seconds, 2 fails on PS2575 1200dpi uncompressed scanning */
+ {
+ BUG("unable to read Dot4ReverseReply header: %m bytesRead=%zd\n", sizeof(DOT4Header)-size);
+ stat = 2; /* short timeout */
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ /* Determine packet size. */
+ pklen = ntohs(pPk->h.length);
+ if (pklen <= 0 || pklen > bufsize)
+ {
+ BUG("invalid Dot4ReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
+ stat = 1;
+ goto bugout;
+ }
+
+ /* Read packet data field. */
+ size = pklen - sizeof(DOT4Header);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read Dot4ReverseReply data: %m exp=%zd act=%zd\n", pklen-sizeof(DOT4Header), pklen-sizeof(DOT4Header)-size);
+ stat = 1;
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ /* Check for reply. */
+ if (pPk->cmd & 0x80)
+ break;
+
+ stat = Dot4ExecReverseCmd(pc, fd, buf);
+
+ if (stat != 0)
+ break;
+
+ } /* while (1) */
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4Init(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n, cnt;
+ DOT4Init *pCmd;
+ DOT4InitReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4Init));
+ pCmd = (DOT4Init *)buf;
+ n = sizeof(DOT4Init);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1; /* transaction credit for reply */
+ pCmd->cmd = DOT4_INIT;
+ pCmd->rev = 0x20;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write DOT4Init: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ cnt=0;
+ while(1)
+ {
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4InitReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_INIT)) || (pReply->result != 0))
+ {
+ if (errno == EIO && cnt<1)
+ {
+ /* hack for usblp.c 2.6.5 */
+ BUG("invalid DOT4InitReply retrying...\n");
+ sleep(1);
+ cnt++;
+ continue;
+ }
+ if (stat == 2 && cnt<1)
+ {
+ /* hack for Fullhouse, Swami and Northstar */
+ BUG("invalid DOT4InitReply retrying command...\n");
+ memset(buf, 0, sizeof(DOT4Init));
+ n = sizeof(DOT4Init);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1; /* transaction credit for reply */
+ pCmd->cmd = DOT4_INIT;
+ pCmd->rev = 0x20;
+ (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT);
+ cnt++;
+ continue;
+ }
+ BUG("invalid DOT4InitReply: cmd=%x, result=%x\n, revision=%x\n", pReply->cmd, pReply->result, pReply->rev);
+ stat = 1;
+ goto bugout;
+ }
+ break;
+ }
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4Exit(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ DOT4Exit *pCmd;
+ DOT4ExitReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4Exit));
+ pCmd = (DOT4Exit *)buf;
+ n = sizeof(DOT4Exit);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1;
+ pCmd->cmd = DOT4_EXIT;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write DOT4Exit: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4ExitReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_EXIT)) || (pReply->result != 0))
+ {
+ BUG("invalid DOT4ExitReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4GetSocket(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ DOT4GetSocket *pCmd;
+ DOT4GetSocketReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4GetSocket));
+ pCmd = (DOT4GetSocket *)buf;
+ n = sizeof(DOT4GetSocket);
+ len = strlen(pc->sn);
+ memcpy(buf+sizeof(DOT4GetSocket), pc->sn, len);
+ n += len;
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1;
+ pCmd->cmd = DOT4_GET_SOCKET;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write DOT4GetSocket: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4GetSocketReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_GET_SOCKET)) || (pReply->result != 0))
+ {
+ BUG("invalid DOT4GetSocketReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->sockid = pReply->socket;
+
+ if (pc->sockid != pc->index)
+ BUG("invalid sockid match sockid=%d index=%d\n", pc->sockid, pc->index);
+
+bugout:
+ return stat;
+}
+
+/* Write data to peripheral. */
+int __attribute__ ((visibility ("hidden"))) Dot4ForwardData(mud_channel *pc, int fd, const void *buf, int size, int usec_timeout)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int stat=0, len, n;
+ DOT4Header h;
+
+ memset(&h, 0, sizeof(h));
+ n = sizeof(DOT4Header) + size;
+ h.length = htons(n);
+ h.psid = pc->sockid;
+ h.ssid = pc->sockid;
+
+ if ((len = (pd->vf.write)(fd, &h, sizeof(DOT4Header), usec_timeout)) != sizeof(DOT4Header))
+ {
+ BUG("unable to write Dot4ForwardData header: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ if ((len = (pd->vf.write)(fd, buf, size, usec_timeout)) != size)
+ {
+ BUG("unable to write Dot4ForwardData: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+bugout:
+ return stat;
+}
+
+/* Read data from peripheral. */
+int __attribute__ ((visibility ("hidden"))) Dot4ReverseData(mud_channel *pc, int fd, void *buf, int length, int usec_timeout)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ mud_channel *out_of_bound_channel;
+ int len, size, total;
+ DOT4Header *pPk;
+
+ pPk = (DOT4Header *)buf;
+
+ while (1)
+ {
+ total = 0;
+
+ /* Read packet header. */
+ size = sizeof(DOT4Header);
+ while (size > 0)
+ {
+ /* Use requested client timeout until we start reading. */
+ if (total == 0)
+ len = (pd->vf.read)(fd, buf+total, size, usec_timeout);
+ else
+ len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT);
+
+ if (len < 0)
+ {
+ /* Got a timeout, if exception timeout or timeout occured after read started thats an error. */
+ if (usec_timeout >= HPMUD_EXCEPTION_TIMEOUT || total > 0)
+ BUG("unable to read Dot4ReverseData header: %m %s\n", pd->uri);
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ }
+
+ /* Determine data size. */
+ size = ntohs(pPk->length) - sizeof(DOT4Header);
+
+ if (size > length)
+ {
+ BUG("invalid Dot4ReverseData size: size=%d, buf=%d\n", size, length);
+ goto bugout;
+ }
+
+ /* Make sure data packet is for this channel. */
+ if (pPk->psid != pc->sockid && pPk->ssid != pc->sockid)
+ {
+ if (pPk->psid == 0 && pPk->ssid == 0)
+ {
+ /* Ok, got a command channel packet instead of a data packet, handle it... */
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read Dot4ReverseData command: %m\n");
+ goto bugout;
+ }
+ size-=len;
+ total=len;
+ }
+ Dot4ExecReverseCmd(pc, fd, buf);
+ continue; /* try again for data packet */
+ }
+ else if (pPk->psid == pPk->ssid)
+ {
+ /* Got a valid data packet for another channel handle it. This can happen when ReadData timeouts and p2hcredit=1. */
+ out_of_bound_channel = &pd->channel[pPk->psid];
+ unsigned char *pBuf;
+
+ if (out_of_bound_channel->ta.p2hcredit <= 0)
+ {
+ BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
+ goto bugout;
+ }
+
+ if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
+ {
+ BUG("invalid data packet size=%d\n", size);
+ goto bugout;
+ }
+
+ total = 0;
+ pBuf = &out_of_bound_channel->rbuf[out_of_bound_channel->rcnt];
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseData: %m\n");
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ }
+
+ out_of_bound_channel->rcnt += total;
+ if (pPk->credit)
+ out_of_bound_channel->ta.h2pcredit += pPk->credit; /* note, piggy back credit is 1 byte wide */
+ out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
+ continue; /* try again for data packet */
+ }
+ else
+ {
+ DOT4Cmd *pCmd = (DOT4Cmd *)buf;
+ BUG("invalid Dot4ReverseData state: unexpected packet psid=%x, ssid=%x, cmd=%x\n", pPk->psid, pPk->ssid, pCmd->cmd);
+ goto bugout;
+ }
+ }
+
+ if (pPk->credit)
+ {
+ pc->ta.h2pcredit += pPk->credit; /* note, piggy back credit is 1 byte wide */
+ }
+
+ total = 0; /* eat packet header */
+
+ /* Read packet data field with exception_timeout. */
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read Dot4ReverseData: %m\n");
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ }
+ break; /* done reading data packet */
+ } /* while (1) */
+
+bugout:
+ return total;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4OpenChannel(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ DOT4OpenChannel *pCmd;
+ DOT4OpenChannelReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4OpenChannel));
+ pCmd = (DOT4OpenChannel *)buf;
+ n = sizeof(DOT4OpenChannel);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1;
+ pCmd->cmd = DOT4_OPEN_CHANNEL;
+ pCmd->psocket = pc->sockid;
+ pCmd->ssocket = pc->sockid;
+ pCmd->maxp2s = htons(HPMUD_BUFFER_SIZE); /* max primary to secondary packet size in bytes */
+ pCmd->maxs2p = htons(HPMUD_BUFFER_SIZE); /* max secondary to primary packet size in bytes */
+ pCmd->maxcredit = htons(0xffff); /* "unlimited credit" mode, give primary (sender) as much credit as possible */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write Dot4OpenChannel: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4OpenChannelReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_OPEN_CHANNEL)) || (pReply->result != 0))
+ {
+ BUG("invalid Dot4OpenChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.h2psize = ntohs(pReply->maxp2s);
+ pc->ta.p2hsize = ntohs(pReply->maxs2p);
+ pc->ta.h2pcredit = ntohs(pReply->credit);
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4CloseChannel(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ DOT4CloseChannel *pCmd;
+ DOT4CloseChannelReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4CloseChannel));
+ pCmd = (DOT4CloseChannel *)buf;
+ n = sizeof(DOT4CloseChannel);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1;
+ pCmd->cmd = DOT4_CLOSE_CHANNEL;
+ pCmd->psocket = pc->sockid;
+ pCmd->ssocket = pc->sockid;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write Dot4CloseChannel: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4CloseChannelReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_CLOSE_CHANNEL)) || (pReply->result != 0))
+ {
+ BUG("invalid Dot4CloseChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4Credit(mud_channel *pc, int fd, unsigned short credit)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ DOT4Credit *pCmd;
+ DOT4CreditReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4Credit));
+ pCmd = (DOT4Credit *)buf;
+ n = sizeof(DOT4Credit);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1;
+ pCmd->cmd = DOT4_CREDIT;
+ pCmd->psocket = pc->sockid;
+ pCmd->ssocket = pc->sockid;
+ pCmd->credit = htons(credit); /* set peripheral to host credit */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write Dot4Credit: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4CreditReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_CREDIT)) || (pReply->result != 0))
+ {
+ BUG("invalid Dot4CreditReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.p2hcredit += credit;
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) Dot4CreditRequest(mud_channel *pc, int fd, unsigned short credit)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ DOT4CreditRequest *pCmd;
+ DOT4CreditRequestReply *pReply;
+
+ memset(buf, 0, sizeof(DOT4CreditRequest));
+ pCmd = (DOT4CreditRequest *)buf;
+ n = sizeof(DOT4CreditRequest);
+ pCmd->h.length = htons(n);
+ pCmd->h.credit = 1;
+ pCmd->cmd = DOT4_CREDIT_REQUEST;
+ pCmd->psocket = pc->sockid;
+ pCmd->ssocket = pc->sockid;
+ // pCmd->maxcredit = htons(credit); /* request host to peripheral credit */
+ pCmd->maxcredit = htons(0xffff); /* request host to peripheral credit */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write Dot4CreditRequest: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (DOT4CreditRequestReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_CREDIT_REQUEST)) || (pReply->result != 0))
+ {
+ BUG("invalid Dot4CreditRequestReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.h2pcredit += ntohs(pReply->credit);
+
+bugout:
+ return stat;
+}
+
diff --git a/io/hpmud/dot4.h b/io/hpmud/dot4.h
new file mode 100644
index 0000000..2623194
--- /dev/null
+++ b/io/hpmud/dot4.h
@@ -0,0 +1,187 @@
+/*****************************************************************************\
+
+ dot4.h - 1284.4 support for multi-point transport driver
+
+ (c) 2005-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#ifndef _DOT4_H
+#define _DOT4_H
+
+enum DOT4_COMMAND
+{
+ DOT4_INIT = MLC_INIT,
+ DOT4_OPEN_CHANNEL = MLC_OPEN_CHANNEL,
+ DOT4_CLOSE_CHANNEL = MLC_CLOSE_CHANNEL,
+ DOT4_CREDIT = MLC_CREDIT,
+ DOT4_CREDIT_REQUEST = MLC_CREDIT_REQUEST,
+ DOT4_GET_SOCKET = 0x9,
+ DOT4_GET_SERVICE = 0xa,
+ DOT4_EXIT = MLC_EXIT,
+ DOT4_ERROR = MLC_ERROR
+};
+
+/*
+ * Note, following structures must be packed. The "pragma pack" statement is not recognized by all gcc compilers (ie: ARM based),
+ * so we use __attribute__((packed)) instead.
+ */
+
+typedef struct
+{
+ unsigned char psid; /* primary socket id (ie: host) */
+ unsigned char ssid; /* secondary socket id (ie: peripheral) */
+ unsigned short length; /* packet length (includes header) */
+ unsigned char credit; /* data packet credit, reserved if command */
+ unsigned char control; /* bit field: 0=normal */
+} __attribute__((packed)) DOT4Header;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char rev;
+} __attribute__((packed)) DOT4Init;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned char rev;
+} __attribute__((packed)) DOT4InitReply;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+} __attribute__((packed)) DOT4Exit;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char result;
+} __attribute__((packed)) DOT4ExitReply;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char psocket; /* primary socket id */
+ unsigned char ssocket; /* secondary socket id */
+ unsigned short maxp2s; /* max primary to secondary packet size in bytes */
+ unsigned short maxs2p; /* max secondary to primary packet size in bytes */
+ unsigned short maxcredit; /* max outstanding credit */
+} __attribute__((packed)) DOT4OpenChannel;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned char psocket;
+ unsigned char ssocket;
+ unsigned short maxp2s; /* max primary to secondary packet size in bytes */
+ unsigned short maxs2p; /* max secondary to primary packet size in bytes */
+ unsigned short maxcredit; /* max outstanding credit */
+ unsigned short credit;
+} __attribute__((packed)) DOT4OpenChannelReply;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char psocket; /* primary socket id */
+ unsigned char ssocket; /* secondary socket id */
+} __attribute__((packed)) DOT4CloseChannel;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned char psocket; /* primary socket id */
+ unsigned char ssocket; /* secondary socket id */
+} __attribute__((packed)) DOT4CloseChannelReply;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned char socket;
+} __attribute__((packed)) DOT4GetSocketReply;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char psocket;
+ unsigned char ssocket;
+ unsigned short credit; /* credit for sender */
+} __attribute__((packed)) DOT4Credit;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char psocket;
+ unsigned char ssocket;
+ unsigned short maxcredit; /* maximum outstanding credit */
+} __attribute__((packed)) DOT4CreditRequest;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned char psocket;
+ unsigned char ssocket;
+ unsigned short credit; /* credit for sender */
+} __attribute__((packed)) DOT4CreditRequestReply;
+
+typedef struct
+{
+ DOT4Header h;
+ unsigned char cmd;
+ unsigned char psocket; /* primary socket id which contains the error */
+ unsigned char ssocket; /* secondary socket id which contains the error */
+ unsigned char error;
+} __attribute__((packed)) DOT4Error;
+
+typedef DOT4ExitReply DOT4Reply;
+typedef DOT4Exit DOT4Cmd;
+typedef DOT4CloseChannelReply DOT4CreditReply;
+typedef DOT4Exit DOT4GetSocket;
+
+int __attribute__ ((visibility ("hidden"))) Dot4ReverseCmd(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) Dot4Init(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) Dot4Exit(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) Dot4GetSocket(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) Dot4ForwardData(struct _mud_channel *pc, int fd, const void *buf, int size, int usec_timeout);
+int __attribute__ ((visibility ("hidden"))) Dot4ReverseData(struct _mud_channel *pc, int fd, void *buf, int length, int usec_timeout);
+int __attribute__ ((visibility ("hidden"))) Dot4OpenChannel(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) Dot4CloseChannel(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) Dot4Credit(struct _mud_channel *pc, int fd, unsigned short credit);
+int __attribute__ ((visibility ("hidden"))) Dot4CreditRequest(struct _mud_channel *pc, int fd, unsigned short credit);
+
+#endif // _DOT4_H
+
diff --git a/io/hpmud/hp-mkuri.c b/io/hpmud/hp-mkuri.c
new file mode 100644
index 0000000..7c32ff7
--- /dev/null
+++ b/io/hpmud/hp-mkuri.c
@@ -0,0 +1,543 @@
+/*****************************************************************************\
+
+ hp-mkuri.c - make uri with multi-point transport driver (HPMUD)
+
+ (c) 2008-2009 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <dlfcn.h>
+#include "hpmud.h"
+
+#define _STRINGIZE(x) #x
+#define STRINGIZE(x) _STRINGIZE(x)
+//#define BUG(args...) fprintf(stderr, __FILE__ " " STRINGIZE(__LINE__) ": " args)
+#define BUG(args...) syslog(LOG_ERR, __FILE__ " " STRINGIZE(__LINE__) ": " args)
+
+static int verbose;
+static char homedir[255] = "";
+
+static void usage()
+{
+ fprintf(stdout, "HPLIP Make URI %s\n", VERSION);
+ fprintf(stdout, "(c) 2008 Copyright Hewlett-Packard Development Company, LP\n");
+ fprintf(stdout, "usage: hp-mkuri -i ip [-p port]\n");
+ fprintf(stdout, "usage: hp-mkuri -z hostname\n");
+ fprintf(stdout, "usage: hp-mkuri -b busnum -d devnum\n");
+ fprintf(stdout, "usage: hp-mkuri -s serialnum\n");
+ fprintf(stdout, "usage: hp-mkuri -l /dev/parportx\n");
+ fprintf(stdout, "usage: hp-mkuri -m hostname [-p port]\n");
+ fprintf(stdout, "usage: hp-mkuri -o (probe)\n");
+ fprintf(stdout, "usage: hp-mkuri -c [-n (no notifier)] (check support)\n");
+ fprintf(stdout, "\nSupport matrix:\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| return value | printer | fax | plugin_required | plugin_optional |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 0 | yes | | | |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 1 | * | * | * | * |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 2 | yes | | yes | |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 3 | yes | | | yes |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 4 | yes | yes | | |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 5 | yes | yes | yes | |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, "| 6 | yes | yes | | yes |\n");
+ fprintf(stdout, "+--------------+---------+-----+-----------------+-----------------+\n");
+ fprintf(stdout, " * no support or error\n");
+} /* usage */
+
+static int GetPair(char *buf, int buf_len, char *key, char *value, char **tail)
+{
+ int i=0, j;
+
+ key[0] = 0;
+ value[0] = 0;
+
+ if (buf[i] == '#')
+ {
+ for (; buf[i] != '\n' && i < buf_len; i++); /* eat comment line */
+ if (buf[i] == '\n')
+ i++; /* bump past '\n' */
+ }
+
+ j = 0;
+ while ((buf[i] != '=') && (i < buf_len) && (j < HPMUD_LINE_SIZE))
+ key[j++] = buf[i++];
+ for (j--; key[j] == ' ' && j > 0; j--); /* eat white space before = */
+ key[++j] = 0;
+
+ if (buf[i] == '=')
+ for (i++; buf[i] == ' ' && i < buf_len; i++); /* eat white space after = */
+
+ j = 0;
+ while ((buf[i] != '\n') && (i < buf_len) && (j < HPMUD_LINE_SIZE))
+ value[j++] = buf[i++];
+ for (j--; value[j] == ' ' && j > 0; j--); /* eat white space before \n */
+ value[++j] = 0;
+
+ if (buf[i] == '\n')
+ i++; /* bump past '\n' */
+
+ if (tail != NULL)
+ *tail = buf + i; /* tail points to next line */
+
+ return i;
+}
+
+static int ReadConfig()
+{
+ char key[HPMUD_LINE_SIZE];
+ char value[HPMUD_LINE_SIZE];
+ char rcbuf[255];
+ char section[32];
+ char *tail;
+ FILE *inFile = NULL;
+ int stat=1;
+
+ homedir[0] = 0;
+
+ if((inFile = fopen(CONFDIR "/hplip.conf", "r")) == NULL)
+ {
+ BUG("unable to open %s: %m\n", CONFDIR "/hplip.conf");
+ goto bugout;
+ }
+
+ section[0] = 0;
+
+ /* Read the config file */
+ while ((fgets(rcbuf, sizeof(rcbuf), inFile) != NULL))
+ {
+ if (rcbuf[0] == '[')
+ {
+ strncpy(section, rcbuf, sizeof(section)); /* found new section */
+ continue;
+ }
+
+ GetPair(rcbuf, strlen(rcbuf), key, value, &tail);
+
+ if ((strncasecmp(section, "[dirs]", 6) == 0) && (strcasecmp(key, "home") == 0))
+ {
+ strncpy(homedir, value, sizeof(homedir));
+ break; /* done */
+ }
+ }
+
+ stat = 0;
+
+bugout:
+ if (inFile != NULL)
+ fclose(inFile);
+
+ return stat;
+}
+
+static int generalize_model(const char *sz, char *buf, int bufSize)
+{
+ const char *pMd=sz;
+ int i, j, dd=0;
+
+ for (i=0; pMd[i] == ' ' && i < bufSize; i++); /* eat leading white space */
+
+ for (j=0; (pMd[i] != 0) && (pMd[i] != ';') && (j < bufSize); i++)
+ {
+ if (pMd[i]==' ' || pMd[i]=='/')
+ {
+ /* Remove double spaces. */
+ if (!dd)
+ {
+ buf[j++] = '_'; /* convert space to "_" */
+ dd=1;
+ }
+ }
+ else
+ {
+ buf[j++] = tolower(pMd[i]);
+ dd=0;
+ }
+ }
+
+ for (j--; buf[j] == '_' && j > 0; j--); /* eat trailing white space */
+
+ buf[++j] = 0;
+
+ return j; /* length does not include zero termination */
+}
+
+static int set_x_environment(void)
+{
+ DIR *dir=NULL;
+ FILE *file=NULL;
+ struct dirent *entry;
+ char path[32], line[256], cookie[128], *p;
+ int i, c, stat=1;
+
+ if ((dir = opendir("/proc"))==NULL)
+ {
+ BUG("unable to open /proc: %m\n");
+ goto bugout;
+ }
+
+ while ((entry = readdir(dir)) != NULL)
+ {
+ if (!isdigit(*entry->d_name))
+ continue;
+
+ /* Get command line for this PID. */
+ snprintf(path, sizeof(path), "/proc/%s/cmdline", entry->d_name);
+ if ((file = fopen(path, "r")) == NULL)
+ continue;
+ for (i=0; ((c = getc(file)) != EOF) && (i < (sizeof(line)-1)); i++)
+ {
+ if (c == 0)
+ c = ' ';
+ line[i] = c;
+ }
+ line[i]=0;
+ fclose(file);
+ if ((p = strstr(line, "-auth ")))
+ {
+ /* Found X server. */
+ for (p+=6; (*p == ' ') && (*p != 0); p++); /* eat any white space before cookie */
+ for (i=0; (*(p+i) != ' ') && (*(p+i) != 0) && i < (sizeof(cookie)-1); i++)
+ cookie[i] = *(p+i);
+ cookie[i]=0;
+ setenv("XAUTHORITY", cookie, 1);
+ setenv("DISPLAY", ":0.0", 1);
+ break;
+ }
+ } /* while ((entry = readdir(dir)) != NULL) */
+
+ stat = 0;
+
+bugout:
+ if (dir)
+ closedir(dir);
+ return(stat);
+} /* set_x_environment */
+
+static int notify(const char *summary, const char *message, int ms_timeout)
+{
+ void *handle=NULL, *n;
+ int stat=1;
+
+ typedef void (*notify_init_t)(char *);
+ typedef void *(*notify_notification_new_t)(const char *, const char *, const char *, void *);
+ typedef void (*notify_notification_set_timeout_t)(void *, int);
+ typedef void (*notify_notification_show_t)(void *, char *);
+
+ notify_init_t n_init;
+ notify_notification_new_t n_new;
+ notify_notification_set_timeout_t n_timeout;
+ notify_notification_show_t n_show;
+
+ set_x_environment();
+
+ /* Bypass glib build dependencies by loading libnotify manually. */
+
+ if ((handle = dlopen("libnotify.so.1", RTLD_LAZY)) == NULL)
+ {
+ BUG("failed to open libnotify: %m\n");
+ goto bugout;
+ }
+
+ if ((n_init = (notify_init_t)dlsym(handle, "notify_init")) == NULL)
+ {
+ BUG("failed to find notify_init: %m\n");
+ goto bugout;
+ }
+ n_init("Basics");
+
+ if ((n_new = (notify_notification_new_t)dlsym(handle, "notify_notification_new")) == NULL)
+ {
+ BUG("failed to find notify_notification_new: %m\n");
+ goto bugout;
+ }
+ n = n_new(summary, message, NULL, NULL);
+
+ if ((n_timeout = (notify_notification_set_timeout_t)dlsym(handle, "notify_notification_set_timeout")) == NULL)
+ {
+ BUG("failed to find notify_notification_set_timeout: %m\n");
+ goto bugout;
+ }
+ n_timeout(n, ms_timeout);
+
+ if ((n_show = (notify_notification_show_t)dlsym(handle, "notify_notification_show")) == NULL)
+ {
+ BUG("failed to find notify_notification_show: %m\n");
+ goto bugout;
+ }
+ n_show(n, NULL);
+
+ stat=0;
+
+bugout:
+ if (handle)
+ dlclose(handle);
+
+ return stat;
+} /* notify */
+
+static int check_support(int send_notify)
+{
+ struct stat sb;
+ char model[256];
+ int ret=1, plugin_installed=1;
+ const char *pm;
+ char m[256];
+ char datfile[256];
+ char value[32];
+ int support, plugin, fax;
+
+ /* Get hp model from environment variables. */
+ if ((pm = getenv("hp_model")))
+ {
+ strncpy(model, pm, sizeof(model));
+ }
+ else
+ {
+ fprintf(stderr, "error no hp_model environment variable set\n");
+ BUG("error no hp_model environment variable set\n");
+ goto bugout;
+ }
+
+ if (model[0]==0)
+ {
+ BUG("invalid parameter(s)\n");
+ usage();
+ goto bugout;
+ }
+
+ generalize_model(model, m, sizeof(m));
+ snprintf(model, sizeof(model), "[%s]", m);
+
+ if (ReadConfig())
+ goto bugout;
+
+ snprintf(datfile, sizeof(datfile), "%s/data/models/models.dat", homedir);
+
+ if (hpmud_get_key_value(datfile, model, "support-type", value, sizeof(value)) != HPMUD_R_OK)
+ goto bugout;
+ support = strtol(value, NULL, 10);
+ if (hpmud_get_key_value(datfile, model, "plugin", value, sizeof(value)) != HPMUD_R_OK)
+ goto bugout;
+ plugin = strtol(value, NULL, 10);
+ if (hpmud_get_key_value(datfile, model, "fax-type", value, sizeof(value)) != HPMUD_R_OK)
+ goto bugout;
+ fax = strtol(value, NULL, 10);
+
+ /* See if device is supported by hplip. */
+ if (support == HPMUD_SUPPORT_TYPE_NONE)
+ {
+ BUG("%s is not supported by HPLIP %s\n", pm, VERSION);
+ goto bugout;
+ }
+
+ if (stat("/etc/udev/rules.d/86-hpmud-hp_laserjet_1018.rules", &sb) == -1)
+ plugin_installed=0;
+
+ if (send_notify && !plugin_installed)
+ {
+ /* See if device requires a Plugin. */
+ switch (plugin)
+ {
+ case HPMUD_PLUGIN_TYPE_REQUIRED:
+ BUG("%s requires a proprietary plugin\n", pm);
+ notify(pm, "requires a proprietary plugin, run hp-setup", 30000);
+ break;
+ case HPMUD_PLUGIN_TYPE_OPTIONAL:
+ BUG("%s has a optional proprietary plugin\n", pm);
+ notify(pm, "has a optional proprietary plugin, run hp-setup", 30000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ret = 0;
+ if (plugin == HPMUD_PLUGIN_TYPE_REQUIRED)
+ ret = 2;
+ else if (plugin == HPMUD_PLUGIN_TYPE_OPTIONAL)
+ ret = 3;
+ if (fax > 0)
+ {
+ ret = 4;
+ if (plugin == HPMUD_PLUGIN_TYPE_REQUIRED)
+ ret = 5;
+ else if (plugin == HPMUD_PLUGIN_TYPE_OPTIONAL)
+ ret = 6;
+ }
+
+bugout:
+ return ret;
+} /* check_support */
+
+int main(int argc, char *argv[])
+{
+ char ip[HPMUD_LINE_SIZE]; /* internet address */
+ char bn[HPMUD_LINE_SIZE]; /* usb bus number */
+ char dn[HPMUD_LINE_SIZE]; /* usb device number */
+ char sn[HPMUD_LINE_SIZE]; /* usb serial number */
+ char pp[HPMUD_LINE_SIZE]; /* parallel port device */
+ char uri[HPMUD_LINE_SIZE];
+ char host[HPMUD_LINE_SIZE];
+ int i, port=1, ret=1, probe=0, support=0, send_notify=1;
+ enum HPMUD_RESULT stat;
+ char buf[HPMUD_LINE_SIZE*64];
+ int cnt, bytes_read;
+
+ ip[0] = bn[0] = dn[0] = pp[0] = uri[0] = sn[0] = host[0] = 0;
+ while ((i = getopt(argc, argv, "vhocni:p:b:d:l:s:z:")) != -1)
+ {
+ switch (i)
+ {
+ case 'i':
+ strncpy(ip, optarg, sizeof(ip));
+ break;
+ case 'z':
+ strncpy(host, optarg, sizeof(host));
+ break;
+ case 'p':
+ port = strtol(optarg, NULL, 10);
+ break;
+ case 'b':
+ strncpy(bn, optarg, sizeof(bn));
+ break;
+ case 'd':
+ strncpy(dn, optarg, sizeof(dn));
+ break;
+ case 'l':
+ strncpy(pp, optarg, sizeof(pp));
+ break;
+ case 's':
+ strncpy(sn, optarg, sizeof(sn));
+ break;
+ case 'o':
+ probe++;
+ break;
+ case 'c':
+ support++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'n':
+ send_notify=0;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ case '?':
+ usage();
+ fprintf(stderr, "unknown argument: %s\n", argv[1]);
+ exit(-1);
+ default:
+ break;
+ }
+ }
+
+ if (ip[0]==0 && (!(bn[0] && dn[0])) && pp[0]==0 && probe==0 && sn[0]==0 && support==0 && host[0]==0)
+ {
+ fprintf(stderr, "invalid command parameter(s)\n");
+ usage();
+ goto bugout;
+ }
+
+ if (probe)
+ {
+ hpmud_probe_devices(HPMUD_BUS_ALL, buf, sizeof(buf), &cnt, &bytes_read);
+ if (bytes_read)
+ fprintf(stdout, "%s", buf);
+ }
+
+#ifdef HAVE_LIBNETSNMP
+ if (ip[0])
+ {
+ stat = hpmud_make_net_uri(ip, port, uri, sizeof(uri), &bytes_read);
+ if (stat == HPMUD_R_OK)
+ {
+ fprintf(stdout, "%s\n", uri);
+ fprintf(stdout, "hpaio%s\n", &uri[2]);
+ }
+ }
+ if (host[0])
+ {
+ stat = hpmud_make_mdns_uri(host, port, uri, sizeof(uri), &bytes_read);
+ if (stat == HPMUD_R_OK)
+ {
+ fprintf(stdout, "%s\n", uri);
+ fprintf(stdout, "hpaio%s\n", &uri[2]);
+ }
+ }
+#endif
+
+ if (bn[0] && dn[0])
+ {
+ stat = hpmud_make_usb_uri(bn, dn, uri, sizeof(uri), &bytes_read);
+ if (stat == HPMUD_R_OK)
+ {
+ fprintf(stdout, "%s\n", uri);
+ fprintf(stdout, "hpaio%s\n", &uri[2]);
+ }
+ }
+
+ if (sn[0])
+ {
+ stat = hpmud_make_usb_serial_uri(sn, uri, sizeof(uri), &bytes_read);
+ if (stat == HPMUD_R_OK)
+ {
+ fprintf(stdout, "%s\n", uri);
+ fprintf(stdout, "hpaio%s\n", &uri[2]);
+ }
+ }
+
+#ifdef HAVE_PPORT
+ if (pp[0])
+ {
+ stat = hpmud_make_par_uri(pp, uri, sizeof(uri), &bytes_read);
+ if (stat == HPMUD_R_OK)
+ {
+ fprintf(stdout, "%s\n", uri);
+ fprintf(stdout, "hpaio%s\n", &uri[2]);
+ }
+ }
+#endif
+
+ ret = 0;
+
+ if (support)
+ ret = check_support(send_notify);
+
+bugout:
+ exit(ret);
+} /* main */
diff --git a/io/hpmud/hpmud.c b/io/hpmud/hpmud.c
new file mode 100644
index 0000000..d24ebd2
--- /dev/null
+++ b/io/hpmud/hpmud.c
@@ -0,0 +1,699 @@
+/*****************************************************************************\
+
+ hpmud.cpp - multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Author: Naga Samrat Chowdary Narla,
+ Contributor: Sarbeswar Meher
+\*****************************************************************************/
+
+#include "hpmud.h"
+#include "hpmudi.h"
+
+/* Client data. */
+mud_session ms __attribute__ ((visibility ("hidden"))); /* mud session, one per client */
+mud_session *msp __attribute__ ((visibility ("hidden"))) = &ms;
+
+/*
+ * sysdump() originally came from http://sws.dett.de/mini/hexdump-c , steffen@dett.de .
+ */
+void __attribute__ ((visibility ("hidden"))) sysdump(const void *data, int size)
+{
+ /* Dump size bytes of *data. Output looks like:
+ * [0000] 75 6E 6B 6E 6F 77 6E 20 30 FF 00 00 00 00 39 00 unknown 0.....9.
+ */
+
+ unsigned char *p = (unsigned char *)data;
+ unsigned char c;
+ int n;
+ char bytestr[4] = {0};
+ char addrstr[10] = {0};
+ char hexstr[16*3 + 5] = {0};
+ char charstr[16*1 + 5] = {0};
+ for(n=1;n<=size;n++) {
+ if (n%16 == 1) {
+ /* store address for this line */
+ snprintf(addrstr, sizeof(addrstr), "%.4d", (int)((p-(unsigned char *)data) & 0xffff));
+ }
+
+ c = *p;
+ if (isprint(c) == 0) {
+ c = '.';
+ }
+
+ /* store hex str (for left side) */
+ snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
+ strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
+
+ /* store char str (for right side) */
+ snprintf(bytestr, sizeof(bytestr), "%c", c);
+ strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
+
+ if(n%16 == 0) {
+ /* line completed */
+ DBG_SZ("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ }
+ p++; /* next byte */
+ }
+
+ if (strlen(hexstr) > 0) {
+ /* print rest of buffer if not empty */
+ DBG_SZ("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ }
+}
+
+/* Given the IEEE 1284 device id string, determine if this is a HP product. */
+int __attribute__ ((visibility ("hidden"))) is_hp(const char *id)
+{
+ char *pMf;
+
+ if ((pMf = strstr(id, "MFG:")) != NULL)
+ pMf+=4;
+ else if ((pMf = strstr(id, "MANUFACTURER:")) != NULL)
+ pMf+=13;
+ else
+ return 0;
+
+ if ((strncasecmp(pMf, "HEWLETT-PACKARD", 15) == 0) ||
+ (strncasecmp(pMf, "APOLLO", 6) == 0) || (strncasecmp(pMf, "HP", 2) == 0))
+ {
+ return 1; /* found HP product */
+ }
+ return 0;
+}
+
+int __attribute__ ((visibility ("hidden"))) generalize_model(const char *sz, char *buf, int bufSize)
+{
+ const char *pMd=sz;
+ int i, j, dd=0;
+
+ for (i=0; pMd[i] == ' ' && i < bufSize; i++); /* eat leading white space */
+
+ for (j=0; (pMd[i] != 0) && (pMd[i] != ';') && (j < bufSize); i++)
+ {
+ if (pMd[i]==' ' || pMd[i]=='/')
+ {
+ /* Remove double spaces. */
+ if (!dd)
+ {
+ buf[j++] = '_'; /* convert space to "_" */
+ dd=1;
+ }
+ }
+ else
+ {
+ buf[j++] = pMd[i];
+ dd=0;
+ }
+ }
+
+ for (j--; buf[j] == '_' && j > 0; j--); /* eat trailing white space */
+
+ buf[++j] = 0;
+
+ return j; /* length does not include zero termination */
+}
+
+int __attribute__ ((visibility ("hidden"))) generalize_serial(const char *sz, char *buf, int bufSize)
+{
+ const char *pMd=sz;
+ int i, j;
+
+ for (i=0; pMd[i] == ' ' && i < bufSize; i++); /* eat leading white space */
+
+ for (j=0; (pMd[i] != 0) && (i < bufSize); i++)
+ {
+ buf[j++] = pMd[i];
+ }
+
+ for (i--; buf[i] == ' ' && i > 0; i--); /* eat trailing white space */
+
+ buf[++i] = 0;
+
+ return i; /* length does not include zero termination */
+}
+
+/* Parse serial number from uri string. */
+int __attribute__ ((visibility ("hidden"))) get_uri_serial(const char *uri, char *buf, int bufSize)
+{
+ char *p;
+ int i;
+
+ buf[0] = 0;
+
+ if ((p = strcasestr(uri, "serial=")) != NULL)
+ p+=7;
+ else
+ return 0;
+
+ for (i=0; (p[i] != 0) && (p[i] != '+') && (i < bufSize); i++)
+ buf[i] = p[i];
+
+ buf[i] = 0;
+
+ return i;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) service_to_channel(mud_device *pd, const char *sn, HPMUD_CHANNEL *index)
+{
+ enum HPMUD_RESULT stat;
+
+ *index=-1;
+
+ /* Check for valid service requests. */
+ if (strncasecmp(sn, "print", 5) == 0)
+ {
+ *index = HPMUD_PRINT_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-ews-ledm", 11) == 0)
+ {
+ *index = HPMUD_EWS_LEDM_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-ews", 6) == 0)
+ {
+ *index = HPMUD_EWS_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-soap-scan", 12) == 0)
+ {
+ *index = HPMUD_SOAPSCAN_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-soap-fax", 11) == 0)
+ {
+ *index = HPMUD_SOAPFAX_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-marvell-scan", 15) == 0)
+ {
+ *index = HPMUD_MARVELL_SCAN_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-marvell-fax", 14) == 0)
+ {
+ *index = HPMUD_MARVELL_FAX_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-ledm-scan", 12) == 0)
+ {
+ *index = HPMUD_LEDM_SCAN_CHANNEL;
+ }
+ /* All the following services require MLC/1284.4. */
+ else if (pd->io_mode == HPMUD_RAW_MODE || pd->io_mode == HPMUD_UNI_MODE)
+ {
+ BUG("invalid channel_open state, current io_mode=raw/uni service=%s %s\n", sn, pd->uri);
+ stat = HPMUD_R_INVALID_STATE;
+ goto bugout;
+ }
+ else if (strncasecmp(sn, "hp-message", 10) == 0)
+ {
+ *index = HPMUD_PML_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-scan", 7) == 0)
+ {
+ *index = HPMUD_SCAN_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-fax-send", 11) == 0)
+ {
+ *index = HPMUD_FAX_SEND_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-card-access", 14) == 0)
+ {
+ *index = HPMUD_MEMORY_CARD_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-configuration-upload", 23) == 0)
+ {
+ *index = HPMUD_CONFIG_UPLOAD_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-configuration-download", 25) == 0)
+ {
+ *index = HPMUD_CONFIG_DOWNLOAD_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-devmgmt", 10) == 0)
+ {
+ *index = HPMUD_DEVMGMT_CHANNEL;
+ }
+ else if (strncasecmp(sn, "hp-wificonfig", 13) == 0)
+ {
+ *index = HPMUD_WIFI_CHANNEL;
+ }
+ else
+ {
+ BUG("invalid service=%s %s\n", sn, pd->uri);
+ stat = HPMUD_R_INVALID_SN;
+ goto bugout;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+static int new_device(const char *uri, enum HPMUD_IO_MODE mode, int *result)
+{
+ int index=0; /* device[0] is unused */
+ int i=1;
+
+ if (uri[0] == 0)
+ return 0;
+
+ pthread_mutex_lock(&msp->mutex);
+
+ if (msp->device[i].index)
+ {
+ BUG("invalid device_open state\n"); /* device is already open for this client, one device per session */
+ *result = HPMUD_R_INVALID_STATE;
+ goto bugout;
+ }
+
+ index = i; /* currently only support one device per client or process */
+
+ /* Based on uri, set local session attributes. */
+ if (strcasestr(uri, ":/usb") != NULL)
+ {
+ msp->device[i].vf = musb_mud_device_vf;
+ }
+#ifdef HAVE_LIBNETSNMP
+ else if (strcasestr(uri, ":/net") != NULL)
+ {
+ msp->device[i].vf = jd_mud_device_vf;
+ }
+#endif
+#ifdef HAVE_PPORT
+ else if (strcasestr(uri, ":/par") != NULL)
+ {
+ msp->device[i].vf = pp_mud_device_vf;
+ }
+#endif
+ else
+ {
+ BUG("invalid uri %s\n", uri);
+ *result = HPMUD_R_INVALID_URI;
+ index = 0;
+ goto bugout;
+ }
+ msp->device[i].io_mode = mode;
+ msp->device[i].index = index;
+ msp->device[i].channel_cnt = 0;
+ msp->device[i].open_fd = -1;
+ strcpy(msp->device[i].uri, uri);
+
+bugout:
+ pthread_mutex_unlock(&msp->mutex);
+
+ return index; /* return device index */
+}
+
+static int del_device(HPMUD_DEVICE index)
+{
+ pthread_mutex_lock(&msp->mutex);
+
+ msp->device[index].index = 0;
+
+ pthread_mutex_unlock(&msp->mutex);
+
+ return 0;
+}
+
+/* Make sure client closed down the device. */
+int device_cleanup(mud_session *ps)
+{
+ int i, dd=1;
+
+ if(!ps->device[dd].index)
+ return 0; /* nothing to do */
+
+ BUG("device_cleanup: device uri=%s\n", ps->device[dd].uri);
+
+ for (i=0; i<HPMUD_CHANNEL_MAX; i++)
+ {
+ if (ps->device[dd].channel[i].client_cnt)
+ {
+ BUG("device_cleanup: close channel %d...\n", i);
+ hpmud_close_channel(dd, ps->device[dd].channel[i].index);
+ BUG("device_cleanup: done closing channel %d\n", i);
+ }
+ }
+
+ BUG("device_cleanup: close device dd=%d...\n", dd);
+ hpmud_close_device(dd);
+ BUG("device_cleanup: done closing device dd=%d\n", dd);
+
+ return 0;
+}
+
+static void __attribute__ ((constructor)) mud_init(void)
+{
+ DBG("[%d] hpmud_init()\n", getpid());
+}
+
+static void __attribute__ ((destructor)) mud_exit(void)
+{
+ DBG("[%d] hpmud_exit()\n", getpid());
+ device_cleanup(msp);
+}
+
+/*******************************************************************************************************************************
+ * Helper functions.
+ */
+
+/* Parse the model from the IEEE 1284 device id string and generalize the model name */
+int hpmud_get_model(const char *id, char *buf, int buf_size)
+{
+ char *pMd;
+
+ buf[0] = 0;
+
+ if ((pMd = strstr(id, "MDL:")) != NULL)
+ pMd+=4;
+ else if ((pMd = strstr(id, "MODEL:")) != NULL)
+ pMd+=6;
+ else
+ return 0;
+
+ return generalize_model(pMd, buf, buf_size);
+}
+
+/* Parse the model from the IEEE 1284 device id string. */
+int hpmud_get_raw_model(char *id, char *raw, int rawSize)
+{
+ char *pMd;
+ int i;
+
+ raw[0] = 0;
+
+ if ((pMd = strstr(id, "MDL:")) != NULL)
+ pMd+=4;
+ else if ((pMd = strstr(id, "MODEL:")) != NULL)
+ pMd+=6;
+ else
+ return 0;
+
+ for (i=0; (pMd[i] != ';') && (i < rawSize); i++)
+ raw[i] = pMd[i];
+ raw[i] = 0;
+
+ return i;
+}
+
+/* Parse device model from uri string. */
+int hpmud_get_uri_model(const char *uri, char *buf, int buf_size)
+{
+ char *p;
+ int i;
+
+ buf[0] = 0;
+
+ if ((p = strstr(uri, "/")) == NULL)
+ return 0;
+ if ((p = strstr(p+1, "/")) == NULL)
+ return 0;
+ p++;
+
+ for (i=0; (p[i] != '?') && (i < buf_size); i++)
+ buf[i] = p[i];
+
+ buf[i] = 0;
+
+ return i;
+}
+
+/* Parse the data link from a uri string. */
+int hpmud_get_uri_datalink(const char *uri, char *buf, int buf_size)
+{
+ char *p;
+ int i;
+ int zc=0;
+#ifdef HAVE_LIBNETSNMP
+ char ip[HPMUD_LINE_SIZE];
+#endif
+
+ buf[0] = 0;
+
+ if ((p = strcasestr(uri, "device=")) != NULL)
+ p+=7;
+ else if ((p = strcasestr(uri, "ip=")) != NULL)
+ p+=3;
+ else if ((p = strcasestr(uri, "zc=")) != NULL)
+ {
+ p+=3;
+ zc=1;
+ }
+ else
+ return 0;
+
+ if (zc)
+ {
+#ifdef HAVE_LIBNETSNMP
+ if (hpmud_mdns_lookup(p, HPMUD_MDNS_TIMEOUT, ip) != HPMUD_R_OK)
+ return 0;
+ for (i=0; (ip[i] != 0) && (i < buf_size); i++)
+ buf[i] = ip[i];
+#else
+ return 0;
+#endif
+ }
+ else {
+ for (i=0; (p[i] != 0) && (p[i] != '&') && (i < buf_size); i++)
+ buf[i] = p[i];
+ }
+
+ buf[i] = 0;
+
+ return i;
+}
+
+/***************************************************************************************************
+ * Core functions.
+ */
+
+enum HPMUD_RESULT hpmud_open_device(const char *uri, enum HPMUD_IO_MODE iomode, HPMUD_DEVICE *dd)
+{
+ HPMUD_DEVICE index=0;
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_URI;
+ int result;
+
+ DBG("[%d,%d,%d,%d,%d,%d] hpmud_device_open() uri=%s iomode=%d\n", getpid(), getppid(), getuid(), geteuid(), getgid(), getegid(), uri, iomode);
+
+ if ((index = new_device(uri, iomode, &result)) == 0)
+ {
+ stat = result;
+ goto bugout;
+ }
+ else
+ {
+ if ((stat = (msp->device[index].vf.open)(&msp->device[index])) != HPMUD_R_OK)
+ {
+ (msp->device[index].vf.close)(&msp->device[index]); /* Open failed perform device cleanup. */
+ del_device(index);
+ goto bugout;
+ }
+ }
+
+ *dd = index;
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_close_device(HPMUD_DEVICE dd)
+{
+ enum HPMUD_RESULT stat;
+
+ DBG("[%d] hpmud_device_close() dd=%d\n", getpid(), dd);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd)
+ {
+ BUG("invalid device_close state\n");
+ stat = HPMUD_R_INVALID_STATE;
+ }
+ else
+ {
+ stat = (msp->device[dd].vf.close)(&msp->device[dd]);
+ del_device(dd);
+ }
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_get_device_id(HPMUD_DEVICE dd, char *buf, int size, int *bytes_read)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+
+ DBG("[%d] hpmud_get_device_id() dd=%d\n", getpid(), dd);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd)
+ {
+ BUG("invalid get_device_id state\n");
+ goto bugout;
+ }
+
+ stat = (msp->device[dd].vf.get_device_id)(&msp->device[dd], buf, size, bytes_read);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_get_device_status(HPMUD_DEVICE dd, unsigned int *status)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+
+ DBG("[%d] hpmud_get_device_status() dd=%d\n", getpid(), dd);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd)
+ {
+ BUG("invalid get_device_status state\n");
+ goto bugout;
+ }
+
+ stat = (msp->device[dd].vf.get_device_status)(&msp->device[dd], status);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_probe_devices(enum HPMUD_BUS_ID bus, char *buf, int buf_size, int *cnt, int *bytes_read)
+{
+ int len=0;
+
+ DBG("[%d] hpmud_probe_devices() bus=%d\n", getpid(), bus);
+
+ buf[0] = 0;
+ *cnt = 0;
+
+ if (bus == HPMUD_BUS_USB)
+ {
+ len = musb_probe_devices(buf, buf_size, cnt);
+ }
+#ifdef HAVE_PPORT
+ else if (bus == HPMUD_BUS_PARALLEL)
+ {
+ len = pp_probe_devices(buf, buf_size, cnt);
+ }
+#endif
+ else if (bus == HPMUD_BUS_ALL)
+ {
+ len = musb_probe_devices(buf, buf_size, cnt);
+#ifdef HAVE_PPORT
+ len += pp_probe_devices(buf+len, buf_size-len, cnt);
+#endif
+ }
+
+ *bytes_read = len;
+
+ return HPMUD_R_OK;
+}
+
+enum HPMUD_RESULT hpmud_open_channel(HPMUD_DEVICE dd, const char *channel_name, HPMUD_CHANNEL *cd)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+
+ DBG("[%d] hpmud_channel_open() dd=%d name=%s\n", getpid(), dd, channel_name);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd)
+ {
+ BUG("invalid channel_open state\n");
+ goto bugout;
+ }
+
+ stat = (msp->device[dd].vf.channel_open)(&msp->device[dd], channel_name, cd);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_close_channel(HPMUD_DEVICE dd, HPMUD_CHANNEL cd)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+
+ DBG("[%d] hpmud_channel_close() dd=%d cd=%d\n", getpid(), dd, cd);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd ||
+ cd <=0 || cd > HPMUD_CHANNEL_MAX || msp->device[dd].channel[cd].client_cnt == 0)
+ {
+ BUG("invalid channel_close state\n");
+ goto bugout;
+ }
+
+ stat = (msp->device[dd].vf.channel_close)(&msp->device[dd], &msp->device[dd].channel[cd]);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_write_channel(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, const void *buf, int size, int sec_timeout, int *bytes_wrote)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+
+ DBG("[%d] hpmud_channel_write() dd=%d cd=%d buf=%p size=%d sectime=%d\n", getpid(), dd, cd, buf, size, sec_timeout);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd ||
+ cd <=0 || cd > HPMUD_CHANNEL_MAX || msp->device[dd].channel[cd].client_cnt == 0)
+ {
+ BUG("invalid channel_write state\n");
+ goto bugout;
+ }
+
+ stat = (msp->device[dd].vf.channel_write)(&msp->device[dd], &msp->device[dd].channel[cd], buf, size, sec_timeout, bytes_wrote);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_read_channel(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, void *buf, int size, int sec_timeout, int *bytes_read)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+ DBG("[%d] hpmud_channel_read() dd=%d cd=%d buf=%p size=%d sectime=%d\n", getpid(), dd, cd, buf, size, sec_timeout);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX || msp->device[dd].index != dd ||
+ cd <=0 || cd > HPMUD_CHANNEL_MAX || msp->device[dd].channel[cd].client_cnt == 0)
+ {
+ BUG("invalid channel_read state\n");
+ goto bugout;
+ }
+
+ stat = (msp->device[dd].vf.channel_read)(&msp->device[dd], &msp->device[dd].channel[cd], buf, size, sec_timeout, bytes_read);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_get_dstat(HPMUD_DEVICE dd, struct hpmud_dstat *ds)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_STATE;
+
+ DBG("[%d] hpmud_dstat() dd=%d ds=%p\n", getpid(), dd, ds);
+
+ if (dd <= 0 || dd > HPMUD_DEVICE_MAX)
+ {
+ BUG("invalid dstat state\n");
+ goto bugout;
+ }
+
+ strncpy(ds->uri, msp->device[dd].uri, sizeof(ds->uri));
+ ds->io_mode = msp->device[dd].io_mode;
+ ds->channel_cnt = msp->device[dd].channel_cnt;
+ ds->mlc_up = msp->device[dd].mlc_up;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
diff --git a/io/hpmud/hpmud.h b/io/hpmud/hpmud.h
new file mode 100644
index 0000000..3970d28
--- /dev/null
+++ b/io/hpmud/hpmud.h
@@ -0,0 +1,581 @@
+/*****************************************************************************\
+
+ hpmud.h - public definitions for multi-point transport driver
+
+ (c) 2004-2015 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Author: Naga Samrat Chowdary Narla, Yashwant Sahu, Sarbeswar Meher
+\*****************************************************************************/
+
+#ifndef _HPMUD_H
+#define _HPMUD_H
+
+enum HPMUD_RESULT
+{
+ HPMUD_R_OK = 0,
+ HPMUD_R_INVALID_DEVICE = 2,
+ HPMUD_R_INVALID_DESCRIPTOR = 3,
+ HPMUD_R_INVALID_URI = 4,
+ HPMUD_R_INVALID_LENGTH = 8,
+ HPMUD_R_IO_ERROR = 12,
+ HPMUD_R_DEVICE_BUSY = 21,
+ HPMUD_R_INVALID_SN = 28,
+ HPMUD_R_INVALID_CHANNEL_ID = 30,
+ HPMUD_R_INVALID_STATE = 31,
+ HPMUD_R_INVALID_DEVICE_OPEN = 37,
+ HPMUD_R_INVALID_DEVICE_NODE = 38,
+ HPMUD_R_INVALID_IP = 45,
+ HPMUD_R_INVALID_IP_PORT = 46,
+ HPMUD_R_INVALID_TIMEOUT = 47,
+ HPMUD_R_DATFILE_ERROR = 48,
+ HPMUD_R_IO_TIMEOUT = 49,
+ HPMUD_R_INVALID_MDNS = 50,
+};
+
+enum HPMUD_IO_MODE
+{
+ HPMUD_UNI_MODE=0, /* uni-di */
+ HPMUD_RAW_MODE=1, /* bi-di */
+ HPMUD_DOT4_MODE=3,
+ HPMUD_DOT4_PHOENIX_MODE=4, /* (ie: clj2550, clj2840, lj3050, lj3055, clj4730mfp) */
+ HPMUD_DOT4_BRIDGE_MODE=5, /* (ie: clj2500) not USB compatable, use HPMUD_RAW_MODE, tested on F10 12/10/08 DES */
+ HPMUD_MLC_GUSHER_MODE=6, /* most new devices */
+ HPMUD_MLC_MISER_MODE=7, /* old stuff */
+};
+
+enum HPMUD_BUS_ID
+{
+ HPMUD_BUS_NA=0,
+ HPMUD_BUS_USB=1,
+ HPMUD_BUS_PARALLEL,
+ HPMUD_BUS_ALL
+};
+
+enum HPMUD_SCANTYPE
+{
+ HPMUD_SCANTYPE_NA = 0,
+ HPMUD_SCANTYPE_SCL = 1,
+ HPMUD_SCANTYPE_PML = 2,
+ HPMUD_SCANTYPE_SOAP = 3, /* Wookie (ie:ljcm1017) */
+ HPMUD_SCANTYPE_MARVELL = 4, /* (ie: ljm1005) */
+ HPMUD_SCANTYPE_SOAPHT = 5, /* HorseThief (ie: ljm1522) */
+ HPMUD_SCANTYPE_SCL_DUPLEX = 6,
+ HPMUD_SCANTYPE_LEDM = 7,
+ HPMUD_SCANTYPE_MARVELL2 = 8, /* (Tsunami lj 1212 and series) */
+};
+
+enum HPMUD_SCANSRC
+{
+ HPMUD_SCANSRC_NA = 0,
+ HPMUD_SCANSRC_FLATBED = 0x1,
+ HPMUD_SCANSRC_ADF= 0x2,
+ HPMUD_SCANSRC_CAMERA = 0x4,
+};
+
+enum HPMUD_STATUSTYPE
+{
+ HPMUD_STATUSTYPE_NA = 0,
+ HPMUD_STATUSTYPE_VSTATUS = 1, /* device-id vstatus */
+ HPMUD_STATUSTYPE_SFIELD = 2, /* device-id s-field */
+ HPMUD_STATUSTYPE_PML = 3, /* laserjet pml */
+ HPMUD_STATUSTYPE_EWS = 6, /* laserjet hp ews */
+ HPMUD_STATUSTYPE_PJL = 8, /* laserjet pjl */
+ HPMUD_STATUSTYPE_PJLPML = 9, /* laserjet pjl and pml */
+};
+
+enum HPMUD_SUPPORT_TYPE
+{
+ HPMUD_SUPPORT_TYPE_NONE = 0, /* not supported */
+ HPMUD_SUPPORT_TYPE_HPIJS = 1, /* supported by hpijs only */
+ HPMUD_SUPPORT_TYPE_HPLIP = 2, /* supported by hpijs and "hp" backend */
+};
+
+enum HPMUD_PLUGIN_TYPE
+{
+ HPMUD_PLUGIN_TYPE_NONE = 0,
+ HPMUD_PLUGIN_TYPE_REQUIRED = 1,
+ HPMUD_PLUGIN_TYPE_OPTIONAL = 2,
+};
+
+#define HPMUD_S_PRINT_CHANNEL "PRINT"
+#define HPMUD_S_PML_CHANNEL "HP-MESSAGE"
+#define HPMUD_S_SCAN_CHANNEL "HP-SCAN"
+#define HPMUD_S_FAX_SEND_CHANNEL "HP-FAX-SEND"
+#define HPMUD_S_CONFIG_UPLOAD_CHANNEL "HP-CONFIGURATION-UPLOAD"
+#define HPMUD_S_CONFIG_DOWNLOAD_CHANNEL "HP-CONFIGURATION-DOWNLOAD"
+#define HPMUD_S_MEMORY_CARD_CHANNEL "HP-CARD-ACCESS"
+#define HPMUD_S_EWS_CHANNEL "HP-EWS"
+#define HPMUD_S_EWS_LEDM_CHANNEL "HP-EWS-LEDM"
+#define HPMUD_S_SOAP_SCAN "HP-SOAP-SCAN"
+#define HPMUD_S_SOAP_FAX "HP-SOAP-FAX"
+#define HPMUD_S_DEVMGMT_CHANNEL "HP-DEVMGMT"
+#define HPMUD_S_MARVELL_SCAN_CHANNEL "HP-MARVELL-SCAN"
+#define HPMUD_S_MARVELL_FAX_CHANNEL "HP-MARVELL-FAX"
+#define HPMUD_S_LEDM_SCAN "HP-LEDM-SCAN"
+#define HPMUD_S_WIFI_CHANNEL "HP-WIFICONFIG"
+
+typedef int HPMUD_DEVICE; /* usb, parallel or jetdirect */
+#define HPMUD_DEVICE_MAX 2 /* zero is not used */
+
+typedef int HPMUD_CHANNEL;
+#define HPMUD_CHANNEL_MAX HPMUD_MAX_CHANNEL_ID
+
+#define HPMUD_LINE_SIZE 256 /* Length of a line. */
+#define HPMUD_BUFFER_SIZE 16384 /* General Read/Write buffer. */
+
+struct hpmud_dstat
+{
+ char uri[HPMUD_LINE_SIZE];
+ int client_cnt; /* number of clients that have this device opend */
+ enum HPMUD_IO_MODE io_mode;
+ int channel_cnt; /* number of open channels */
+ int mlc_up; /* 0 = MLC/1284.4 transport up, 1 = MLD/1284.4 transport down */
+};
+
+struct hpmud_model_attributes
+{
+ enum HPMUD_IO_MODE prt_mode; /* print only (io_mode) */
+ enum HPMUD_IO_MODE mfp_mode; /* pml | scan | fax (io_mode) */
+ enum HPMUD_SCANTYPE scantype; /* scan protocol i.e. SCL, PML, SOAP, MARVELL, LEDM */
+ enum HPMUD_STATUSTYPE statustype;
+ enum HPMUD_SUPPORT_TYPE support;
+ enum HPMUD_PLUGIN_TYPE plugin;
+ enum HPMUD_SUPPORT_TYPE reserved[5];
+ enum HPMUD_SCANSRC scansrc; /*Flatbed, ADF, Camera or combination of these*/
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * hpmud_device_open - open specified device, call normally does not block
+ *
+ * inputs:
+ * uri - specifies device to open
+ * io_mode - see enum definition
+ *
+ * outputs:
+ * dd - device descriptor
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_open_device(const char *uri, enum HPMUD_IO_MODE io_mode, HPMUD_DEVICE *dd);
+
+/*
+ * hpmud_device_close - close specified device, call does not block
+ *
+ * inputs:
+ * dd - device descriptor
+ *
+ * outputs:
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_close_device(HPMUD_DEVICE dd);
+
+/*
+ * hpmud_get_device_id - read IEEE 1284 device ID string, call normally does not block
+ *
+ * If the device is busy, a cached copy may be returned.
+ *
+ * inputs:
+ * dd - device descriptor
+ * buf_size - maximum size of buf
+ *
+ * outputs:
+ * buf - zero terminated device ID string
+ * bytes_read - size of device ID string, does not include zero termination
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_device_id(HPMUD_DEVICE dd, char *buf, int buf_size, int *bytes_read);
+
+/*
+ * hpmud_get_device_status - read 8-bit device status, call normally does not block
+ *
+ * inputs:
+ * dd - device descriptor
+ *
+ * outputs:
+ * status - 3-bit status, supported by inkjets only
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_device_status(HPMUD_DEVICE dd, unsigned int *status);
+
+/*
+ * hpmud_probe_devices - probe local buses for HP supported devices, call normally does not block
+ *
+ * inputs:
+ * bus - see enum definiton
+ * buf_size - size of read buffer
+ *
+ * outputs:
+ * buf - zero terminated CUPS backend formatted data
+ * cnt - number of HP devices found
+ * bytes_read - number of bytes actually read
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_probe_devices(enum HPMUD_BUS_ID bus, char *buf, int buf_size, int *cnt, int *bytes_read);
+
+/*
+ * hpmud_channel_open - open specified channel, call will block
+ *
+ * Only EWS channel can be opened by more than one process.
+ *
+ * inputs:
+ * dd - device descriptor
+ * channel_name - requested service name
+ *
+ * outputs:
+ * cd - channel descriptor
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_open_channel(HPMUD_DEVICE dd, const char *channel_name, HPMUD_CHANNEL *cd);
+
+/*
+ * hpmud_channel_close - close specified channel, call will block
+ *
+ * inputs:
+ * dd - device descriptor
+ * cd - channel descriptor
+ *
+ * outputs:
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_close_channel(HPMUD_DEVICE dd, HPMUD_CHANNEL cd);
+
+/*
+ * hpmud_channel_write - write data to specified channel, call will block
+ *
+ * May return with partial bytes written (ie: bytes_wrote < size) with or with-out a timeout.
+ *
+ * inputs:
+ * dd - device descriptor
+ * cd - channel descriptor
+ * buf - data to write
+ * size - number of bytes to write
+ * timeout - in seconds
+ *
+ * outputs:
+ * bytes_wrote - number of bytes actually wrote
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_write_channel(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, const void *buf, int size, int timeout, int *bytes_written);
+
+/*
+ * hpmud_channel_read - read data from specified channel, call will block
+ *
+ * May return with partial bytes read (ie: bytes_read < size) or zero if timeout occured.
+ *
+ * inputs:
+ * dd - device descriptor
+ * cd - channel descriptor
+ * size - number of bytes to read
+ * timeout - in seconds
+ *
+ * outputs:
+ * buf - read data buffer
+ * bytes_read - number of bytes actually read
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_read_channel(HPMUD_DEVICE dd, HPMUD_CHANNEL cd, void *buf, int size, int timeout, int *bytes_read);
+
+/*
+ * hpmud_dstat - get device information
+ *
+ * inputs:
+ * dd - device descriptor
+ *
+ * outputs:
+ * ds - see dstat definition
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_dstat(HPMUD_DEVICE dd, struct hpmud_dstat *ds);
+
+/*
+ * hpmud_set_pml - set pml object
+ *
+ * Set_pml is a high level interface to hpmud. This command calls the hpmud core interface.
+ * This command can be used with local or jetdirect connections. Jetdirect connection will
+ * use snmp.
+ *
+ * inputs:
+ * dd - device descriptor
+ * cc - channel descriptor
+ * snmp_oid - snmp encoded pml oid
+ * type - oid data type
+ * data - data payload
+ * data_size - number of bytes to write
+ *
+ * outputs:
+ * pml_result
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_set_pml(HPMUD_DEVICE device, HPMUD_CHANNEL channel, const char *snmp_oid, int type, void *data, int data_size, int *pml_result);
+
+/*
+ * hpmud_get_pml - get pml object
+ *
+ * Get_pml is a high level interface to hpmud. This command calls the hpmud core interface.
+ * This command can be used with local or jetdirect connections. Jetdirect connection will
+ * use snmp.
+ *
+ * inputs:
+ * dd - device descriptor
+ * cc - channel descriptor
+ * snmp_oid - snmp encoded pml oid
+ * data_size - data buffer size in bytes
+ *
+ * outputs:
+ * data - data payload
+ * type - pml data type
+ * pml_result
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_pml(HPMUD_DEVICE device, HPMUD_CHANNEL channel, const char *snmp_oid, void *buf, int buf_size, int *bytes_read, int *type, int *pml_result);
+
+/*
+ * hpmud_get_model - parse device model from the IEEE 1284 device id string.
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * id - IEEE 1284 device id string
+ * buf_size - size of buf in bytes
+ *
+ * outputs:
+ * buf - device model string (generalized)
+ * return value - length of string in bytes, does not include zero termination
+ */
+int hpmud_get_model(const char *id, char *buf, int buf_size);
+
+/*
+ * hpmud_get_raw_model - parse device model from the IEEE 1284 device id string.
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * id - IEEE 1284 device id string
+ * buf_size - size of buf in bytes
+ *
+ * outputs:
+ * buf - device model string (raw)
+ * return value - length of string in bytes, does not include zero termination
+ */
+int hpmud_get_raw_model(char *id, char *raw, int rawSize);
+
+/*
+ * hpmud_get_uri_model - parse device model from uri
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * uri
+ * buf_size - size of buf in bytes
+ *
+ * outputs:
+ * buf - device model string
+ * return value - length of string in bytes, does not include zero termination
+ */
+int hpmud_get_uri_model(const char *uri, char *buf, int buf_size);
+
+/*
+ * hpmud_get_uri_datalink - parse the data link from uri
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * uri
+ * buf_size - size of buf in bytes
+ *
+ * outputs:
+ * buf - device model string
+ * return value - length of string in bytes, does not include zero termination
+ */
+int hpmud_get_uri_datalink(const char *uri, char *buf, int buf_size);
+
+/*
+ * hpmud_get_model_attributes - get all model attributes for specified device
+ *
+ * Reads device model attributes from models.dat file. This function is a
+ * stateless hpmud helper function.
+ *
+ * inputs:
+ * uri - specifies device
+ * buf_size - size of buf in bytes
+ *
+ * outputs:
+ * buf - buffer for all model attributes, key/value pair, one per line
+ * bytes_read - number of bytes actually read
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_model_attributes(char *uri, char *attr, int attrSize, int *bytes_read);
+
+/*
+ * hpmud_model_query - get model attributes structure for specified device
+ *
+ * Reads device model attributes from models.dat file. This function is a
+ * stateless hpmud helper function.
+ *
+ * inputs:
+ * uri - specifies device
+ *
+ * outputs:
+ * ma - see structure definition
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_query_model(char *uri, struct hpmud_model_attributes *ma);
+
+/*
+ * hpmud_make_usb_uri - make a usb uri from bus:dev pair
+ *
+ * This function is a stateless hpmud helper function. The lsusb command can be used
+ * determine the bus:dev pair.
+ *
+ * inputs:
+ * busnum - specifies usbfs bus number
+ * devnum - specifies usbfs device number
+ * uri_size - size of uri buffer in bytes
+ *
+ * outputs:
+ * uri - zero terminated string
+ * bytes_read - size of uri
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_make_usb_uri(const char *busnum, const char *devnum, char *uri, int uri_size, int *bytes_read);
+
+/*
+ * hpmud_make_usb_serial_uri - make a usb uri from product serial number
+ *
+ * This function is a stateless hpmud helper function. The lsusb command can be used
+ * determine the product serial number.
+ *
+ * inputs:
+ * sn - specifies product serial number
+ * uri_size - size of uri buffer in bytes
+ *
+ * outputs:
+ * uri - zero terminated string
+ * bytes_read - size of uri
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_make_usb_serial_uri(const char *sn, char *uri, int uri_size, int *bytes_read);
+
+/*
+ * hpmud_make_net_uri - make a net uri from IP
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * ip - internet address
+ * port - 1-4
+ * uri_size - size of uri buffer in bytes
+ *
+ * outputs:
+ * uri - zero terminated string
+ * bytes_read - size of uri
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_make_net_uri(const char *ip, int port, char *uri, int uri_size, int *bytes_read);
+
+/*
+ * hpmud_make_par_uri - make a par uri from parallel port
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * dnode - device node
+ * uri_size - size of uri buffer in bytes
+ *
+ * outputs:
+ * uri - zero terminated string
+ * bytes_read - size of uri
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_make_par_uri(const char *dnode, char *uri, int uri_size, int *bytes_read);
+
+/*
+ * hpmud_get_conf - get key value from hplip.conf
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * section - zero terminated string (ie: "[dirs]")
+ * key - zero terminated string (ie: "home")
+ * value_size - size of value buffer in bytes
+ *
+ * outputs:
+ * value - zero terminated string
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_conf(const char *section, const char *key, char *value, int value_size);
+
+/*
+ * hpmud_get_key_value - get key value from specified file
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * file - zero terminated file path
+ * section - zero terminated string (ie: "[dirs]")
+ * key - zero terminated string (ie: "home")
+ * value_size - size of value buffer in bytes
+ *
+ * outputs:
+ * value - zero terminated string
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_get_key_value(const char *file, const char *section, const char *key, char *value, int value_size);
+
+/*
+ * hpmud_mdns_lookup - lookup IP for MDNS host name
+ *
+ * This function is a stateless hpmud helper function.
+ *
+ * inputs:
+ * host_name - zero terminated string (ie: "npi7c8a3e")
+ * sec_timeout - in seconds
+ *
+ * outputs:
+ * ip - zero terminated string
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_mdns_lookup(const char *host_name, int sec_timeout, char *ip);
+
+/*
+ * hpmud_make_mdns_uri - make a network uri from host name
+ *
+ * This function is a stateless hpmud helper function. Requires UDP port 5353 to be open.
+ *
+ * inputs:
+ * host - zero terminated string (ie: "npi7c8a3e")
+ * uri_size - size of uri buffer in bytes
+ *
+ * outputs:
+ * uri - zero terminated string
+ * bytes_read - size of uri
+ * return value - see enum definition
+ */
+enum HPMUD_RESULT hpmud_make_mdns_uri(const char *host, int port, char *uri, int uri_size, int *bytes_read);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _HPMUD_H
+
diff --git a/io/hpmud/hpmudi.h b/io/hpmud/hpmudi.h
new file mode 100644
index 0000000..269cb06
--- /dev/null
+++ b/io/hpmud/hpmudi.h
@@ -0,0 +1,212 @@
+/*****************************************************************************\
+
+ hpmudi.h - internal definitions for multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Author: Naga Samrat Chowdary Narla,
+\*****************************************************************************/
+
+#ifndef _HPMUDI_H
+#define _HPMUDI_H
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <time.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <arpa/inet.h>
+#include "hpmud.h"
+#include "musb.h"
+#include "mlc.h"
+#include "dot4.h"
+#include "pml.h"
+#ifdef HAVE_LIBNETSNMP
+#include "jd.h"
+#endif
+#ifdef HAVE_PPORT
+#include "pp.h"
+#endif
+
+// Don DO NOT commit with HPMUD_DEBUG enabled :(
+//#define HPMUD_DEBUG
+
+#define _STRINGIZE(x) #x
+#define STRINGIZE(x) _STRINGIZE(x)
+
+#define BUG(args...) syslog(LOG_ERR, __FILE__ " " STRINGIZE(__LINE__) ": " args)
+//#define BUG(args...) fprintf(stderr, __FILE__ " " STRINGIZE(__LINE__) ": " args)
+
+#ifdef HPMUD_DEBUG
+ #define DBG(args...) syslog(LOG_INFO, __FILE__ " " STRINGIZE(__LINE__) ": " args)
+// #define DBG(args...) fprintf(stderr, __FILE__ " " STRINGIZE(__LINE__) ": " args)
+ #define DBG_DUMP(data, size) sysdump((data), (size))
+ #define DBG_SZ(args...) syslog(LOG_INFO, args)
+#else
+ #define DBG(args...)
+ #define DBG_DUMP(data, size)
+ #define DBG_SZ(args...)
+#endif
+
+#define HEX2INT(x, i) if (x >= '0' && x <= '9') i |= x - '0'; \
+ else if (x >= 'A' && x <= 'F') i |= 0xA + x - 'A'; \
+ else if (x >= 'a' && x <= 'f') i |= 0xA + x - 'a'
+
+/* offset_of returns the number of bytes that the fieldname MEMBER is offset from the beginning of the structure TYPE */
+#define offset_of(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+#define HPMUD_EXCEPTION_TIMEOUT 45000000 /* microseconds */
+#define HPMUD_EXCEPTION_SEC_TIMEOUT 45 /* seconds */
+#define HPMUD_MDNS_TIMEOUT 10 /* seconds */
+
+#define NFAULT_BIT 0x08
+#define PERROR_BIT 0x20
+
+enum HPMUD_CHANNEL_ID
+{
+ HPMUD_PML_CHANNEL = 1,
+ HPMUD_PRINT_CHANNEL = 2,
+ HPMUD_SCAN_CHANNEL = 4,
+ HPMUD_FAX_SEND_CHANNEL = 7,
+ HPMUD_CONFIG_UPLOAD_CHANNEL = 0xe,
+ HPMUD_CONFIG_DOWNLOAD_CHANNEL = 0xf,
+ HPMUD_MEMORY_CARD_CHANNEL = 0x11,
+ HPMUD_EWS_CHANNEL = 0x12, /* Embeded Web Server interface ff/1/1, any unused socket id */
+ HPMUD_SOAPSCAN_CHANNEL = 0x13, /* Soap Scan interface ff/2/1, any unused socket id */
+ HPMUD_SOAPFAX_CHANNEL = 0x14, /* Soap Fax interface ff/3/1, any unused socket id */
+ HPMUD_MARVELL_SCAN_CHANNEL = 0x15, /* Marvell scan interface ff/ff/ff, any unused socket id */
+ HPMUD_MARVELL_FAX_CHANNEL = 0x16, /* Marvell fax interface ff/ff/ff, any unused socket id */
+ HPMUD_EWS_LEDM_CHANNEL = 0x17, /* Embeded Web Server interface ff/4/1, any unused socket id */
+ HPMUD_LEDM_SCAN_CHANNEL = 0x18, /* LEDM scan interface ff/cc/0, any unused socket id */
+ HPMUD_WIFI_CHANNEL = 0x2b, /* WIFI config */
+ HPMUD_DEVMGMT_CHANNEL = 0x2c, /* decimal 44 */
+ HPMUD_MAX_CHANNEL_ID
+};
+
+#define HPMUD_DEVICE_MAX 2 /* zero is not used */
+#define HPMUD_CHANNEL_MAX HPMUD_MAX_CHANNEL_ID
+
+/* MLC/1284.4 attributes. Note for MLC, attributes must remain persistant while transport is up. */
+typedef struct
+{
+ unsigned short h2pcredit; /* host to peripheral credit (dot4: primary socket id credit for sending) */
+ unsigned short p2hcredit; /* peripheral to host credit (dot4: secondary socket id credit for sending) */
+ unsigned short h2psize; /* host to peripheral packet size in bytes (dot4: primary max packet size for sending) */
+ unsigned short p2hsize; /* peripheral to host packet size in bytes (dot4: secondary max packet size for sending) */
+} transport_attributes;
+
+typedef struct _mud_channel_vf
+{
+ enum HPMUD_RESULT (*open)(struct _mud_channel *pc); /* transport specific open */
+ enum HPMUD_RESULT (*close)(struct _mud_channel *pc); /* transport specific close */
+ enum HPMUD_RESULT (*channel_write)(struct _mud_channel *pc, const void *buf, int size, int timeout, int *bytes_wrote); /* tranport specific write */
+ enum HPMUD_RESULT (*channel_read)(struct _mud_channel *pc, void *buf, int size, int timeout, int *bytes_read); /* transport specific read */
+} mud_channel_vf;
+
+typedef struct _mud_device_vf
+{
+ int (*write)(int fd, const void *buf, int size, int usec_timeout); /* low level device write */
+ int (*read)(int fd, void *buf, int size, int usec_timout); /* low level device read */
+ enum HPMUD_RESULT (*open)(struct _mud_device *pd); /* device specific open */
+ enum HPMUD_RESULT (*close)(struct _mud_device *pd); /* device specific close */
+ enum HPMUD_RESULT (*get_device_id)(struct _mud_device *pd, char *id, int size, int *bytes_read); /* IEEE 1284 device id string */
+ enum HPMUD_RESULT (*get_device_status)(struct _mud_device *pd, unsigned int *status); /* device 8-bit status */
+ enum HPMUD_RESULT (*channel_open)(struct _mud_device *pd, const char *channel_name, HPMUD_CHANNEL *cd); /* channel specific open */
+ enum HPMUD_RESULT (*channel_close)(struct _mud_device *pd, struct _mud_channel *pc); /* channel specific close */
+ enum HPMUD_RESULT (*channel_write)(struct _mud_device *pd, struct _mud_channel *pc, const void *buf, int size, int sec_timeout, int *bytes_wrote);
+ enum HPMUD_RESULT (*channel_read)(struct _mud_device *pd, struct _mud_channel *pc, void *buf, int size, int sec_timeout, int *bytes_read);
+} mud_device_vf;
+
+typedef struct _mud_channel
+{
+ char sn[HPMUD_LINE_SIZE]; /* service name */
+ unsigned char sockid; /* socket id */
+ int client_cnt; /* number of clients using this channel */
+ int index; /* channel[index] of this object */
+ int fd; /* file descriptor for this channel */
+ pid_t pid; /* process owner */
+ int dindex; /* device[dindex] parent device */
+
+ /* MLC/1284.4 specific variables. */
+ transport_attributes ta;
+ unsigned char rbuf[HPMUD_BUFFER_SIZE]; /* read packet buffer */
+ int rindex;
+ int rcnt;
+
+ /* JetDirect specific data. */
+ int socket;
+
+ mud_channel_vf vf;
+} mud_channel;
+
+typedef struct _mud_device
+{
+ char uri[HPMUD_LINE_SIZE];
+ char id[1024]; /* device id */
+ int index; /* device[index] of this object */
+ enum HPMUD_IO_MODE io_mode;
+ mud_channel channel[HPMUD_CHANNEL_MAX];
+ int channel_cnt; /* number of open channels */
+ int open_fd; /* file descriptor used by device_open */
+
+ /* MLC/1284.4 specific variables. */
+ int mlc_up; /* 0=transport down, 1=transport up */
+ int mlc_fd; /* file descriptor used by 1284.4/MLC transport */
+
+ /* JetDirect specific data. */
+ char ip[HPMUD_LINE_SIZE]; /* internet address */
+ int port;
+
+ mud_device_vf vf; /* virtual function table */
+ pthread_mutex_t mutex;
+} mud_device;
+
+typedef struct
+{
+ mud_device device[HPMUD_DEVICE_MAX];
+ pthread_mutex_t mutex;
+} mud_session;
+
+extern mud_session *msp __attribute__ ((visibility ("hidden")));
+
+void __attribute__ ((visibility ("hidden"))) sysdump(const void *data, int size);
+int __attribute__ ((visibility ("hidden"))) mm_device_lock(int fd, HPMUD_DEVICE index);
+int __attribute__ ((visibility ("hidden"))) mm_device_unlock(int fd, HPMUD_DEVICE index);
+int __attribute__ ((visibility ("hidden"))) mm_device_trylock(int fd, HPMUD_DEVICE index);
+int __attribute__ ((visibility ("hidden"))) is_hp(const char *id);
+int __attribute__ ((visibility ("hidden"))) generalize_model(const char *sz, char *buf, int bufSize);
+int __attribute__ ((visibility ("hidden"))) generalize_serial(const char *sz, char *buf, int bufSize);
+int __attribute__ ((visibility ("hidden"))) get_uri_model(const char *uri, char *buf, int bufSize);
+int __attribute__ ((visibility ("hidden"))) get_uri_serial(const char *uri, char *buf, int bufSize);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) service_to_channel(mud_device *pd, const char *sn, HPMUD_CHANNEL *index);
+
+#endif // _HPMUDI_H
+
diff --git a/io/hpmud/jd.c b/io/hpmud/jd.c
new file mode 100644
index 0000000..1b7a382
--- /dev/null
+++ b/io/hpmud/jd.c
@@ -0,0 +1,906 @@
+/*****************************************************************************\
+
+ jd.c - JetDirect support for multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Client/Server generic message format (see messaging-protocol.doc):
+
+ Author: Naga Samrat Chowdary Narla, Sarbeswar Meher
+\*****************************************************************************/
+
+#ifdef HAVE_LIBNETSNMP
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <signal.h>
+#include "hpmud.h"
+#include "hpmudi.h"
+
+mud_device_vf __attribute__ ((visibility ("hidden"))) jd_mud_device_vf =
+{
+ .open = jd_open,
+ .close = jd_close,
+ .get_device_id = jd_get_device_id,
+ .get_device_status = jd_get_device_status,
+ .channel_open = jd_channel_open,
+ .channel_close = jd_channel_close,
+ .channel_write = jd_channel_write,
+ .channel_read = jd_channel_read
+};
+
+static mud_channel_vf jd_channel_vf =
+{
+ .open = jd_s_channel_open,
+ .close = jd_s_channel_close,
+ .channel_write = jd_s_channel_write,
+ .channel_read = jd_s_channel_read
+};
+
+static const int PrintPort[] = { 0, 9100, 9101, 9102 };
+static const int ScanPort0[] = { 0, 9290, 9291, 9292 };
+static const int GenericPort[] = { 0, 9220, 9221, 9222 };
+static const int ScanPort1[] = { 0, 8290, 0, 0 }; /* hack for CLJ28xx */
+static const int GenericPort1[] = { 0, 8292, 0, 0 }; /* hack for CLJ28xx (fax) */
+
+const char __attribute__ ((visibility ("hidden"))) *kStatusOID = "1.3.6.1.4.1.11.2.3.9.1.1.7.0"; /* device id snmp oid */
+
+static int ReadReply(mud_channel *pc)
+{
+ char buf[HPMUD_LINE_SIZE];
+ int len=0, num=0;
+ char *tail;
+ enum HPMUD_RESULT stat;
+
+ stat = jd_s_channel_read(pc, buf, sizeof(buf), 2, &len);
+ buf[len] = 0;
+
+ if (stat == HPMUD_R_OK)
+ num = strtol((char *)buf, &tail, 10);
+
+ return num;
+}
+
+static int device_id(const char *ip, int port, char *buffer, int size)
+{
+ int len=0, maxSize, result, dt, status;
+
+ maxSize = (size > 1024) ? 1024 : size; /* RH8 has a size limit for device id */
+
+ if ((len = GetSnmp(ip, port, (char *)kStatusOID, (unsigned char *)buffer, maxSize, &dt, &status, &result)) == 0)
+ BUG("unable to read device-id\n");
+
+ return len; /* length does not include zero termination */
+}
+
+/* Create channel object given the requested socket id and service name. */
+static int new_channel(mud_device *pd, int index, const char *sn)
+{
+ int stat=1;
+
+ /* Check for existing name service already open. */
+ if (pd->channel[index].client_cnt)
+ {
+#if 0
+ if (index == HPMUD_EWS_CHANNEL)
+ {
+ pd->channel[index].client_cnt++; /* allow multiple clients for separate USB interfaces only */
+ stat = 0;
+ DBG("reused %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
+ }
+ else
+#endif
+ 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);
+ goto bugout;
+ }
+
+ pd->channel[index].vf = jd_channel_vf;
+ pd->channel[index].index = index;
+ pd->channel[index].client_cnt = 1;
+ pd->channel[index].sockid = index;
+ pd->channel[index].pid = getpid();
+ pd->channel[index].dindex = pd->index;
+ pd->channel[index].fd = 0;
+ pd->channel[index].socket = -1;
+ strcpy(pd->channel[index].sn, sn);
+ pd->channel_cnt++;
+
+ stat = 0;
+ DBG("new %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
+
+bugout:
+ return stat;
+}
+
+/* Remove channel object given the channel decriptor. */
+static int del_channel(mud_device *pd, mud_channel *pc)
+{
+ pc->client_cnt--;
+
+ if (pc->client_cnt <= 0)
+ {
+ pd->channel_cnt--;
+ }
+ DBG("removed %s channel=%d clientCnt=%d channelCnt=%d\n", pc->sn, pc->index, pc->client_cnt, pd->channel_cnt);
+ return 0;
+}
+
+/*********************************************************************************************************************************
+ * JetDirect mud_device functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_open(mud_device *pd)
+{
+ char uri_model[128];
+ char model[128];
+ char *p, *tail;
+ int len=0;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (pd->id[0] == 0)
+ {
+ /* First client. */
+ hpmud_get_uri_datalink(pd->uri, pd->ip, sizeof(pd->ip));
+
+ if ((p = strcasestr(pd->uri, "port=")) != NULL)
+ pd->port = strtol(p+5, &tail, 10);
+ else
+ pd->port = 1;
+ if (pd->port > 3)
+ {
+ stat = HPMUD_R_INVALID_IP_PORT;
+ BUG("invalid ip port=%d\n", pd->port);
+ goto blackout;
+ }
+
+ len = device_id(pd->ip, pd->port, pd->id, sizeof(pd->id)); /* get new copy and cache it */
+ if (len == 0)
+ {
+ stat = HPMUD_R_IO_ERROR;
+ goto blackout;
+ }
+ }
+
+ /* Make sure uri model matches device id model. */
+ hpmud_get_uri_model(pd->uri, uri_model, sizeof(uri_model));
+ hpmud_get_model(pd->id, model, sizeof(model));
+ if (strcmp(uri_model, model) != 0)
+ {
+ stat = HPMUD_R_INVALID_URI; /* different device plugged in */
+ BUG("invalid uri model %s != %s\n", uri_model, model);
+ goto blackout;
+ }
+
+ stat = HPMUD_R_OK;
+
+blackout:
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_close(mud_device *pd)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ pthread_mutex_lock(&pd->mutex);
+ pd->id[0] = 0;
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_get_device_id(mud_device *pd, char *buf, int size, int *len)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *len=0;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ *len = device_id(pd->ip, pd->port, pd->id, sizeof(pd->id)); /* get new copy and cache it */
+
+ if (*len)
+ {
+ memcpy(buf, pd->id, *len > size ? size : *len);
+ stat = HPMUD_R_OK;
+ }
+
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_get_device_status(mud_device *pd, unsigned int *status)
+{
+ *status = NFAULT_BIT; /* there is no 8-bit status, so fake it */
+ return HPMUD_R_OK;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_write(mud_device *pd, mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote)
+{
+ enum HPMUD_RESULT stat;
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.channel_write)(pc, buf, length, sec_timeout, bytes_wrote);
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_read(mud_device *pd, mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read)
+{
+ enum HPMUD_RESULT stat;
+
+ if (pd->io_mode == HPMUD_UNI_MODE)
+ {
+ stat = HPMUD_R_INVALID_STATE;
+ BUG("invalid channel_read io_mode=%d\n", pd->io_mode);
+ }
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.channel_read)(pc, buf, length, sec_timeout, bytes_read);
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_open(mud_device *pd, const char *sn, HPMUD_CHANNEL *cd)
+{
+ int index;
+ enum HPMUD_RESULT stat;
+
+ /* Check for valid service requests. */
+ if ((stat = service_to_channel(pd, sn, &index)) != HPMUD_R_OK)
+ goto bugout;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (new_channel(pd, index, sn))
+ {
+ stat = HPMUD_R_DEVICE_BUSY;
+ }
+ else
+ {
+ if ((stat = (pd->channel[index].vf.open)(&pd->channel[index])) != HPMUD_R_OK) /* call transport specific open */
+ del_channel(pd, &pd->channel[index]); /* open failed, cleanup */
+ else
+ *cd = index;
+ }
+
+ pthread_mutex_unlock(&pd->mutex);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_close(mud_device *pd, mud_channel *pc)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.close)(pc); /* call trasport specific close */
+ del_channel(pd, pc);
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * JetDirect channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_open(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ struct sockaddr_in pin;
+ char buf[HPMUD_LINE_SIZE];
+ int r, len, port;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ bzero(&pin, sizeof(pin));
+ pin.sin_family = AF_INET;
+ pin.sin_addr.s_addr = inet_addr(pd->ip);
+
+ switch (pc->index)
+ {
+ case HPMUD_PRINT_CHANNEL:
+ port = PrintPort[pd->port];
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open print port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to print port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_SCAN_CHANNEL:
+ if (pd->io_mode == HPMUD_DOT4_PHOENIX_MODE)
+ port = ScanPort1[pd->port];
+ else
+ port = ScanPort0[pd->port];
+ pin.sin_port = htons(port);
+
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to scan err=%d port %d: %m %s\n", errno, port, pd->uri);
+ goto bugout;
+ }
+ if (pd->io_mode != HPMUD_DOT4_PHOENIX_MODE)
+ {
+ r = ReadReply(pc);
+ if (r != 0)
+ {
+ BUG("invalid scan response %d port %d %s\n", r, port, pd->uri);
+ goto bugout;
+ }
+ }
+ break;
+ case HPMUD_MEMORY_CARD_CHANNEL:
+ case HPMUD_FAX_SEND_CHANNEL:
+ case HPMUD_CONFIG_UPLOAD_CHANNEL:
+ case HPMUD_CONFIG_DOWNLOAD_CHANNEL:
+ if (pd->io_mode == HPMUD_DOT4_PHOENIX_MODE)
+ port = GenericPort1[pd->port];
+ else
+ port = GenericPort[pd->port];
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+
+ if (pd->io_mode != HPMUD_DOT4_PHOENIX_MODE)
+ {
+ r = ReadReply(pc);
+ if (r != 220)
+ {
+ BUG("invalid response %d port %d %s\n", r, port, pd->uri);
+ goto bugout;
+ }
+ len = sprintf(buf, "open %d\n", pc->index);
+ send(pc->socket, buf, len, 0);
+ r = ReadReply(pc);
+ if (r != 200)
+ {
+ BUG("invalid response %d port %d %s\n", r, port, pd->uri);
+ goto bugout;
+ }
+ len = sprintf(buf, "data\n");
+ send(pc->socket, "data\n", len, 0);
+ r = ReadReply(pc);
+ if (r != 200)
+ {
+ BUG("invalid response %d port %d %s\n", r, port, pd->uri);
+ goto bugout;
+ }
+ }
+
+ break;
+ case HPMUD_EWS_CHANNEL:
+ port = 80;
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open ews port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to ews port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_SOAPSCAN_CHANNEL:
+ port = 8289;
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open soap-scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to soap-scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_SOAPFAX_CHANNEL:
+ port = 8295;
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open soap-fax port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to soap-fax port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_MARVELL_SCAN_CHANNEL:
+ port = 8290; /* same as ScanPort1[1] */
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open marvell-scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to marvell-scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_LEDM_SCAN_CHANNEL:
+ case HPMUD_EWS_LEDM_CHANNEL:
+ port = 8080;
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open ledm-scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to ledm-scan port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_MARVELL_FAX_CHANNEL:
+ port = 8285;
+ pin.sin_port = htons(port);
+ if ((pc->socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ {
+ BUG("unable to open marvell-fax port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ if (connect(pc->socket, (struct sockaddr *)&pin, sizeof(pin)) == -1)
+ {
+ BUG("unable to connect to marvell-fax port %d: %m %s\n", port, pd->uri);
+ goto bugout;
+ }
+ break;
+ case HPMUD_PML_CHANNEL:
+ /* Do nothing here, use GetPml/SetPml instead of ReadData/WriteData. */
+ break;
+ default:
+ BUG("unsupported service %d %s\n", pc->index, pd->uri);
+ stat = HPMUD_R_INVALID_SN;
+ goto bugout;
+ break;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_close(mud_channel *pc)
+{
+ if (pc->socket >= 0)
+ {
+ close(pc->socket);
+
+ /* Delay for back-to-back scanning using scanimage. Otherwise next channel_open(HPMUD_SCAN_CHANNEL) can fail. */
+ sleep(1);
+ }
+
+ pc->socket = -1;
+
+ return HPMUD_R_OK;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_write(mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int len, size, total=0;
+ struct timeval tmo;
+ fd_set master;
+ fd_set writefd;
+ int maxfd, ret;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_wrote=0;
+ size = length;
+
+ if (pc->socket<0)
+ {
+ stat = HPMUD_R_INVALID_STATE;
+ BUG("invalid data link socket=%d %s\n", pc->socket, pd->uri);
+ goto bugout;
+ }
+
+ FD_ZERO(&master);
+ FD_SET(pc->socket, &master);
+ maxfd = pc->socket;
+ size = length;
+
+ while (size > 0)
+ {
+ tmo.tv_sec = HPMUD_EXCEPTION_SEC_TIMEOUT; /* note linux select will modify tmo */
+ tmo.tv_usec = 0;
+ writefd = master;
+ if ((ret = select(maxfd+1, NULL, &writefd, NULL, &tmo)) == 0)
+ {
+ stat = HPMUD_R_IO_TIMEOUT;
+ BUG("timeout write_channel %s\n", pd->uri);
+ goto bugout; /* timeout */
+ }
+ len = send(pc->socket, buf+total, size, 0);
+ if (len < 0)
+ {
+ BUG("unable to write_channel: %m %s\n", pd->uri);
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ *bytes_wrote+=len;
+ }
+
+ DBG("write socket=%d len=%d size=%d\n", pc->socket, len, length);
+ DBG_DUMP(buf, len < 32 ? len : 32);
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/*
+ * Channel_read() tries to read "length" bytes from the peripheral. The returned read count may be zero
+ * (timeout, no data available), less than "length" or equal "length".
+ */
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_read(mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int len=0;
+ struct timeval tmo;
+ fd_set master;
+ fd_set readfd;
+ int maxfd, ret;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_read = 0;
+
+ if (pc->socket<0)
+ {
+ stat = HPMUD_R_INVALID_STATE;
+ BUG("invalid data link socket=%d %s\n", pc->socket, pd->uri);
+ goto bugout;
+ }
+
+ FD_ZERO(&master);
+ FD_SET(pc->socket, &master);
+ maxfd = pc->socket;
+ tmo.tv_sec = sec_timeout;
+ tmo.tv_usec = 0;
+
+ readfd = master;
+ ret = select(maxfd+1, &readfd, NULL, NULL, &tmo);
+ if (ret < 0)
+ {
+ BUG("unable to read_channel: %m %s\n", pd->uri);
+ goto bugout;
+ }
+ if (ret == 0)
+ {
+ stat = HPMUD_R_IO_TIMEOUT;
+// if (sec_timeout >= HPMUD_EXCEPTION_SEC_TIMEOUT)
+ BUG("timeout read_channel sec=%d %s\n", sec_timeout, pd->uri);
+ goto bugout;
+ }
+ else
+ {
+ if ((len = recv(pc->socket, buf, length, 0)) < 0)
+ {
+ BUG("unable to read_channel: %m %s\n", pd->uri);
+ goto bugout;
+ }
+ }
+
+ DBG("read socket=%d len=%d size=%d\n", pc->socket, len, length);
+ DBG_DUMP(buf, len < 32 ? len : 32);
+
+ *bytes_read = len;
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/* Convert "www.google.com" to "3www6google3com". */
+static int convert_name_to_dns(const char *name, int name_size, unsigned char *dns_name)
+{
+ int i, x=0;
+ unsigned char *p=dns_name;
+
+ for (i=0; i<name_size; i++)
+ {
+ if (name[i]=='.')
+ {
+ *p++ = i-x; /* length */
+ for (; x<i; x++)
+ *p++ = name[x];
+ x++;
+ }
+ }
+
+ if (i)
+ {
+ i--;
+ *p++ = i-x; /* length */
+ for (; x<i; x++)
+ *p++ = name[x];
+ x++;
+ }
+
+ dns_name[x++]=0;
+
+ return x; /* return length DOES include null termination */
+}
+
+/*
+ * Lookup IP for MDNS host name.
+ * MDNS host name example: "npi7c8a3e" (LaserJet p2055dn)
+ */
+enum HPMUD_RESULT hpmud_mdns_lookup(const char *host_name, int sec_timeout, char *ip)
+{
+ struct sockaddr_in send_addr;
+ struct sockaddr_in recv_addr;
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+ struct timeval tmo;
+ fd_set master;
+ fd_set readfd;
+ int i, len, n, host_len, yes=1;
+ int maxfd, ret;
+ int udp_socket;
+ char recvbuffer[256], host[256];
+ unsigned char dnsquery[256]={0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+ unsigned char tail[] = {0x0, 0x1, 0x0, 0x1};
+ unsigned char loop=0, ttl=255;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ DBG("mdns lookup '%s'\n", host_name);
+
+ if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ {
+ BUG("unable to create udp socket: %m\n");
+ goto bugout;
+ }
+
+ /* Get rid of "address already in use" error message. */
+ if (setsockopt(udp_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
+ {
+ BUG("unable to setsockopt: %m\n");
+ goto bugout;
+ }
+
+ /* Bind the socket to port and IP equal to INADDR_ANY. */
+ bzero(&recv_addr, sizeof(recv_addr));
+ recv_addr.sin_family = AF_INET;
+ recv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ recv_addr.sin_port = htons(5353);
+ if (bind(udp_socket, (struct sockaddr *)&recv_addr, sizeof(recv_addr)) == -1)
+ {
+ BUG("unable to bind udp socket: %m\n");
+ goto bugout;
+ }
+
+ /* Set multicast loopback off. */
+ if (setsockopt(udp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) == -1)
+ {
+ BUG("unable to setsockopt: %m\n");
+ goto bugout;
+ }
+
+ /* Set ttl to 255. Required by mdns. */
+ if (setsockopt(udp_socket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == -1)
+ {
+ BUG("unable to setsockopt: %m\n");
+ goto bugout;
+ }
+
+ /* Convert host name to mdns host name. */
+ host_len = snprintf(host, sizeof(host), "%s.local", host_name) + 1;
+
+ /* Create dns message. (header + question) */
+ n = convert_name_to_dns(host, host_len, dnsquery+12);
+ memcpy(dnsquery+12+n, tail, sizeof(tail));
+ n = 12+n+sizeof(tail);
+
+ i=0;
+ while (1)
+ {
+
+ DBG("send socket=%d len=%d\n", udp_socket, n);
+ DBG_DUMP(dnsquery, n);
+
+ bzero(&send_addr, sizeof(send_addr));
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_addr.s_addr = inet_addr("224.0.0.251");
+ send_addr.sin_port = htons(5353);
+ sendto(udp_socket, dnsquery, n, 0, (struct sockaddr *)&send_addr, sizeof(send_addr));
+
+ FD_ZERO(&master);
+ FD_SET(udp_socket, &master);
+ maxfd = udp_socket;
+ tmo.tv_sec = 0;
+ tmo.tv_usec = 500000;
+
+ readfd = master;
+ ret = select(maxfd+1, &readfd, NULL, NULL, &tmo);
+ if (ret < 0)
+ {
+ BUG("error mdns lookup %s: %m\n", host);
+ goto bugout;
+ }
+ if (ret == 0)
+ {
+ goto retry;
+ }
+ else
+ {
+ bzero(&addr, sizeof(addr));
+ addrlen = sizeof(addr);
+ if ((len = recvfrom(udp_socket, recvbuffer, sizeof(recvbuffer), 0, (struct sockaddr *)&addr, &addrlen)) < 0)
+ {
+ BUG("error mdns lookup %s: %m\n", host);
+ goto bugout;
+ }
+
+ /* Make sure reply is from specified host. */
+ if (strncasecmp((const char *)dnsquery+12, (const char *)recvbuffer+12, n)==0)
+ break;
+ BUG("error mdns lookup %s: bad hostname in reply from ip=%s port=%d\n", host, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ }
+
+retry:
+ if (i++ >= 2 * sec_timeout)
+ {
+ BUG("error timeout mdns lookup %s\n", host);
+ goto bugout;
+ }
+
+ BUG("mdns lookup %s retry %d...\n", host, i);
+ }
+
+ strcpy(ip, inet_ntoa(addr.sin_addr));
+
+ DBG("recv socket=%d len=%d port=%d ip=%s\n", udp_socket, len, ntohs(addr.sin_port), ip);
+ DBG_DUMP(recvbuffer, len);
+
+ stat = HPMUD_R_OK;
+
+bugout:
+
+ if (udp_socket >= 0)
+ close(udp_socket);
+
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_make_net_uri(const char *ip, int port, char *uri, int uri_size, int *bytes_read)
+{
+ char id[1024];
+ char model[128];
+ enum HPMUD_RESULT stat;
+
+ DBG("[%d] hpmud_make_net_uri() ip=%s port=%d\n", getpid(), ip, port);
+
+ *bytes_read=0;
+
+ uri[0]=0;
+
+ if (ip[0]==0)
+ {
+ BUG("invalid ip %s\n", ip);
+ stat = HPMUD_R_INVALID_IP;
+ goto bugout;
+ }
+
+ if (device_id(ip, port, id, sizeof(id)) > 0 && is_hp(id))
+ {
+ hpmud_get_model(id, model, sizeof(model));
+ if (port == 1)
+ *bytes_read = snprintf(uri, uri_size, "hp:/net/%s?ip=%s", model, ip);
+ else
+ *bytes_read = snprintf(uri, uri_size, "hp:/net/%s?ip=%s&port=%d", model, ip, port);
+ }
+ else
+ {
+ BUG("invalid ip %s\n", ip);
+ stat = HPMUD_R_INVALID_IP;
+ goto bugout;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_make_mdns_uri(const char *host, int port, char *uri, int uri_size, int *bytes_read)
+{
+ char id[1024];
+ char model[128];
+ char ip[HPMUD_LINE_SIZE]; /* internet address */
+ enum HPMUD_RESULT stat;
+
+ DBG("[%d] hpmud_make_mdns_uri() host=%s port=%d\n", getpid(), host, port);
+
+ *bytes_read=0;
+
+ uri[0]=0;
+
+ if (host[0]==0)
+ {
+ BUG("invalid host %s\n", host);
+ stat = HPMUD_R_INVALID_MDNS;
+ goto bugout;
+ }
+
+ if (hpmud_mdns_lookup(host, HPMUD_MDNS_TIMEOUT, ip) != HPMUD_R_OK)
+ {
+ BUG("invalid host %s, check firewall UDP/5353 or try using IP\n", host);
+ stat = HPMUD_R_INVALID_MDNS;
+ goto bugout;
+ }
+
+ if (device_id(ip, port, id, sizeof(id)) > 0 && is_hp(id))
+ {
+ hpmud_get_model(id, model, sizeof(model));
+ if (port == 1)
+ *bytes_read = snprintf(uri, uri_size, "hp:/net/%s?zc=%s", model, host);
+ else
+ *bytes_read = snprintf(uri, uri_size, "hp:/net/%s?zc=%s&port=%d", model, host, port);
+ }
+ else
+ {
+ BUG("invalid host %s, or try using IP\n", host);
+ stat = HPMUD_R_INVALID_MDNS;
+ goto bugout;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+#endif /* HAVE_LIBNETSNMP */
diff --git a/io/hpmud/jd.h b/io/hpmud/jd.h
new file mode 100644
index 0000000..f252fd8
--- /dev/null
+++ b/io/hpmud/jd.h
@@ -0,0 +1,56 @@
+/*****************************************************************************\
+
+ jd.h - JetDirect support for multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#ifndef _JD_H
+#define _JD_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "hpmud.h"
+#include "hpmudi.h"
+
+struct _mud_device;
+struct _mud_channel;
+
+extern const char __attribute__ ((visibility ("hidden"))) *kStatusOID; /* device id snmp oid */
+
+extern struct _mud_device_vf __attribute__ ((visibility ("hidden"))) jd_mud_device_vf;
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_open(struct _mud_device *pd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_close(struct _mud_device *pd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_get_device_id(struct _mud_device *pd, char *buf, int size, int *len);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_get_device_status(struct _mud_device *pd, unsigned int *status);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_open(struct _mud_device *pd, const char *sn, HPMUD_CHANNEL *cd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_close(struct _mud_device *pd, struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_write(struct _mud_device *pd, struct _mud_channel *pc, const void *buf, int length, int timeout, int *bytes_wrote);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_channel_read(struct _mud_device *pd, struct _mud_channel *pc, void *buf, int length, int timeout, int *bytes_read);
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_close(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_write(struct _mud_channel *pc, const void *buf, int length, int timeout, int *bytes_wrote);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) jd_s_channel_read(struct _mud_channel *pc, void *buf, int length, int timeout, int *bytes_wrote);
+
+#endif // _JD_H
+
diff --git a/io/hpmud/list.h b/io/hpmud/list.h
new file mode 100644
index 0000000..007e704
--- /dev/null
+++ b/io/hpmud/list.h
@@ -0,0 +1,131 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+/*
+ * This linked list implementation is the same as linux kernel implementation.
+ * Refer to the linux kernel documentation for usage.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head * new_entry,
+ struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = new_entry;
+ new_entry->next = next;
+ new_entry->prev = prev;
+ prev->next = new_entry;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new_entry, struct list_head *head)
+{
+ __list_add(new_entry, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new_entry, struct list_head *head)
+{
+ __list_add(new_entry, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev,
+ struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = entry->prev = 0;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+#endif /* _LIST_H */
diff --git a/io/hpmud/mlc.c b/io/hpmud/mlc.c
new file mode 100644
index 0000000..e8b9784
--- /dev/null
+++ b/io/hpmud/mlc.c
@@ -0,0 +1,772 @@
+/*****************************************************************************\
+
+ mlc.c - MLC support for multi-point tranport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#include "hpmud.h"
+#include "hpmudi.h"
+
+int __attribute__ ((visibility ("hidden"))) cut_buf(mud_channel *pc, char *buf, int size)
+{
+ int len;
+
+ if (pc->rcnt > size)
+ {
+ /* Return part of rbuf. */
+ len = size;
+ memcpy(buf, &pc->rbuf[pc->rindex], len);
+ pc->rindex += len;
+ pc->rcnt -= len;
+ }
+ else
+ {
+ /* Return all of rbuf. */
+ len = pc->rcnt;
+ memcpy(buf, &pc->rbuf[pc->rindex], len);
+ pc->rindex = pc->rcnt = 0;
+ }
+
+ return len;
+}
+
+/* Write command reply back to peripheral. */
+static int MlcForwardReply(mud_channel *pc, int fd, unsigned char *buf, int size)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int len=0;
+
+ if ((len = (pd->vf.write)(fd, buf, size, HPMUD_EXCEPTION_TIMEOUT)) != size)
+ {
+ BUG("unable to MlcForwarReply: %m\n");
+ }
+ return len;
+}
+
+/* Execute command from peripheral. */
+static int MlcExecReverseCmd(mud_channel *pc, int fd, unsigned char *buf)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ mud_channel *out_of_bound_channel;
+ MLCCmd *pCmd;
+ MLCReply *pReply;
+ MLCCredit *pCredit;
+ MLCCreditReply *pCreditReply;
+ MLCCreditRequest *pCreditReq;
+ MLCCreditRequestReply *pCreditReqReply;
+ MLCError *pError;
+ int len, size;
+ static int cnt;
+
+ pCmd = (MLCCmd *)buf;
+
+ /* See if this packet is a command packet. */
+ if (!(pCmd->h.hsid == 0 && pCmd->h.psid == 0))
+ {
+ if (pCmd->h.hsid == pCmd->h.psid)
+ {
+ /* Got a valid data packet handle it. This can happen when channel_read timeouts and p2hcredit=1. */
+ out_of_bound_channel = &pd->channel[pCmd->h.hsid];
+
+ if (out_of_bound_channel->ta.p2hcredit <= 0)
+ {
+ BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
+ return 0;
+ }
+
+ size = ntohs(pCmd->h.length) - sizeof(MLCHeader);
+ if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
+ {
+ BUG("invalid data packet size=%d\n", size);
+ return 0;
+ }
+ memcpy(&out_of_bound_channel->rbuf[out_of_bound_channel->rcnt], buf+sizeof(MLCHeader), size);
+ out_of_bound_channel->rcnt += size;
+ if (pCmd->h.credit)
+ out_of_bound_channel->ta.h2pcredit += pCmd->h.credit; /* note, piggy back credit is 1 byte wide */
+ out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
+ }
+ else
+ {
+ len = ntohs(pCmd->h.length);
+ BUG("unsolicited data packet: hsid=%x, psid=%x, length=%d, credit=%d, status=%x\n", pCmd->h.hsid,
+ pCmd->h.psid, len, pCmd->h.credit, pCmd->h.status);
+ DBG_DUMP(buf, len);
+ }
+ return 0;
+ }
+
+ /* Process any command. */
+ switch (pCmd->cmd)
+ {
+ case MLC_CREDIT:
+ pCredit = (MLCCredit *)buf;
+ out_of_bound_channel = &pd->channel[pCredit->hsocket];
+ out_of_bound_channel->ta.h2pcredit += ntohs(pCredit->credit);
+ pCreditReply = (MLCCreditReply *)buf;
+ pCreditReply->h.length = htons(sizeof(MLCCreditReply));
+ pCreditReply->cmd |= 0x80;
+ pCreditReply->result = 0;
+ MlcForwardReply(pc, fd, (unsigned char *)pCreditReply, sizeof(MLCCreditReply));
+ break;
+ case MLC_CREDIT_REQUEST:
+ pCreditReq = (MLCCreditRequest *)buf;
+ if (cnt++ < 5)
+ BUG("unexpected MLCCreditRequest: cmd=%x, hid=%x, pid=%x, credit=%d\n", pCreditReq->cmd,
+ pCreditReq->hsocket, pCreditReq->psocket, ntohs(pCreditReq->credit));
+ pCreditReqReply = (MLCCreditRequestReply *)buf;
+ pCreditReqReply->h.length = htons(sizeof(MLCCreditRequestReply));
+ pCreditReqReply->cmd |= 0x80;
+ pCreditReqReply->result = 0;
+ pCreditReqReply->credit = 0;
+ MlcForwardReply(pc, fd, (unsigned char *)pCreditReqReply, sizeof(MLCCreditRequestReply));
+ break;
+ case MLC_ERROR:
+ pError = (MLCError *)buf;
+ BUG("unexpected MLCError: cmd=%x, result=%x\n", pError->cmd, pError->result);
+ return 1;
+ default:
+ pReply = (MLCReply *)buf;
+ BUG("unexpected command: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ pReply->h.length = htons(sizeof(MLCReply));
+ pReply->cmd |= 0x80;
+ pReply->result = 1;
+ MlcForwardReply(pc, fd, (unsigned char *)pReply, sizeof(MLCReply));
+ break;
+ }
+ return 0;
+}
+
+/* Get command from peripheral and processes the reverse command. */
+int __attribute__ ((visibility ("hidden"))) MlcReverseCmd(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, size;
+ unsigned int pklen;
+ unsigned char *pBuf;
+ MLCReply *pPk;
+
+ pPk = (MLCReply *)buf;
+
+ pBuf = buf;
+
+ /* Read packet header. */
+ size = sizeof(MLCHeader);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseCmd header: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ /* Determine packet size. */
+ if ((pklen = ntohs(pPk->h.length)) > sizeof(buf))
+ {
+ BUG("invalid MlcReverseCmd packet size: size=%d\n", pklen);
+ stat = 1;
+ goto bugout;
+ }
+
+ /* Read packet data field. */
+ size = pklen - sizeof(MLCHeader);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseCmd data: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ stat = MlcExecReverseCmd(pc, fd, buf);
+
+bugout:
+ return stat;
+}
+
+/*
+ * Get command reply from peripheral. Waits for reply then returns. Processes any reverse commands
+ * while waiting for a reply.
+ */
+static int MlcReverseReply(mud_channel *pc, int fd, unsigned char *buf, int bufsize)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int stat=0, len, size, pklen;
+ unsigned char *pBuf;
+ MLCReply *pPk;
+
+ pPk = (MLCReply *)buf;
+
+ while (1)
+ {
+ pBuf = buf;
+
+ /* Read packet header. */
+ size = sizeof(MLCHeader);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, 4000000)) < 0) /* wait 4 seconds, same as dot4 */
+ {
+ BUG("unable to read MlcReverseReply header: %m bytesRead=%zd\n", sizeof(MLCHeader)-size);
+ stat = 2; /* short timeout */
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ /* Determine packet size. */
+ pklen = ntohs(pPk->h.length);
+ if (pklen < 0 || pklen > bufsize)
+ {
+ BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
+ stat = 1;
+ goto bugout;
+ }
+
+ if (pklen == 0)
+ {
+ /* Got invalid MLC header from peripheral, try this "off-by-one" firmware hack (ie: OJ600). */
+ BUG("trying MlcReverseReply firmware hack\n");
+ memcpy(buf, &buf[1], sizeof(MLCHeader)-1);
+ pklen = ntohs(pPk->h.length);
+ if (pklen <= 0 || pklen > bufsize)
+ {
+ BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
+ stat = 1;
+ goto bugout;
+ }
+ if ((len = (pd->vf.read)(fd, --pBuf, 1, 1000000)) < 0) /* wait 1 second */
+ {
+ BUG("unable to read MlcReverseReply header: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+ pBuf++;
+ DBG_DUMP(buf, sizeof(MLCHeader));
+ }
+
+ /* Read packet data field. */
+ size = pklen - sizeof(MLCHeader);
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseReply data: %m exp=%zd act=%zd\n", pklen-sizeof(MLCHeader), pklen-sizeof(MLCHeader)-size);
+ stat = 1;
+ goto bugout;
+ }
+ size-=len;
+ pBuf+=len;
+ }
+
+ /* Check for reply. */
+ if (pPk->cmd & 0x80)
+ break;
+
+ stat = MlcExecReverseCmd(pc, fd, buf);
+
+ if (stat != 0)
+ break;
+
+ } /* while (1) */
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcInit(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n, cnt;
+ MLCInit *pCmd;
+ MLCInitReply *pReply;
+
+ memset(buf, 0, sizeof(MLCInit));
+ pCmd = (MLCInit *)buf;
+ n = sizeof(MLCInit);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_INIT;
+ pCmd->rev = 3;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MLCInit: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ cnt=0;
+ while(1)
+ {
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCInitReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_INIT)) || (pReply->result != 0))
+ {
+ if (errno == EIO && cnt<1)
+ {
+ /* hack for usblp.c 2.6.5 */
+ BUG("invalid MLCInitReply retrying...\n");
+ sleep(1);
+ cnt++;
+ continue;
+ }
+ if (stat == 2 && cnt<1)
+ {
+ /* hack for Tahoe */
+ BUG("invalid MLCInitReply retrying command...\n");
+ memset(buf, 0, sizeof(MLCInit));
+ n = sizeof(MLCInit);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_INIT;
+ pCmd->rev = 3;
+ (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT);
+ cnt++;
+ continue;
+ }
+ BUG("invalid MLCInitReply: cmd=%x, result=%x\n, revision=%x\n", pReply->cmd, pReply->result, pReply->rev);
+ stat = 1;
+ goto bugout;
+ }
+ break;
+ }
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcExit(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ MLCExit *pCmd;
+ MLCExitReply *pReply;
+
+ memset(buf, 0, sizeof(MLCExit));
+ pCmd = (MLCExit *)buf;
+ n = sizeof(MLCExit);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_EXIT;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MLCExit: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCExitReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_EXIT)) || (pReply->result != 0))
+ {
+ BUG("invalid MLCExitReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcConfigSocket(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ MLCConfigSocket *pCmd;
+ MLCConfigSocketReply *pReply;
+
+ if (pc->ta.h2psize > 0)
+ return stat; /* already got host/peripheral packet sizes */
+
+ memset(buf, 0, sizeof(MLCConfigSocket));
+ pCmd = (MLCConfigSocket *)buf;
+ n = sizeof(MLCConfigSocket);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_CONFIG_SOCKET;
+ pCmd->socket = pc->sockid;
+ pCmd->h2psize = htons(HPMUD_BUFFER_SIZE);
+ pCmd->p2hsize = htons(HPMUD_BUFFER_SIZE);
+ pCmd->status = 0; /* status level?? */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MLCConfigSocket: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCConfigSocketReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CONFIG_SOCKET)) || (pReply->result != 0))
+ {
+ BUG("invalid MLCConfigSocketReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.h2psize = ntohs(pReply->h2psize);
+ pc->ta.p2hsize = ntohs(pReply->p2hsize);
+
+bugout:
+ return stat;
+}
+
+/* Write data to peripheral. */
+int __attribute__ ((visibility ("hidden"))) MlcForwardData(mud_channel *pc, int fd, const void *buf, int size, int usec_timeout)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int stat=0, len, n;
+ MLCHeader h;
+
+ memset(&h, 0, sizeof(h));
+ n = sizeof(MLCHeader) + size;
+ h.length = htons(n);
+ h.hsid = pc->sockid;
+ h.psid = pc->sockid;
+
+ if ((len = (pd->vf.write)(fd, &h, sizeof(MLCHeader), usec_timeout)) != sizeof(MLCHeader))
+ {
+ BUG("unable to write MlcForwardData header: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ if ((len = (pd->vf.write)(fd, buf, size, usec_timeout)) != size)
+ {
+ BUG("unable to write MlcForwardData: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+bugout:
+ return stat;
+}
+
+/* Read data from peripheral. */
+int __attribute__ ((visibility ("hidden"))) MlcReverseData(mud_channel *pc, int fd, void *buf, int length, int usec_timeout)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ mud_channel *out_of_bound_channel;
+ int len, size, total;
+ MLCHeader *pPk;
+
+ pPk = (MLCHeader *)buf;
+
+ while (1)
+ {
+ total = 0;
+
+ /* Read packet header. */
+ size = sizeof(MLCHeader);
+ while (size > 0)
+ {
+ /* Use requested client timeout until we start reading. */
+ if (total == 0)
+ len = (pd->vf.read)(fd, buf+total, size, usec_timeout);
+ else
+ len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT);
+
+ if (len < 0)
+ {
+ /* Got a timeout, if exception timeout or timeout occured after read started thats an error. */
+ if (usec_timeout >= HPMUD_EXCEPTION_TIMEOUT || total > 0)
+ BUG("unable to read MlcReverseData header: %m %s\n", pd->uri);
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ }
+
+ /* Determine data size. */
+ size = ntohs(pPk->length) - sizeof(MLCHeader);
+
+ if (size > length)
+ {
+ BUG("invalid MlcReverseData size: size=%d, buf=%d\n", size, length);
+ goto bugout;
+ }
+
+ /* Make sure data packet is for this channel. */
+ if (pPk->hsid != pc->sockid && pPk->psid != pc->sockid)
+ {
+ if (pPk->hsid == 0 && pPk->psid == 0)
+ {
+ /* Ok, got a command channel packet instead of a data packet, handle it... */
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseData command: %m\n");
+ goto bugout;
+ }
+ size-=len;
+ total=len;
+ }
+ MlcExecReverseCmd(pc, fd, buf);
+ continue; /* try again for data packet */
+ }
+ else if (pPk->hsid == pPk->psid)
+ {
+ /* Got a valid data packet for another channel handle it. This can happen when ReadData timeouts and p2hcredit=1. */
+ out_of_bound_channel = &pd->channel[pPk->hsid];
+ unsigned char *pBuf;
+
+ if (out_of_bound_channel->ta.p2hcredit <= 0)
+ {
+ BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
+ goto bugout;
+ }
+
+ if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
+ {
+ BUG("invalid data packet size=%d\n", size);
+ goto bugout;
+ }
+
+ total = 0;
+ pBuf = &out_of_bound_channel->rbuf[out_of_bound_channel->rcnt];
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, pBuf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseData: %m\n");
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ }
+
+ out_of_bound_channel->rcnt += total;
+ if (pPk->credit)
+ out_of_bound_channel->ta.h2pcredit += pPk->credit; /* note, piggy back credit is 1 byte wide */
+ out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
+ continue; /* try again for data packet */
+ }
+ else
+ {
+ MLCCmd *pCmd = (MLCCmd *)buf;
+ BUG("invalid MlcReverseData state: exp hsid=%x, act hsid=%x, psid=%x, length=%d, credit=%d, status=%x, cmd=%x\n", pc->sockid,
+ pPk->hsid, pPk->psid, ntohs(pPk->length), pPk->credit, pPk->status, pCmd->cmd);
+ goto bugout;
+ }
+ }
+
+ if (pPk->credit)
+ {
+ pc->ta.h2pcredit += pPk->credit; /* note, piggy back credit is 1 byte wide */
+ }
+
+ total = 0; /* eat packet header */
+
+ /* Read packet data field with exception_timeout. */
+ while (size > 0)
+ {
+ if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
+ {
+ BUG("unable to read MlcReverseData: %m\n");
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ }
+ break; /* done reading data packet */
+ } /* while (1) */
+
+bugout:
+ return total;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcOpenChannel(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ MLCOpenChannel *pCmd;
+ MLCOpenChannelReply *pReply;
+
+ memset(buf, 0, sizeof(MLCOpenChannel));
+ pCmd = (MLCOpenChannel *)buf;
+ n = sizeof(MLCOpenChannel);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_OPEN_CHANNEL;
+ pCmd->hsocket = pc->sockid; /* assume static socket ids */
+ pCmd->psocket = pc->sockid;
+ pCmd->credit = htons(0); /* credit sender will accept from receiver (set by MlcDevice::ReadData) */
+ // SetH2PCredit(0); /* initialize sender to receiver credit */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MlcOpenChannel: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCOpenChannelReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_OPEN_CHANNEL)) || (pReply->result != 0))
+ {
+ BUG("invalid MlcOpenChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.h2pcredit = ntohs(pReply->credit);
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcCloseChannel(mud_channel *pc, int fd)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ MLCCloseChannel *pCmd;
+ MLCCloseChannelReply *pReply;
+
+ memset(buf, 0, sizeof(MLCCloseChannel));
+ pCmd = (MLCCloseChannel *)buf;
+ n = sizeof(MLCCloseChannel);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_CLOSE_CHANNEL;
+ pCmd->hsocket = pc->sockid; /* assume static socket ids */
+ pCmd->psocket = pc->sockid;
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MlcCloseChannel: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCCloseChannelReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CLOSE_CHANNEL)) || (pReply->result != 0))
+ {
+ BUG("invalid MlcCloseChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcCredit(mud_channel *pc, int fd, unsigned short credit)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ MLCCredit *pCmd;
+ MLCCreditReply *pReply;
+
+ memset(buf, 0, sizeof(MLCCredit));
+ pCmd = (MLCCredit *)buf;
+ n = sizeof(MLCCredit);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_CREDIT;
+ pCmd->hsocket = pc->sockid; /* assume static socket ids */
+ pCmd->psocket = pc->sockid;
+ pCmd->credit = htons(credit); /* set peripheral to host credit */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MlcCredit: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCCreditReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT)) || (pReply->result != 0))
+ {
+ BUG("invalid MlcCreditReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.p2hcredit += credit;
+
+bugout:
+ return stat;
+}
+
+int __attribute__ ((visibility ("hidden"))) MlcCreditRequest(mud_channel *pc, int fd, unsigned short credit)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char buf[HPMUD_BUFFER_SIZE];
+ int stat=0, len, n;
+ MLCCreditRequest *pCmd;
+ MLCCreditRequestReply *pReply;
+
+ memset(buf, 0, sizeof(MLCCreditRequest));
+ pCmd = (MLCCreditRequest *)buf;
+ n = sizeof(MLCCreditRequest);
+ pCmd->h.length = htons(n);
+ pCmd->cmd = MLC_CREDIT_REQUEST;
+ pCmd->hsocket = pc->sockid; /* assume static socket ids */
+ pCmd->psocket = pc->sockid;
+ pCmd->credit = htons(credit); /* request host to peripheral credit */
+
+ if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
+ {
+ BUG("unable to write MlcCreditRequest: %m\n");
+ stat = 1;
+ goto bugout;
+ }
+
+ stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
+ pReply = (MLCCreditRequestReply *)buf;
+
+ if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT_REQUEST)) || (pReply->result != 0))
+ {
+ BUG("invalid MlcCreditRequestReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
+ stat = 1;
+ goto bugout;
+ }
+
+ pc->ta.h2pcredit += ntohs(pReply->credit);
+
+bugout:
+ return stat;
+}
+
+
+
diff --git a/io/hpmud/mlc.h b/io/hpmud/mlc.h
new file mode 100644
index 0000000..afc6b22
--- /dev/null
+++ b/io/hpmud/mlc.h
@@ -0,0 +1,150 @@
+/*****************************************************************************\
+
+ mlc.h - MLC support for multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#ifndef _MLC_H
+#define _MLC_H
+
+enum MLC_COMMAND
+{
+ MLC_INIT = 0,
+ MLC_OPEN_CHANNEL = 1,
+ MLC_CLOSE_CHANNEL = 2,
+ MLC_CREDIT = 3,
+ MLC_CREDIT_REQUEST = 4,
+ MLC_DEBIT = 5,
+ MLC_DEBIT_REQUEST = 6,
+ MLC_CONFIG_SOCKET = 7,
+ MLC_EXIT = 8,
+ MLC_ERROR = 0x7f
+};
+
+typedef struct
+{
+ unsigned char hsid; /* host socket id */
+ unsigned char psid; /* peripheral socket id */
+ unsigned short length; /* packet length (includes header) */
+ unsigned char credit; /* data packet credit, reserved if command */
+ unsigned char status; /* upper layer status */
+} __attribute__((packed)) MLCHeader;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char rev;
+} __attribute__((packed)) MLCInit;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned char rev;
+} __attribute__((packed)) MLCInitReply;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+} __attribute__((packed)) MLCExit;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char result;
+} __attribute__((packed)) MLCExitReply;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char socket; /* socket id */
+ unsigned short h2psize; /* host-to-peripheral packet size */
+ unsigned short p2hsize; /* peripheral-to-host packet size */
+ unsigned char status; /* status level */
+} __attribute__((packed)) MLCConfigSocket;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned short h2psize; /* host-to-peripheral packet size */
+ unsigned short p2hsize; /* peripheral-to-host packet size */
+ unsigned char status; /* status level */
+} __attribute__((packed)) MLCConfigSocketReply;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char hsocket; /* host socket id */
+ unsigned char psocket; /* peripheral socket id */
+ unsigned short credit;
+} __attribute__((packed)) MLCOpenChannel;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char result;
+ unsigned short credit;
+} __attribute__((packed)) MLCOpenChannelReply;
+
+typedef struct
+{
+ MLCHeader h;
+ unsigned char cmd;
+ unsigned char hsocket; /* host socket id */
+ unsigned char psocket; /* peripheral socket id */
+} __attribute__((packed)) MLCCloseChannel;
+
+typedef MLCExitReply MLCCloseChannelReply;
+typedef MLCExitReply MLCReply;
+typedef MLCExit MLCCmd;
+typedef MLCOpenChannel MLCCredit;
+typedef MLCExitReply MLCCreditReply;
+typedef MLCOpenChannel MLCCreditRequest;
+typedef MLCOpenChannelReply MLCCreditRequestReply;
+typedef MLCExitReply MLCError;
+
+struct _mud_device;
+struct _mud_channel;
+
+int __attribute__ ((visibility ("hidden"))) cut_buf(struct _mud_channel *pc, char *buf, int size);
+int __attribute__ ((visibility ("hidden"))) MlcInit(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) MlcExit(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) MlcConfigSocket(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) MlcForwardData(struct _mud_channel *pc, int fd, const void *buf, int size, int usec_timeout);
+int __attribute__ ((visibility ("hidden"))) MlcReverseData(struct _mud_channel *pc, int fd, void *buf, int length, int usec_timeout);
+int __attribute__ ((visibility ("hidden"))) MlcOpenChannel(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) MlcCloseChannel(struct _mud_channel *pc, int fd);
+int __attribute__ ((visibility ("hidden"))) MlcCredit(struct _mud_channel *pc, int fd, unsigned short credit);
+int __attribute__ ((visibility ("hidden"))) MlcCreditRequest(struct _mud_channel *pc, int fd, unsigned short credit);
+int __attribute__ ((visibility ("hidden"))) MlcReverseCmd(struct _mud_channel *pc, int fd);
+
+#endif // _MLC_H
+
diff --git a/io/hpmud/model.c b/io/hpmud/model.c
new file mode 100644
index 0000000..3678af5
--- /dev/null
+++ b/io/hpmud/model.c
@@ -0,0 +1,633 @@
+/*****************************************************************************\
+
+ model.c - model parser for hplip devices
+
+ (c) 2006-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include "list.h"
+#include "hpmud.h"
+#include "hpmudi.h"
+
+#define SECTION_SIZE 4096 /* Rough estimate of key/value section size in bytes. */
+
+typedef struct
+{
+ char *name;
+ char *incFile;
+ int valueSize; /* size of list in bytes */
+ char *value; /* list of key/value pairs */
+ struct list_head list;
+} LabelRecord;
+
+static LabelRecord head; /* list of labels from include files */
+static char homedir[255] = "";
+
+static int GetPair(char *buf, int buf_len, char *key, char *value, char **tail)
+{
+ int i=0, j;
+
+ key[0] = 0;
+ value[0] = 0;
+
+ if (buf[i] == '#')
+ {
+ for (; buf[i] != '\n' && i < buf_len; i++); /* eat comment line */
+ if (buf[i] == '\n')
+ i++; /* bump past '\n' */
+ }
+
+ j = 0;
+ while ((buf[i] != '=') && (i < buf_len) && (j < HPMUD_LINE_SIZE))
+ key[j++] = buf[i++];
+ for (j--; key[j] == ' ' && j > 0; j--); /* eat white space before = */
+ key[++j] = 0;
+
+ if (buf[i] == '=')
+ for (i++; buf[i] == ' ' && i < buf_len; i++); /* eat white space after = */
+
+ j = 0;
+ while ((buf[i] != '\n') && (i < buf_len) && (j < HPMUD_LINE_SIZE))
+ value[j++] = buf[i++];
+ for (j--; value[j] == ' ' && j > 0; j--); /* eat white space before \n */
+ value[++j] = 0;
+
+ if (buf[i] == '\n')
+ i++; /* bump past '\n' */
+
+ if (tail != NULL)
+ *tail = buf + i; /* tail points to next line */
+
+ return i;
+}
+
+static int ReadConfig()
+{
+ char key[HPMUD_LINE_SIZE];
+ char value[HPMUD_LINE_SIZE];
+ char rcbuf[255];
+ char section[32];
+ char *tail;
+ FILE *inFile = NULL;
+ int stat=1;
+
+ homedir[0] = 0;
+
+ if((inFile = fopen(CONFDIR "/hplip.conf", "r")) == NULL)
+ {
+ BUG("unable to open %s: %m\n", CONFDIR "/hplip.conf");
+ goto bugout;
+ }
+
+ section[0] = 0;
+
+ /* Read the config file */
+ while ((fgets(rcbuf, sizeof(rcbuf), inFile) != NULL))
+ {
+ if (rcbuf[0] == '[')
+ {
+ strncpy(section, rcbuf, sizeof(section)); /* found new section */
+ continue;
+ }
+
+ GetPair(rcbuf, strlen(rcbuf), key, value, &tail);
+
+ if ((strncasecmp(section, "[dirs]", 6) == 0) && (strcasecmp(key, "home") == 0))
+ {
+ strncpy(homedir, value, sizeof(homedir));
+ break; /* done */
+ }
+ }
+
+ stat = 0;
+
+bugout:
+ if (inFile != NULL)
+ fclose(inFile);
+
+ return stat;
+}
+
+/* Find last occurance of y in x. */
+static char *strrstr(const char *x, const char *y)
+{
+ char *prev=NULL, *next;
+
+ if (*y == '\0')
+ return strchr(x, '\0');
+
+ while ((next = strstr(x, y)) != NULL)
+ {
+ prev = next;
+ x = next + 1;
+ }
+ return prev;
+}
+
+static int CopyLabel(char *label, char *buf, int bufSize)
+{
+ struct list_head *p;
+ LabelRecord *pl;
+ int i=0, found=0;
+
+ /* Look for label. */
+ list_for_each(p, &head.list)
+ {
+ pl = list_entry(p, LabelRecord, list);
+ if (strcasecmp(pl->name, label) == 0)
+ {
+ found = 1; /* found label */
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ BUG("error undefined label %s\n", label);
+ goto bugout;
+ }
+
+ if (pl->valueSize > bufSize)
+ {
+ BUG("error label %s size=%d buf=%d\n", label, pl->valueSize, bufSize);
+ goto bugout;
+ }
+
+ memcpy(buf, pl->value, pl->valueSize);
+ i=pl->valueSize;
+
+bugout:
+ return i;
+}
+
+static int ResolveAttributes(FILE *fp, char *attr, int attrSize)
+{
+ char label[128];
+ int i=0, j, ch;
+
+ /* Process each key/value line. */
+ ch = fgetc(fp);
+ while (ch != EOF)
+ {
+ if (ch == '[')
+ {
+ ungetc(ch, fp); /* found new section, done with current section */
+ break;
+ }
+
+ if (ch == '#' || ch == ' ')
+ {
+ while ((ch = fgetc(fp)) != '\n' && ch != EOF); /* skip line */
+ }
+ else if (ch == '\n')
+ {
+ /* skip blank line */
+ }
+ else if (ch == '%')
+ {
+ j=0;
+ while ((ch = fgetc(fp)) != '\n' && ch != EOF) /* get label */
+ {
+ if (j < sizeof(label)-1)
+ label[j++] = ch;
+ }
+ label[j-1] = 0;
+ i += CopyLabel(label, attr+i, attrSize-i);
+ }
+ else
+ {
+ if (i < attrSize-1)
+ attr[i++] = ch;
+ while ((ch = fgetc(fp)) != '\n' && ch != EOF) /* get key/value line */
+ {
+ if (i < attrSize-1)
+ attr[i++] = ch;
+ }
+ if (i < attrSize-1)
+ attr[i++] = '\n';
+ }
+
+ if (ch == '\n')
+ ch = fgetc(fp); /* bump to next line */
+ continue;
+ }
+
+ attr[i] = 0; /* terminate string */
+
+ return i;
+}
+static int RegisterLabel(FILE *fp, char *incFile, char *label)
+{
+ struct list_head *p;
+ LabelRecord *pl;
+ char buf[SECTION_SIZE];
+ int i=0, stat=1, ch;
+
+ /* Look for duplicate label. */
+ list_for_each(p, &head.list)
+ {
+ pl = list_entry(p, LabelRecord, list);
+ if (strcasecmp(pl->name, label) == 0)
+ {
+ BUG("error duplicate label %s\n", label);
+ goto bugout;
+ }
+ }
+
+ if ((pl = (LabelRecord *)malloc(sizeof(LabelRecord))) == NULL)
+ {
+ BUG("unable to creat label record: %m\n");
+ goto bugout;
+ }
+
+ pl->incFile = strdup(incFile);
+ pl->name = strdup(label);
+
+ /* Process each key/value line. */
+ ch = fgetc(fp);
+ while (ch != EOF)
+ {
+ if (ch == '[')
+ {
+ ungetc(ch, fp); /* found new section, done with label */
+ break;
+ }
+
+ if (ch == '#' || ch == ' ')
+ {
+ while ((ch = fgetc(fp)) != '\n' && ch != EOF); /* skip line */
+ }
+ else if (ch == '\n')
+ {
+ /* skip blank line */
+ }
+ else
+ {
+ if (i < SECTION_SIZE-1)
+ buf[i++] = ch;
+ while ((ch = fgetc(fp)) != '\n' && ch != EOF) /* get key/value line */
+ {
+ if (i < SECTION_SIZE-1)
+ buf[i++] = ch;
+ }
+ if (i < SECTION_SIZE-1)
+ buf[i++] = '\n';
+ }
+
+ if (ch == '\n')
+ ch = fgetc(fp); /* bump to next line */
+ continue;
+ }
+
+ buf[i] = 0; /* terminate string */
+
+ pl->value = strdup(buf);
+ pl->valueSize = i; /* size does not include zero termination */
+
+ list_add(&(pl->list), &(head.list));
+ stat = 0;
+
+bugout:
+
+ return stat;
+}
+
+static int UnRegisterLabel(LabelRecord *pl)
+{
+ if (pl->incFile)
+ free(pl->incFile);
+ if (pl->name)
+ free(pl->name);
+ if (pl->value)
+ free(pl->value);
+ list_del(&(pl->list));
+ free(pl);
+ return 0;
+}
+
+static int DelList()
+{
+ struct list_head *p, *n;
+ LabelRecord *pl;
+
+ /* Remove each label. */
+ list_for_each_safe(p, n, &head.list)
+ {
+ pl = list_entry(p, LabelRecord, list);
+ UnRegisterLabel(pl);
+ }
+ return 0;
+}
+
+/* Parse *.inc file. */
+static int ParseInc(char *incFile)
+{
+ FILE *fp=NULL;
+ struct list_head *p;
+ LabelRecord *pl;
+ char rcbuf[255];
+ char section[128];
+ int stat=1, n;
+
+ /* Look for duplicate include file. */
+ list_for_each(p, &head.list)
+ {
+ pl = list_entry(p, LabelRecord, list);
+ if (strcmp(pl->incFile, incFile) == 0)
+ {
+ BUG("error duplicate include file %s\n", incFile);
+ goto bugout;
+ }
+ }
+
+ if ((fp = fopen(incFile, "r")) == NULL)
+ {
+ BUG("open %s failed: %m\n", incFile);
+ goto bugout;
+ }
+
+ section[0] = 0;
+
+ /* Read the *.inc file, check each line for new label. */
+ while ((fgets(rcbuf, sizeof(rcbuf), fp) != NULL))
+ {
+ if (rcbuf[0] == '[')
+ {
+ strncpy(section, rcbuf+1, sizeof(section)); /* found new section */
+ n = strlen(section);
+ section[n-2]=0; /* remove ']' and CR */
+ RegisterLabel(fp, incFile, section);
+ }
+ }
+
+ stat = 0;
+
+bugout:
+ if (fp)
+ fclose(fp);
+ return stat;
+}
+
+/* Parse *.dat file. */
+static int ParseFile(char *datFile, char *model, char *attr, int attrSize, int *bytes_read)
+{
+ FILE *fp;
+ char rcbuf[255];
+ char section[128];
+ char file[128];
+ int found=0, n;
+
+ if ((fp = fopen(datFile, "r")) == NULL)
+ goto bugout;
+
+ section[0] = 0;
+
+ /* Read the *.dat file, check each line for model match. */
+ while ((fgets(rcbuf, sizeof(rcbuf), fp) != NULL))
+ {
+ if (rcbuf[0] == '[')
+ {
+ strncpy(section, rcbuf+1, sizeof(section)); /* found new section */
+ n = strlen(section);
+ section[n-2]=0; /* remove ']' and CR */
+ if (strcasecmp(model, section) == 0)
+ {
+ /* Found model match. */
+ *bytes_read = ResolveAttributes(fp, attr, attrSize);
+ found = 1;
+ break;
+ }
+ }
+ else if (strncmp(rcbuf, "%include", 8) == 0)
+ {
+ strncpy(file, datFile, sizeof(file)); /* get dirname from *.dat file */
+ n = strrstr(file, "/") - file + 1;
+ strncpy(file+n, rcbuf+9, sizeof(file)-n); /* concatenate include filename to dirname */
+ n = strlen(file);
+ file[n-1]=0; /* remove CR */
+ ParseInc(file);
+ }
+ }
+
+bugout:
+ if (fp)
+ fclose(fp);
+
+ return found;
+}
+
+/* Parse and convert all known key value pairs in buffer. Do sanity check on values. */
+static int parse_key_value_pair(char *buf, int len, struct hpmud_model_attributes *ma)
+{
+ char key[HPMUD_LINE_SIZE];
+ char value[HPMUD_LINE_SIZE];
+ char *tail, *tail2;
+ int i=0, ret=HPMUD_R_OK;
+
+ ma->prt_mode = HPMUD_RAW_MODE;
+ ma->mfp_mode = HPMUD_DOT4_MODE;
+ ma->scantype = 0;
+ ma->statustype = HPMUD_STATUSTYPE_SFIELD;
+ ma->support = HPMUD_SUPPORT_TYPE_NONE;
+
+ if (buf == NULL)
+ return HPMUD_R_OK; /* initialize ma */
+
+ tail = buf;
+
+ while (i < len)
+ {
+ i += GetPair(tail, len-i, key, value, &tail);
+
+ if (strcasecmp(key, "io-mode") == 0)
+ {
+ ma->prt_mode = strtol(value, &tail2, 10); /* uni | raw | mlc */
+ }
+ else if (strcasecmp(key, "io-mfp-mode") == 0)
+ {
+ ma->mfp_mode = strtol(value, &tail2, 10); /* mfc | dot4 */
+ }
+ else if(strcasecmp(key, "scan-type") == 0)
+ {
+ ma->scantype = strtol(value, &tail2, 10); /*SCL, PML, SOAP, MARVELL, LEDM*/
+ }
+ else if(strcasecmp(key, "scan-src") == 0)
+ {
+ ma->scansrc = strtol(value, &tail2, 10); /*Flatbed, ADF, Camera or combination of these*/
+ }
+ else if(strcasecmp(key, "status-type") == 0)
+ {
+ ma->statustype = strtol(value, &tail2, 10);
+ }
+ else if(strcasecmp(key, "support-type") == 0)
+ {
+ ma->support = strtol(value, &tail2, 10);
+ }
+ else if(strcasecmp(key, "plugin") == 0)
+ {
+ ma->plugin = strtol(value, &tail2, 10);
+ }
+ else
+ {
+ /* Unknown keys are ignored (R_AOK). */
+ }
+ } // end while (i < len)
+
+ return ret;
+}
+
+/* Request device model attributes for URI. Return all attributes. */
+enum HPMUD_RESULT hpmud_get_model_attributes(char *uri, char *attr, int attrSize, int *bytes_read)
+{
+ char sz[256];
+ char model[256];
+ int found;
+ enum HPMUD_RESULT stat = HPMUD_R_DATFILE_ERROR;
+
+ memset(attr, 0, attrSize);
+
+ INIT_LIST_HEAD(&head.list);
+
+ if (homedir[0] == 0)
+ ReadConfig();
+
+ hpmud_get_uri_model(uri, model, sizeof(model));
+
+ /* Search /data/models.dat file for specified model. */
+ snprintf(sz, sizeof(sz), "%s/data/models/models.dat", homedir);
+ found = ParseFile(sz, model, attr, attrSize, bytes_read); /* save any labels in *.inc files */
+
+ if (!found)
+ {
+ BUG("no %s attributes found in %s\n", model, sz);
+
+ DelList(); /* Unregister all labels. */
+
+ /* Search /data/models/unreleased/unreleased.dat file for specified model. */
+ snprintf(sz, sizeof(sz), "%s/data/models/unreleased/unreleased.dat", homedir);
+ found = ParseFile(sz, model, attr, attrSize, bytes_read); /* save any *.inc files */
+ }
+
+ if (!found)
+ {
+ BUG("no %s attributes found in %s\n", model, sz);
+ goto bugout;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ DelList(); /* Unregister all labels. */
+ return stat;
+}
+
+/* Request device model attributes for URI. Return filled in hpmud_model_attributes structure. */
+enum HPMUD_RESULT hpmud_query_model(char *uri, struct hpmud_model_attributes *ma)
+{
+ char buf[SECTION_SIZE];
+ int len;
+ enum HPMUD_RESULT stat = HPMUD_R_DATFILE_ERROR;
+
+ parse_key_value_pair(NULL, 0, ma); /* set ma defaults */
+
+ if (hpmud_get_model_attributes(uri, buf, sizeof(buf), &len) != 0)
+ goto bugout; /* model not found, return ma defaults */
+
+ parse_key_value_pair(buf, len, ma);
+
+ stat=HPMUD_R_OK;
+
+bugout:
+
+ return stat;
+}
+
+/* Get value for specified section and key from hplip.conf. */
+enum HPMUD_RESULT hpmud_get_conf(const char *section, const char *key, char *value, int value_size)
+{
+ return hpmud_get_key_value(CONFDIR "/hplip.conf", section, key, value, value_size);
+}
+
+/* Get value for specified section and key from specified file. */
+enum HPMUD_RESULT hpmud_get_key_value(const char *file, const char *section, const char *key, char *value, int value_size)
+{
+ char new_key[HPMUD_LINE_SIZE];
+ char new_value[HPMUD_LINE_SIZE];
+ char rcbuf[255];
+ char new_section[32];
+ char *tail;
+ FILE *inFile;
+ enum HPMUD_RESULT stat = HPMUD_R_DATFILE_ERROR;
+ int i,j;
+
+ if((inFile = fopen(file, "r")) == NULL)
+ {
+ BUG("unable to open %s: %m\n", file);
+ goto bugout;
+ }
+
+ new_section[0] = 0;
+
+ /* Read the config file */
+ while ((fgets(rcbuf, sizeof(rcbuf), inFile) != NULL))
+ {
+ if (rcbuf[0] == '[')
+ {
+ i = j = 0;
+ while ((rcbuf[i] != ']') && (j < (sizeof(new_section)-2)))
+ new_section[j++] = rcbuf[i++];
+ new_section[j++] = rcbuf[i++]; /* ']' */
+ new_section[j] = 0; /* zero terminate */
+ continue;
+ }
+
+ GetPair(rcbuf, strlen(rcbuf), new_key, new_value, &tail);
+
+ if ((strcasecmp(new_section, section) == 0) && (strcasecmp(new_key, key) == 0))
+ {
+ strncpy(value, new_value, value_size);
+ stat = HPMUD_R_OK;
+ break; /* done */
+ }
+ }
+
+ if (stat != HPMUD_R_OK)
+ BUG("unable to find %s %s in %s\n", section, key, file);
+
+bugout:
+ if (inFile != NULL)
+ fclose(inFile);
+
+ return stat;
+}
+
diff --git a/io/hpmud/musb.c b/io/hpmud/musb.c
new file mode 100644
index 0000000..1649297
--- /dev/null
+++ b/io/hpmud/musb.c
@@ -0,0 +1,2197 @@
+/*****************************************************************************\
+
+ musb.c - USB support for multi-point transport driver
+
+ (c) 2010 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Client/Server generic message format (see messaging-protocol.doc):
+
+ Author: Naga Samrat Chowdary Narla, Sarbeswar Meher
+\*****************************************************************************/
+
+#include "hpmud.h"
+#include "hpmudi.h"
+
+mud_device_vf __attribute__ ((visibility ("hidden"))) musb_mud_device_vf =
+{
+ .read = musb_read,
+ .write = musb_write,
+ .open = musb_open,
+ .close = musb_close,
+ .get_device_id = musb_get_device_id,
+ .get_device_status = musb_get_device_status,
+ .channel_open = musb_channel_open,
+ .channel_close = musb_channel_close,
+ .channel_write = musb_channel_write,
+ .channel_read = musb_channel_read
+};
+
+static mud_channel_vf musb_raw_channel_vf =
+{
+ .open = musb_raw_channel_open,
+ .close = musb_raw_channel_close,
+ .channel_write = musb_raw_channel_write,
+ .channel_read = musb_raw_channel_read
+};
+
+static mud_channel_vf musb_comp_channel_vf =
+{
+ .open = musb_comp_channel_open,
+ .close = musb_raw_channel_close,
+ .channel_write = musb_raw_channel_write,
+ .channel_read = musb_raw_channel_read
+};
+
+static mud_channel_vf musb_mlc_channel_vf =
+{
+ .open = musb_mlc_channel_open,
+ .close = musb_mlc_channel_close,
+ .channel_write = musb_mlc_channel_write,
+ .channel_read = musb_mlc_channel_read
+};
+
+static mud_channel_vf musb_dot4_channel_vf =
+{
+ .open = musb_dot4_channel_open,
+ .close = musb_dot4_channel_close,
+ .channel_write = musb_dot4_channel_write,
+ .channel_read = musb_dot4_channel_read
+};
+
+/*
+ * The folloing fd arrays must match "enum FD_ID" definition.
+ */
+
+static char *fd_name[MAX_FD] =
+{
+ "na",
+ "7/1/2",
+ "7/1/3",
+ "ff/1/1",
+ "ff/2/1",
+ "ff/3/1",
+ "ff/ff/ff",
+ "ff/d4/0",
+ "ff/4/1",
+ "ff/1/0",
+ "ff/cc/0",
+ "ff/2/10",
+};
+
+static int fd_class[MAX_FD] =
+{
+ 0,0x7,0x7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+};
+
+static int fd_subclass[MAX_FD] =
+{
+ 0,0x1,0x1,0x1,0x2,0x3,0xff,0xd4,0x4,0x1,0xcc,0x2,
+};
+
+static int fd_protocol[MAX_FD] =
+{
+ 0,0x2,0x3,0x1,0x1,0x1,0xff,0,0x1,0,0,0x10,
+};
+
+static const unsigned char venice_power_on[] = {0x1b, '%','P','u','i','f','p','.','p','o','w','e','r',' ','1',';',
+ 'u','d','w','.','q','u','i','t',';',0x1b,'%','-','1','2','3','4','5','X' };
+
+static struct usb_device *libusb_device; /* libusb device referenced by URI */
+//static int open_fd; /* 7/1/2 file descriptor, used by deviceid and status */
+static file_descriptor fd_table[MAX_FD]; /* usb file descriptors */
+
+/* This function is similar to usb_get_string_simple, but it handles zero returns. */
+static int get_string_descriptor(usb_dev_handle *dev, int index, char *buf, size_t buflen)
+{
+ char tbuf[255]; /* Some devices choke on size > 255 */
+ int ret, si, di, cnt=5;
+
+ while (cnt--)
+ {
+ ret = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index,
+ 0x409, tbuf, sizeof(tbuf), LIBUSB_CONTROL_REQ_TIMEOUT);
+ if (ret==0)
+ {
+ /* This retry is necessary for lj1000 and lj1005. des 12/12/07 */
+ BUG("get_string_descriptor zero result, retrying...");
+ continue;
+ }
+ break;
+ }
+
+ if (ret < 0)
+ {
+ BUG("unable get_string_descriptor %d: %m\n", ret);
+ return ret;
+ }
+
+ if (tbuf[1] != USB_DT_STRING)
+ {
+ BUG("invalid get_string_descriptor tag act=%d exp=%d\n", tbuf[1], USB_DT_STRING);
+ return -EIO;
+ }
+
+ if (tbuf[0] > ret)
+ {
+ BUG("invalid get_string_descriptor size act=%d exp=%d\n", tbuf[0], ret);
+ return -EFBIG;
+ }
+
+ for (di = 0, si = 2; si < tbuf[0]; si += 2)
+ {
+ if (di >= (buflen - 1))
+ break;
+
+ if (tbuf[si + 1]) /* high byte */
+ buf[di++] = '0';
+ else
+ buf[di++] = tbuf[si];
+ }
+
+ buf[di] = 0;
+
+ return di;
+}
+
+/* Check for USB interface descriptor with specified class. */
+static int is_interface(struct usb_device *dev, int dclass)
+{
+ struct usb_interface_descriptor *pi;
+ int i, j, k;
+
+ for (i=0; i<dev->descriptor.bNumConfigurations; i++)
+ {
+ for (j=0; j<dev->config[i].bNumInterfaces; j++)
+ {
+ for (k=0; k<dev->config[i].interface[j].num_altsetting; k++)
+ {
+ pi = &dev->config[i].interface[j].altsetting[k];
+ if (pi->bInterfaceClass == dclass)
+ {
+ return 1; /* found interface */
+ }
+ }
+ }
+ }
+ return 0; /* no interface found */
+}
+
+/* Write HP vendor-specific ECP channel message. */
+static int write_ecp_channel(file_descriptor *pfd, int value)
+{
+ usb_dev_handle *hd;
+ int interface = pfd->interface;
+ int len, stat=1;
+ char byte;
+
+ if (pfd->hd == NULL)
+ {
+ BUG("invalid write_ecp_channel state\n");
+ goto bugout;
+ }
+
+ hd = pfd->hd;
+
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, /* bmRequestType */
+ USB_REQ_GET_STATUS, /* bRequest */
+ value, /* wValue */
+ interface, /* wIndex */
+ &byte, 1, LIBUSB_CONTROL_REQ_TIMEOUT);
+
+ if (len != 1)
+ {
+ BUG("invalid write_ecp_channel: %m\n");
+ goto bugout;
+ }
+
+ stat = 0;
+
+bugout:
+ return stat;
+}
+
+/* Set Cypress USS-725 Bridge Chip to 1284.4 mode. */
+static int bridge_chip_up(file_descriptor *pfd)
+{
+ usb_dev_handle *hd;
+ int len, stat=1;
+ char buf[9];
+ char nullByte=0;
+
+ if (pfd->hd == NULL)
+ {
+ BUG("invalid bridge_chip_up state\n");
+ goto bugout;
+ }
+
+ hd = pfd->hd;
+
+ memset(buf, 0, sizeof(buf));
+
+ /* Read register values. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ USB_REQ_SET_FEATURE, /* bRequest */
+ 0, /* wValue */
+ 0, /* wIndex */
+ buf, sizeof(buf), LIBUSB_CONTROL_REQ_TIMEOUT);
+ if (len < 0)
+ {
+ BUG("invalid write_bridge_up: %m\n");
+ goto bugout;
+ }
+
+ /* Check for auto ECP mode. */
+ if (buf[ECRR] != 0x43)
+ {
+ /* Place 725 chip in register mode. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x0758, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+ /* Turn off RLE in auto ECP mode. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x0a1d, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+ /* Place 725 chip in auto ECP mode. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x0759, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+ /* Force negotiation. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x0817, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+ /* Read register values. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ USB_REQ_SET_FEATURE, /* bRequest */
+ 0, /* wValue */
+ 0, /* wIndex */
+ buf, sizeof(buf), LIBUSB_CONTROL_REQ_TIMEOUT);
+ if (buf[ECRR] != 0x43)
+ {
+ BUG("invalid auto ecp mode mode=%d\n", buf[ECRR]);
+ }
+ }
+
+ /* Reset to ECP channel 0. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x05ce, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+ musb_write(pfd->fd, &nullByte, 1, HPMUD_EXCEPTION_TIMEOUT);
+
+ /* Switch to ECP channel 77. */
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x05cd, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+
+ stat = 0;
+
+bugout:
+ return stat;
+}
+
+/* Set Cypress USS-725 Bridge Chip to compatibility mode. */
+static int bridge_chip_down(file_descriptor *pfd)
+{
+ usb_dev_handle *hd;
+ int len, stat=1;
+
+ if (pfd->hd == NULL)
+ {
+ BUG("invalid bridge_chip_down state\n");
+ goto bugout;
+ }
+
+ hd = pfd->hd;
+
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, /* bmRequestType */
+ 0x04, /* bRequest */
+ 0x080f, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+ if (len < 0)
+ {
+ BUG("invalid write_bridge_up: %m\n");
+ goto bugout;
+ }
+
+ stat = 0;
+
+bugout:
+ return stat;
+}
+
+/* Write HP vendor-specific Setup command. */
+static int write_phoenix_setup(file_descriptor *pfd)
+{
+ usb_dev_handle *hd;
+ int len, stat=1;
+
+ if (pfd->hd == NULL)
+ {
+ BUG("invalid write_phoenix_setup state\n");
+ goto bugout;
+ }
+
+ hd = pfd->hd;
+
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER, /* bmRequestType */
+ 0x02, /* bRequest */
+ 0, /* wValue */
+ 0, /* wIndex */
+ NULL, 0, LIBUSB_CONTROL_REQ_TIMEOUT);
+
+ if (len < 0)
+ {
+ BUG("invalid write_phoenix_setup: %m\n");
+ goto bugout;
+ }
+
+ stat = 0;
+
+bugout:
+ return stat;
+}
+
+/* Detach any kernel module that may have claimed specified inteface. */
+static int detach(usb_dev_handle *hd, int interface)
+{
+ char driver[32];
+
+ driver[0] = 0;
+
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+ /* If any kernel module (ie:usblp) has claimed this interface, detach it. */
+ usb_get_driver_np(hd, interface, driver, sizeof(driver));
+ if ((driver[0] != 0) && (strcasecmp(driver, "usbfs") != 0))
+ {
+ DBG("removing %s driver interface=%d\n", driver, interface);
+ if (usb_detach_kernel_driver_np(hd, interface) < 0)
+ BUG("could not remove %s driver interface=%d: %m\n", driver, interface);
+ }
+#endif
+
+ return 0;
+}
+
+/* Get interface descriptor for specified xx/xx/xx protocol. */
+static int get_interface(struct usb_device *dev, enum FD_ID index, file_descriptor *pfd)
+{
+ struct usb_interface_descriptor *pi;
+ int i, j, k;
+
+ for (i=0; i<dev->descriptor.bNumConfigurations; i++)
+ {
+ if (dev->config == NULL)
+ goto bugout;
+
+ for (j=0; j<dev->config[i].bNumInterfaces; j++)
+ {
+ if (dev->config[i].interface == NULL)
+ goto bugout;
+
+ for (k=0; k<dev->config[i].interface[j].num_altsetting; k++)
+ {
+ if (dev->config[i].interface[j].altsetting == NULL)
+ goto bugout;
+
+ pi = &dev->config[i].interface[j].altsetting[k];
+ if (pi->bInterfaceClass == fd_class[index] && pi->bInterfaceSubClass == fd_subclass[index] && pi->bInterfaceProtocol == fd_protocol[index])
+ {
+ pfd->config=i; /* found interface */
+ pfd->interface=j;
+ pfd->alt_setting=k;
+ pfd->fd=index;
+ return 0;
+ }
+ }
+ }
+ }
+
+bugout:
+ return 1; /* no interface found */
+}
+
+/* Get out endpoint for specified interface descriptor. */
+static int get_out_ep(struct usb_device *dev, int config, int interface, int altset, int type)
+{
+ struct usb_interface_descriptor *pi;
+ int i;
+
+ if (dev->config == NULL || dev->config[config].interface == NULL || dev->config[config].interface[interface].altsetting == NULL)
+ goto bugout;
+
+ pi = &dev->config[config].interface[interface].altsetting[altset];
+ for (i=0; i<pi->bNumEndpoints; i++)
+ {
+ if (pi->endpoint == NULL)
+ goto bugout;
+ if (pi->endpoint[i].bmAttributes == type && !(pi->endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
+ DBG("get_out_ep(type=%d): out=%d\n", type, pi->endpoint[i].bEndpointAddress);
+ return pi->endpoint[i].bEndpointAddress;
+ }
+ }
+
+bugout:
+ DBG("get_out_ep: ERROR! returning -1\n");
+ return -1; /* no endpoint found */
+}
+
+/* Get in endpoint for specified interface descriptor. */
+static int get_in_ep(struct usb_device *dev, int config, int interface, int altset, int type)
+{
+ struct usb_interface_descriptor *pi;
+ int i;
+
+ if (dev->config == NULL || dev->config[config].interface == NULL || dev->config[config].interface[interface].altsetting == NULL)
+ goto bugout;
+
+ pi = &dev->config[config].interface[interface].altsetting[altset];
+ for (i=0; i<pi->bNumEndpoints; i++)
+ {
+ if (pi->endpoint == NULL)
+ goto bugout;
+ if (pi->endpoint[i].bmAttributes == type && (pi->endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
+ DBG("get_in_ep(type=%d): out=%d\n", type, pi->endpoint[i].bEndpointAddress);
+ return pi->endpoint[i].bEndpointAddress;
+ }
+ }
+
+bugout:
+ DBG("get_in_ep: ERROR! returning -1\n");
+ return -1; /* no endpoint found */
+}
+
+static int claim_interface(struct usb_device *dev, file_descriptor *pfd)
+{
+ int stat=1;
+
+ if (pfd->hd != NULL)
+ return 0; /* interface is already claimed */
+
+ if ((pfd->hd = usb_open(dev)) == NULL)
+ {
+ BUG("invalid usb_open: %m\n");
+ goto bugout;
+ }
+
+ detach(pfd->hd, pfd->interface);
+
+#if 0 /* hp devices only have one configuration, so far ... */
+ if (usb_set_configuration(FD[fd].pHD, dev->config[config].bConfigurationValue))
+ goto bugout;
+#endif
+
+ if (usb_claim_interface(pfd->hd, pfd->interface))
+ {
+ usb_close(pfd->hd);
+ pfd->hd = NULL;
+ DBG("invalid claim_interface %s: %m\n", fd_name[pfd->fd]);
+ goto bugout;
+ }
+
+ if (usb_set_altinterface(pfd->hd, pfd->alt_setting))
+ {
+ usb_release_interface(pfd->hd, pfd->interface);
+ usb_close(pfd->hd);
+ pfd->hd = NULL;
+ BUG("invalid set_altinterface %s altset=%d: %m\n", fd_name[pfd->fd], pfd->alt_setting);
+ goto bugout;
+ }
+
+ pfd->write_active=0;
+ pthread_mutex_init(&pfd->mutex, NULL);
+ pthread_cond_init(&pfd->write_done_cond, NULL);
+
+ DBG("claimed %s interface\n", fd_name[pfd->fd]);
+
+ stat=0;
+
+bugout:
+ return stat;
+}
+
+static int release_interface(file_descriptor *pfd)
+{
+ if (pfd->hd == NULL)
+ return 0;
+
+ if (pfd->write_active)
+ {
+ BUG("aborting outstanding %s write\n", fd_name[pfd->fd]);
+ pthread_cancel(pfd->tid); /* kill outstanding write */
+ pfd->write_active = 0;
+ }
+
+ usb_release_interface(pfd->hd, pfd->interface);
+ usb_close(pfd->hd);
+ pfd->hd = NULL;
+ pthread_mutex_destroy(&pfd->mutex);
+ pthread_cond_destroy(&pfd->write_done_cond);
+
+ DBG("released %s interface\n", fd_name[pfd->fd]);
+
+ return 0;
+}
+
+/* Claim any open interface which is valid for device_id and device status. */
+static int claim_id_interface(struct usb_device *dev)
+{
+ enum FD_ID i;
+
+ for (i=FD_7_1_2; i!=MAX_FD; i++)
+ {
+ if (get_interface(dev, i, &fd_table[i]) == 0)
+ {
+ if (claim_interface(libusb_device, &fd_table[i]))
+ continue; /* interface is busy, try next interface */
+ break; /* done */
+ }
+ }
+
+ return i;
+}
+
+/* See if this usb device and URI match. */
+static int is_uri(struct usb_device *dev, const char *uri)
+{
+ usb_dev_handle *hd=NULL;
+ char sz[128];
+ char uriModel[128];
+ char uriSerial[128];
+ char gen[128];
+ int r, stat=0;
+
+ if ((hd = usb_open(dev)) == NULL)
+ {
+ BUG("invalid usb_open: %m\n");
+ goto bugout;
+ }
+
+ if (dev->descriptor.idVendor != 0x3f0)
+ goto bugout;
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iProduct, sz, sizeof(sz))) < 0)
+ {
+ BUG("invalid product id string ret=%d\n", r);
+ goto bugout;
+ }
+
+ generalize_model(sz, gen, sizeof(gen));
+
+ hpmud_get_uri_model(uri, uriModel, sizeof(uriModel));
+ if (strcasecmp(uriModel, gen) != 0)
+ goto bugout;
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iSerialNumber, sz, sizeof(sz))) < 0)
+ {
+ BUG("invalid serial id string ret=%d\n", r);
+ goto bugout;
+ }
+
+ if (sz[0])
+ generalize_serial(sz, gen, sizeof(gen));
+ else
+ strcpy(gen, "0");
+
+ get_uri_serial(uri, uriSerial, sizeof(uriSerial));
+ if (strcmp(uriSerial, gen) != 0)
+ goto bugout;
+
+ stat = 1; /* found usb device that matches uri */
+
+bugout:
+ if (hd != NULL)
+ usb_close(hd);
+
+ return stat;
+}
+
+/* See if this usb device and serial number match. Return model if match. */
+static int is_serial(struct usb_device *dev, const char *sn, char *model, int model_size)
+{
+ usb_dev_handle *hd=NULL;
+ char sz[128];
+ char gen[128];
+ int r, stat=0;
+
+ if ((hd = usb_open(dev)) == NULL)
+ {
+ BUG("invalid usb_open: %m\n");
+ goto bugout;
+ }
+
+ if (dev->descriptor.idVendor != 0x3f0)
+ goto bugout; /* not a HP product */
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iSerialNumber, sz, sizeof(sz))) < 0)
+ {
+ BUG("invalid serial id string ret=%d\n", r);
+ goto bugout;
+ }
+ if (sz[0])
+ generalize_serial(sz, gen, sizeof(gen));
+ else
+ strcpy(gen, "0");
+
+ if (strncmp(sn, gen, sizeof(gen)) != 0)
+ goto bugout; /* match failed */
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iProduct, sz, sizeof(sz))) < 0)
+ {
+ BUG("invalid product id string ret=%d\n", r);
+ goto bugout;
+ }
+ generalize_model(sz, model, model_size);
+
+ stat = 1; /* found usb device that matches sn */
+
+bugout:
+ if (hd != NULL)
+ usb_close(hd);
+
+ return stat;
+}
+
+static struct usb_device *get_libusb_device(const char *uri)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ for (bus=usb_busses; bus; bus=bus->next)
+ for (dev=bus->devices; dev; dev=dev->next)
+ if (dev->descriptor.idVendor == 0x3f0 && is_interface(dev, 7))
+ if (is_uri(dev, uri))
+ return dev; /* found usb device that matches uri */
+
+ return NULL;
+}
+
+static int device_id(int fd, char *buffer, int size)
+{
+ usb_dev_handle *hd;
+ int config,interface,alt;
+ int len=0, rlen, maxSize;
+
+ hd = fd_table[fd].hd;
+ config = fd_table[fd].config;
+ interface = fd_table[fd].interface;
+ alt = fd_table[fd].alt_setting;
+
+ if (hd == NULL)
+ {
+ BUG("invalid device_id state\n");
+ goto bugout;
+ }
+
+ maxSize = (size > 1024) ? 1024 : size; /* RH8 has a size limit for device id (usb) */
+
+ rlen = usb_control_msg(hd,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, /* bmRequestType */
+ USB_REQ_GET_STATUS, /* bRequest */
+ config, /* wValue */
+ interface, /* wIndex */ /* note firmware does not follow the USB Printer Class specification for wIndex */
+ buffer, maxSize, LIBUSB_CONTROL_REQ_TIMEOUT);
+
+ if (rlen < 0)
+ {
+#if 0 /* Removed this PS A420 hack so a valid error is returned after USB reset. DES 10/1/09 */
+ /* Following retry is necessary for a firmware problem with PS A420 products. DES 4/17/07 */
+ BUG("invalid deviceid wIndex=%x, retrying wIndex=%x: %m\n", interface, interface << 8);
+ rlen = usb_control_msg(hd,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, /* bmRequestType */
+ USB_REQ_GET_STATUS, /* bRequest */
+ config, /* wValue */
+ interface << 8, /* wIndex */
+ buffer, maxSize, LIBUSB_CONTROL_REQ_TIMEOUT);
+ if (rlen < 0)
+ {
+ BUG("invalid deviceid retry ret=%d: %m\n", rlen);
+ goto bugout;
+ }
+#endif
+ BUG("invalid deviceid ret=%d: %m\n", rlen);
+ goto bugout;
+ }
+
+ len = ntohs(*(short *)buffer);
+ if (len > (size-1))
+ len = size-1; /* leave byte for zero termination */
+ if (len > 2)
+ len -= 2;
+ memcpy(buffer, buffer+2, len); /* remove length */
+ buffer[len]=0;
+ DBG("read actual device_id successfully fd=%d len=%d\n", fd, len);
+
+bugout:
+ return len; /* length does not include zero termination */
+}
+
+static int device_status(int fd, unsigned int *status)
+{
+ usb_dev_handle *hd;
+ int interface;
+ int len, stat=1;
+ char byte;
+
+ hd = fd_table[fd].hd;
+ interface = fd_table[fd].interface;
+
+ if (hd == NULL)
+ {
+ BUG("invalid device_status state\n");
+ goto bugout;
+ }
+
+ len = usb_control_msg(hd,
+ USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, /* bmRequestType */
+ USB_REQ_CLEAR_FEATURE, /* bRequest */
+ 0, /* wValue */
+ interface, /* wIndex */
+ &byte, 1, LIBUSB_CONTROL_REQ_TIMEOUT);
+
+ if (len < 0)
+ {
+ BUG("invalid device_status: %m\n");
+ goto bugout;
+ }
+
+ *status = (unsigned int)byte;
+ stat = 0;
+ DBG("read actual device_status successfully fd=%d\n", fd);
+
+bugout:
+ return stat;
+}
+
+/* Get VStatus from S-field. */
+static int sfield_printer_state(const char *id)
+{
+ char *pSf;
+ int vstatus=0, ver;
+
+ if ((pSf = strstr(id, ";S:")) == NULL)
+ {
+ BUG("invalid S-field\n");
+ return vstatus;
+ }
+
+ /* Valid S-field, get version number. */
+ pSf+=3;
+ ver = 0;
+ HEX2INT(*pSf, ver);
+ pSf++;
+ ver = ver << 4;
+ HEX2INT(*pSf, ver);
+ pSf++;
+
+ /* Position pointer to printer state subfield. */
+ switch (ver)
+ {
+ case 0:
+ case 1:
+ case 2:
+ pSf+=12;
+ break;
+ case 3:
+ pSf+=14;
+ break;
+ case 4:
+ pSf+=18;
+ break;
+ default:
+ BUG("unknown S-field version=%d\n", ver);
+ pSf+=12;
+ break;
+ }
+
+ /* Extract VStatus.*/
+ vstatus = 0;
+ HEX2INT(*pSf, vstatus);
+ pSf++;
+ vstatus = vstatus << 4;
+ HEX2INT(*pSf, vstatus);
+
+ return vstatus;
+}
+
+/*
+ * Power up printer if necessary. Most all-in-ones have no power down state (ie: OJ K80), so they are already powered up.
+ * Newer single function printers power-up with the print job. May be called by other mud_device.
+ */
+int __attribute__ ((visibility ("hidden"))) power_up(mud_device *pd, int fd)
+{
+ const char *pSf;
+
+ if ((pSf = strstr(pd->id, "CMD:LDL")) != NULL)
+ return 0; /* crossbow don't do power-up */
+
+ if ((pSf = strstr(pd->id, ";S:")) != NULL)
+ {
+ if (sfield_printer_state(pd->id) != 3)
+ return 0; /* already powered up */
+ }
+ else if ((pSf = strstr(pd->id, "VSTATUS:")) != NULL)
+ {
+ /* DJ895C returns $XB0$XC0 (unknown pens) when powered off. */
+ if (!(strstr(pSf+8, "OFFF") || strstr(pSf+8, "PWDN") || strstr(pSf+8, "$X")))
+ return 0; /* already powered up */
+ }
+ else
+ return 0; /* must be laserjet, don't do power-up */
+
+ (pd->vf.write)(fd, venice_power_on, sizeof(venice_power_on), HPMUD_EXCEPTION_TIMEOUT);
+ sleep(2);
+
+ return 0;
+}
+
+/* Create channel object given the requested socket id and service name. */
+static int new_channel(mud_device *pd, int index, const char *sn)
+{
+ int stat=1;
+
+ /* Check for existing name service already open. */
+ if (pd->channel[index].client_cnt)
+ {
+#if 0
+ if (index == HPMUD_EWS_CHANNEL)
+ {
+ pd->channel[index].client_cnt++; /* allow multiple clients for separate USB interfaces only */
+ stat = 0;
+ DBG("reused %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
+ }
+ else
+#endif
+ 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);
+ goto bugout;
+ }
+
+ if (index == HPMUD_EWS_CHANNEL || index == HPMUD_EWS_LEDM_CHANNEL ||
+ index == HPMUD_SOAPSCAN_CHANNEL || index == HPMUD_SOAPFAX_CHANNEL ||
+ index == HPMUD_MARVELL_SCAN_CHANNEL || index == HPMUD_MARVELL_FAX_CHANNEL ||
+ index == HPMUD_LEDM_SCAN_CHANNEL) {
+ pd->channel[index].vf = musb_comp_channel_vf;
+ }
+ else if (pd->io_mode == HPMUD_RAW_MODE || pd->io_mode == HPMUD_UNI_MODE) {
+ pd->channel[index].vf = musb_raw_channel_vf;
+ }
+ else if (pd->io_mode == HPMUD_MLC_GUSHER_MODE || pd->io_mode == HPMUD_MLC_MISER_MODE) {
+ pd->channel[index].vf = musb_mlc_channel_vf;
+ }
+ else {
+ pd->channel[index].vf = musb_dot4_channel_vf;
+ }
+
+ pd->channel[index].index = index;
+ pd->channel[index].client_cnt = 1;
+ pd->channel[index].sockid = index; /* static socket id is valid for MLC but not 1284.4 */
+ pd->channel[index].pid = getpid();
+ pd->channel[index].dindex = pd->index;
+ pd->channel[index].fd = 0;
+ strcpy(pd->channel[index].sn, sn);
+ pd->channel_cnt++;
+
+ stat = 0;
+ DBG("new %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
+
+bugout:
+ return stat;
+}
+
+/* Remove channel object given the channel decriptor. */
+static int del_channel(mud_device *pd, mud_channel *pc)
+{
+ pc->client_cnt--;
+
+ if (pc->client_cnt <= 0)
+ {
+ pd->channel_cnt--;
+ }
+ DBG("removed %s channel=%d clientCnt=%d channelCnt=%d\n", pc->sn, pc->index, pc->client_cnt, pd->channel_cnt);
+ return 0;
+}
+
+static void write_thread(file_descriptor *pfd)
+{
+ int ep;
+
+ pthread_detach(pthread_self());
+
+ if ((ep = get_out_ep(libusb_device, pfd->config, pfd->interface, pfd->alt_setting, USB_ENDPOINT_TYPE_BULK)) < 0)
+ {
+ BUG("invalid bulk out endpoint\n");
+ goto bugout;
+ }
+
+ /* Wait forever for write to complete (actually 72 hours in ms). */
+ pfd->write_return = usb_bulk_write(pfd->hd, ep, (char *)pfd->write_buf, pfd->write_size, 72*3600*1000);
+
+bugout:
+ pthread_mutex_lock(&pfd->mutex);
+ pfd->write_buf = NULL;
+ pthread_cond_signal(&pfd->write_done_cond); /* signal write is complete */
+ pthread_mutex_unlock(&pfd->mutex);
+
+ return;
+}
+
+/*********************************************************************************************************************************
+ * USB mud_device functions.
+ */
+
+int __attribute__ ((visibility ("hidden"))) musb_write(int fd, const void *buf, int size, int usec)
+{
+ int len=-EIO;
+
+ if (fd_table[fd].hd == NULL)
+ {
+ BUG("invalid musb_write state\n");
+ goto bugout;
+ }
+
+#if 1
+ struct timeval now;
+ struct timespec timeout;
+ int ret;
+ /* If write is still active, probably OOP condition, don't kick off a new write. */
+ if (!fd_table[fd].write_active)
+ {
+ fd_table[fd].write_active = 1;
+ fd_table[fd].write_buf = buf;
+ fd_table[fd].write_size = size;
+
+ /* Create usb_bulk_write thread so we can use our own timeout. Otherwise we cannot handle OOP condition. */
+ if (pthread_create(&fd_table[fd].tid, NULL, (void *(*)(void*))write_thread, (void *)&fd_table[fd]) != 0)
+ {
+ BUG("unable to creat write_thread: %m\n");
+ goto bugout; /* bail */
+ }
+ }
+
+ /* Wait for write to complete. */
+ pthread_mutex_lock(&fd_table[fd].mutex);
+ gettimeofday(&now, NULL);
+ now.tv_usec += usec;
+ now.tv_sec += now.tv_usec / 1000000;
+ now.tv_usec %= 1000000;
+ timeout.tv_sec = now.tv_sec;
+ timeout.tv_nsec = now.tv_usec * 1000;
+ ret = 0;
+ while (fd_table[fd].write_buf && ret != ETIMEDOUT)
+ ret = pthread_cond_timedwait(&fd_table[fd].write_done_cond, &fd_table[fd].mutex, &timeout);
+ pthread_mutex_unlock(&fd_table[fd].mutex);
+
+ if (ret == ETIMEDOUT)
+ {
+ len = -ETIMEDOUT; /* write timeout, let client know */
+ goto bugout;
+ }
+
+ fd_table[fd].write_active = 0;
+
+ len = fd_table[fd].write_return;
+#else
+ int ep;
+ if ((ep = get_out_ep(libusb_device, fd_table[fd].config, fd_table[fd].interface, fd_table[fd].alt_setting, USB_ENDPOINT_TYPE_BULK)) < 0)
+ {
+ BUG("invalid bulk out endpoint\n");
+ goto bugout;
+ }
+
+ len = usb_bulk_write(fd_table[fd].hd, ep, (char *)buf, size, usec);
+#endif
+
+ if (len < 0)
+ {
+ BUG("bulk_write failed buf=%p size=%d len=%d: %m\n", buf, size, len);
+ goto bugout;
+ }
+
+ DBG("write fd=%d len=%d size=%d usec=%d\n", fd, len, size, usec);
+ DBG_DUMP(buf, len < 512 ? len : 512);
+
+bugout:
+ return len;
+}
+
+int __attribute__ ((visibility ("hidden"))) musb_read(int fd, void *buf, int size, int usec)
+{
+ struct timeval t1, t2;
+ int total_usec, tmo_usec=usec;
+ int len=-EIO, ep;
+
+ if (fd_table[fd].hd == NULL)
+ {
+ BUG("invalid musb_read state\n");
+ goto bugout;
+ }
+
+ gettimeofday (&t1, NULL); /* get start time */
+
+ if ((ep = get_in_ep(libusb_device, fd_table[fd].config, fd_table[fd].interface, fd_table[fd].alt_setting, USB_ENDPOINT_TYPE_BULK)) < 0)
+ {
+ BUG("invalid bulk in endpoint\n");
+ goto bugout;
+ }
+
+ while (1)
+ {
+ len = usb_bulk_read(fd_table[fd].hd, ep, (char *)buf, size, tmo_usec/1000);
+
+ if (len == -ETIMEDOUT)
+ goto bugout;
+
+ if (len < 0)
+ {
+ BUG("bulk_read failed: %m\n");
+ goto bugout;
+ }
+
+ if (len == 0)
+ {
+ /* Bulk_read has a timeout, but bulk_read can return zero byte packet(s), so we must use our own timeout here. */
+ gettimeofday(&t2, NULL); /* get current time */
+
+ total_usec = (t2.tv_sec - t1.tv_sec)*1000000;
+ total_usec += (t2.tv_usec > t1.tv_usec) ? t2.tv_usec - t1.tv_usec : t1.tv_usec - t2.tv_usec;
+ if (total_usec > usec)
+ {
+ len = -ETIMEDOUT; /* timeout */
+ goto bugout;
+ }
+ tmo_usec = usec - total_usec; /* decrease timeout */
+ continue;
+ }
+
+ break;
+ }
+
+ DBG("read fd=%d len=%d size=%d usec=%d\n", fd, len, size, usec);
+ DBG_DUMP(buf, len < 32 ? len : 32);
+
+bugout:
+ return len;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_open(mud_device *pd)
+{
+ int len=0, fd=0;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ /* Find usb device for specified uri. */
+ if ((libusb_device = get_libusb_device(pd->uri)) == NULL)
+ {
+ BUG("unable to open %s\n", pd->uri);
+ goto bugout;
+ }
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (pd->id[0] == 0)
+ {
+ /* First client. */
+
+ if ((fd = claim_id_interface(libusb_device)) == MAX_FD)
+ {
+ stat = HPMUD_R_DEVICE_BUSY;
+ goto blackout;
+ }
+
+ len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy and cache it */
+
+ if (len > 0 && is_hp(pd->id))
+ power_up(pd, fd);
+
+ release_interface(&fd_table[fd]);
+
+ if (len == 0)
+ goto blackout;
+
+ pd->open_fd = fd;
+ }
+
+ stat = HPMUD_R_OK;
+
+blackout:
+ pthread_mutex_unlock(&pd->mutex);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_close(mud_device *pd)
+{
+ int i;
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ for (i=1; i<MAX_FD; i++)
+ {
+ if (fd_table[i].hd != NULL)
+ release_interface(&fd_table[i]);
+ }
+
+ pd->id[0] = 0;
+
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_get_device_id(mud_device *pd, char *buf, int size, int *len)
+{
+ int i, fd=FD_NA;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+
+ *len=0;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (pd->io_mode == HPMUD_DOT4_BRIDGE_MODE || pd->io_mode == HPMUD_UNI_MODE)
+ {
+ *len = strlen(pd->id); /* usb/parallel bridge chip, use cached copy */
+ }
+ else
+ {
+ /* See if any interface is already claimed. */
+ for (i=1; i<MAX_FD; i++)
+ {
+ if (fd_table[i].hd != NULL)
+ {
+ fd = i;
+ break;
+ }
+ }
+
+ if (fd == FD_NA)
+ {
+ /* Device not in use. Claim interface, but release for other processes. */
+ if ((fd = claim_id_interface(libusb_device)) != MAX_FD)
+ {
+ *len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy and cache it */
+ release_interface(&fd_table[fd]);
+ }
+ else
+ {
+ /* Device is in use by another process, return cache copy. */
+ *len = strlen(pd->id);
+ }
+ }
+ else
+ {
+ /* Device in use by current process, leave interface up. Other processes are blocked. */
+ *len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy and cache it */
+ }
+ }
+
+ if (*len)
+ {
+ memcpy(buf, pd->id, *len > size ? size : *len);
+ stat = HPMUD_R_OK;
+ }
+
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_get_device_status(mud_device *pd, unsigned int *status)
+{
+ int i, fd=FD_NA;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+ int r=1;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (pd->io_mode == HPMUD_DOT4_BRIDGE_MODE || pd->io_mode == HPMUD_UNI_MODE)
+ *status = NFAULT_BIT; /* usb/parallel bridge chip, fake status */
+ else
+ {
+ /* See if any interface is already claimed. */
+ for (i=1; i<MAX_FD; i++)
+ {
+ if (fd_table[i].hd != NULL)
+ {
+ fd = i;
+ break;
+ }
+ }
+
+ if (fd == FD_NA)
+ {
+ /* Device not in use. Claim interface, but release for other processes. */
+ if ((fd = claim_id_interface(libusb_device)) != MAX_FD)
+ {
+ r = device_status(fd, status);
+ release_interface(&fd_table[fd]);
+ }
+ }
+ else
+ {
+ /* Device in use by current process, leave interface up. Other processes are blocked. */
+ r = device_status(fd, status);
+ }
+ }
+
+ pthread_mutex_unlock(&pd->mutex);
+
+ if (r != 0)
+ goto bugout;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_write(mud_device *pd, mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote)
+{
+ enum HPMUD_RESULT stat;
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.channel_write)(pc, buf, length, sec_timeout, bytes_wrote);
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_read(mud_device *pd, mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read)
+{
+ enum HPMUD_RESULT stat;
+
+ if (pd->io_mode == HPMUD_UNI_MODE)
+ {
+ stat = HPMUD_R_INVALID_STATE;
+ BUG("invalid channel_read io_mode=%d\n", pd->io_mode);
+ goto bugout;
+ }
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.channel_read)(pc, buf, length, sec_timeout, bytes_read);
+ pthread_mutex_unlock(&pd->mutex);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_open(mud_device *pd, const char *sn, HPMUD_CHANNEL *cd)
+{
+ int index;
+ enum HPMUD_RESULT stat;
+
+ /* Check for valid service requests. */
+ if ((stat = service_to_channel(pd, sn, &index)) != HPMUD_R_OK)
+ goto bugout;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (new_channel(pd, index, sn))
+ {
+ stat = HPMUD_R_DEVICE_BUSY;
+ }
+ else
+ {
+ if ((stat = (pd->channel[index].vf.open)(&pd->channel[index])) != HPMUD_R_OK) /* call transport specific open */
+ del_channel(pd, &pd->channel[index]); /* open failed, cleanup */
+ else
+ *cd = index;
+ }
+
+ pthread_mutex_unlock(&pd->mutex);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_close(mud_device *pd, mud_channel *pc)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.close)(pc); /* call trasport specific close */
+ del_channel(pd, pc);
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * USB raw_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_open(mud_channel *pc)
+{
+ int fd = FD_7_1_2;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+
+ get_interface(libusb_device, fd, &fd_table[fd]);
+
+ if (claim_interface(libusb_device, &fd_table[fd]))
+ goto bugout;
+
+ pc->fd = fd;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_close(mud_channel *pc)
+{
+ int fd = pc->fd;
+
+ // For New laserjet devices like Tsunami, end point was getting stall or halted, hence clearing it
+ int ep = -1;
+ if (( ep = get_in_ep(libusb_device, fd_table[fd].config, fd_table[fd].interface, fd_table[fd].alt_setting, USB_ENDPOINT_TYPE_BULK)) >= 0)
+ {
+ usb_clear_halt(fd_table[fd].hd, ep);
+ }
+
+ if (( ep = get_out_ep(libusb_device, fd_table[fd].config, fd_table[fd].interface, fd_table[fd].alt_setting, USB_ENDPOINT_TYPE_BULK)) >= 0)
+ {
+ usb_clear_halt(fd_table[fd].hd, ep);
+ }
+
+ release_interface(&fd_table[fd]);
+
+ pc->fd = 0;
+
+ return HPMUD_R_OK;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_write(mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote)
+{
+ int len, size, total=0;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_wrote=0;
+ size = length;
+
+ while (size > 0)
+ {
+ len = (msp->device[pc->dindex].vf.write)(pc->fd, buf+total, size, sec_timeout*1000000);
+ if (len < 0)
+ {
+ if (len == -ETIMEDOUT)
+ {
+ stat = HPMUD_R_IO_TIMEOUT;
+ if (sec_timeout >= HPMUD_EXCEPTION_SEC_TIMEOUT)
+ BUG("unable to write data %s: %d second io timeout\n", msp->device[pc->dindex].uri, sec_timeout);
+ }
+ else
+ BUG("unable to write data %s: %m\n", msp->device[pc->dindex].uri);
+ goto bugout;
+ }
+ size-=len;
+ total+=len;
+ *bytes_wrote+=len;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/*
+ * Channel_read() tries to read "length" bytes from the peripheral. The returned read count may be zero
+ * (timeout, no data available), less than "length" or equal "length".
+ */
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_read(mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read)
+{
+ int len=0, usec;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_read = 0;
+
+ if (sec_timeout==0)
+ usec = 1000; /* minmum timeout is 1ms for libusb 0.1.12, hangs forever with zero */
+ else
+ usec = sec_timeout*1000000;
+
+ len = (msp->device[pc->dindex].vf.read)(pc->fd, buf, length, usec);
+ if (len < 0)
+ {
+ if (len == -ETIMEDOUT)
+ {
+ stat = HPMUD_R_IO_TIMEOUT;
+ if (sec_timeout >= HPMUD_EXCEPTION_SEC_TIMEOUT)
+ BUG("unable to read data %s: %d second io timeout\n", msp->device[pc->dindex].uri, sec_timeout);
+ }
+ else
+ BUG("unable to read data %s: %m\n", msp->device[pc->dindex].uri);
+ goto bugout;
+ }
+
+ *bytes_read = len;
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * USB comp_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_comp_channel_open(mud_channel *pc)
+{
+ int fd;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+
+ /* Get requested composite interface. */
+ switch (pc->index)
+ {
+ case HPMUD_EWS_CHANNEL:
+ fd = FD_ff_1_1;
+ break;
+ case HPMUD_EWS_LEDM_CHANNEL:
+ fd = FD_ff_4_1;
+ break;
+ case HPMUD_SOAPSCAN_CHANNEL:
+ fd = FD_ff_2_1;
+ break;
+ case HPMUD_SOAPFAX_CHANNEL:
+ fd = FD_ff_3_1;
+ break;
+ case HPMUD_MARVELL_SCAN_CHANNEL:
+ fd = FD_ff_ff_ff;
+ break;
+ case HPMUD_MARVELL_FAX_CHANNEL: //using vendor specific C/S/P codes for fax too
+ fd = FD_ff_1_0;
+ break;
+ case HPMUD_LEDM_SCAN_CHANNEL: //using vendor specific C/S/P codes for fax too
+ fd = FD_ff_cc_0;
+ break;
+ default:
+ stat = HPMUD_R_INVALID_SN;
+ BUG("invalid %s channel=%d\n", pc->sn, pc->index);
+ goto bugout;
+ break;
+ }
+
+ if (get_interface(libusb_device, fd, &fd_table[fd]))
+ {
+ stat = HPMUD_R_INVALID_SN;
+ BUG("invalid %s channel=%d\n", pc->sn, pc->index);
+ goto bugout;
+ }
+
+ if (claim_interface(libusb_device, &fd_table[fd]))
+ goto bugout;
+
+ pc->fd = fd;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * USB mlc_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_open(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum FD_ID fd;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ /* Initialize MLC transport if this is the first MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (get_interface(libusb_device, FD_7_1_3, &fd_table[FD_7_1_3]) == 0 && claim_interface(libusb_device, &fd_table[FD_7_1_3]) == 0)
+ fd = FD_7_1_3; /* mlc, dot4 */
+ else if (get_interface(libusb_device, FD_ff_ff_ff, &fd_table[FD_ff_ff_ff]) == 0 && claim_interface(libusb_device, &fd_table[FD_ff_ff_ff]) == 0)
+ fd = FD_ff_ff_ff; /* mlc, dot4 */
+ else if (get_interface(libusb_device, FD_ff_d4_0, &fd_table[FD_ff_d4_0]) == 0 && claim_interface(libusb_device, &fd_table[FD_ff_d4_0]) == 0)
+ fd = FD_ff_d4_0; /* mlc, dot4 */
+ else if (get_interface(libusb_device, FD_7_1_2, &fd_table[FD_7_1_2]) == 0 && claim_interface(libusb_device, &fd_table[FD_7_1_2]) == 0)
+ fd = FD_7_1_2; /* raw, mlc, dot4 */
+ else
+ {
+ stat = HPMUD_R_DEVICE_BUSY;
+ goto bugout;
+ }
+
+ if (fd == FD_7_1_2)
+ {
+ /* Emulate 7/1/3 on 7/1/2 using vendor-specific ECP channel-77. */
+ if (write_ecp_channel(&fd_table[fd], 77))
+ goto bugout;
+ }
+
+ unsigned int i;
+#if 0
+// Removed reverse drain I seen it hang forever on read, one-time with PSC750 (FC5 64-bit). DES
+ int len;
+ unsigned char buf[255];
+
+ /* Drain any reverse data. */
+ for (i=0,len=1; len > 0 && i < sizeof(buf); i++)
+ len = (pd->vf.read)(fd, buf+i, 1, 0); /* no blocking */
+#endif
+
+ /* MLC initialize */
+ if (MlcInit(pc, fd) != 0)
+ goto bugout;
+
+ /* Reset transport attributes for all channels. */
+ for (i=0; i<HPMUD_CHANNEL_MAX; i++)
+ memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
+
+ pd->mlc_fd = fd;
+ pd->mlc_up=1;
+
+ } /* if (pDev->ChannelCnt==1) */
+
+ if (MlcConfigSocket(pc, pd->mlc_fd))
+ goto bugout;
+
+ if (MlcOpenChannel(pc, pd->mlc_fd))
+ goto bugout;
+
+ pc->rcnt = pc->rindex = 0;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_close(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ unsigned char nullByte=0;
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ if (pd->mlc_up)
+ {
+ if (MlcCloseChannel(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+
+ /* Remove MLC transport if this is the last MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (pd->mlc_up)
+ {
+ if (MlcExit(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+ pd->mlc_up=0;
+
+ if (pd->mlc_fd == FD_7_1_2)
+ {
+ write_ecp_channel(&fd_table[pd->mlc_fd], 78);
+ (pd->vf.write)(pd->mlc_fd, &nullByte, 1, HPMUD_EXCEPTION_TIMEOUT);
+ write_ecp_channel(&fd_table[pd->mlc_fd], 0);
+ }
+
+ release_interface(&fd_table[pd->mlc_fd]);
+
+ /* Delay for back-to-back scanning using scanimage (OJ 7110, OJ d135). */
+ sleep(1);
+ }
+
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_write(mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int ret, len, size, dlen, total=0;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_wrote=0;
+ size = length;
+ dlen = pc->ta.h2psize - sizeof(MLCHeader);
+ while (size > 0)
+ {
+ len = (size > dlen) ? dlen : size;
+
+ if (pc->ta.h2pcredit == 0 && pd->io_mode == HPMUD_MLC_MISER_MODE)
+ {
+ if (MlcCreditRequest(pc, pd->mlc_fd, 1)) /* Miser flow control */
+ {
+ BUG("invalid MlcCreditRequest from peripheral\n");
+ goto bugout;
+ }
+ }
+
+ if (pc->ta.h2pcredit == 0)
+ {
+ ret = MlcReverseCmd(pc, pd->mlc_fd);
+ if (pc->ta.h2pcredit == 0)
+ {
+ if (ret == 0)
+ continue; /* Got a reverse command, but no MlcCredit, try again. */
+
+ if (pd->io_mode != HPMUD_MLC_MISER_MODE)
+ {
+ /* If miser flow control works for this device, set "miser" in models.dat. */
+ BUG("invalid MlcCredit from peripheral, trying miser\n");
+ pd->io_mode = HPMUD_MLC_MISER_MODE;
+ continue;
+ }
+
+ BUG("invalid MlcCredit from peripheral\n");
+ goto bugout;
+ }
+ }
+
+ if (MlcForwardData(pc, pd->mlc_fd, buf+total, len, sec_timeout*1000000))
+ {
+ goto bugout;
+ }
+
+ pc->ta.h2pcredit--;
+ size-=len;
+ total+=len;
+ *bytes_wrote+=len;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/*
+ * Mlc_channel_read() tries to read "length" bytes from the peripheral. ReadData() reads data in packet size chunks.
+ * The returned read count may be zero (timeout, no data available), less than "length" or equal "length".
+ *
+ * Mlc_channel_read() may read more the "length" if the data packet is greater than "length". For this case the
+ * return value will equal "length" and the left over data will be buffered for the next ReadData() call.
+ *
+ * The "timeout" specifies how many seconds to wait for a data packet. Once the read of the data packet has
+ * started the "timeout" is no longer used.
+ *
+ * Note, if a "timeout" occurs one peripheral to host credit is left outstanding. Which means the peripheral
+ * can send unsolicited data later.
+ */
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_read(mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_read=0;
+ if (pc->ta.p2hsize==0)
+ {
+ BUG("invalid channel_read state\n");
+ goto bugout;
+ }
+
+ if (pc->rcnt)
+ {
+ stat=HPMUD_R_OK;
+ *bytes_read = cut_buf(pc, buf, length);
+ goto bugout;
+ }
+
+ if (pc->ta.p2hcredit == 0)
+ {
+ /* Issue enough credit to the peripheral to read one data packet. */
+ if (MlcCredit(pc, pd->mlc_fd, 1))
+ goto bugout;
+ }
+
+ stat=HPMUD_R_OK;
+ pc->rcnt = MlcReverseData(pc, pd->mlc_fd, pc->rbuf, sizeof(pc->rbuf), sec_timeout*1000000);
+ if (pc->rcnt)
+ pc->ta.p2hcredit--; /* one data packet was read, decrement credit count */
+
+ *bytes_read = cut_buf(pc, buf, length);
+
+bugout:
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * USB dot4_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_open(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum FD_ID fd;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ /* Initialize MLC transport if this is the first MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (get_interface(libusb_device, FD_7_1_3, &fd_table[FD_7_1_3]) == 0 && claim_interface(libusb_device, &fd_table[FD_7_1_3]) == 0)
+ fd = FD_7_1_3; /* mlc, dot4 */
+ else if (get_interface(libusb_device, FD_ff_ff_ff, &fd_table[FD_ff_ff_ff]) == 0 && claim_interface(libusb_device, &fd_table[FD_ff_ff_ff]) == 0)
+ fd = FD_ff_ff_ff; /* mlc, dot4 */
+ else if (get_interface(libusb_device, FD_ff_d4_0, &fd_table[FD_ff_d4_0]) == 0 && claim_interface(libusb_device, &fd_table[FD_ff_d4_0]) == 0)
+ fd = FD_ff_d4_0; /* mlc, dot4 */
+ else if (get_interface(libusb_device, FD_7_1_2, &fd_table[FD_7_1_2]) == 0 && claim_interface(libusb_device, &fd_table[FD_7_1_2]) == 0)
+ fd = FD_7_1_2; /* raw, mlc, dot4 */
+ else
+ {
+ stat = HPMUD_R_DEVICE_BUSY;
+ goto bugout;
+ }
+
+ if (fd == FD_7_1_2)
+ {
+ if (pd->io_mode == HPMUD_DOT4_BRIDGE_MODE)
+ {
+ /* Emulate 7/1/3 on 7/1/2 using the bridge chip set (ie: CLJ2500). */
+ if (bridge_chip_up(&fd_table[fd]))
+ goto bugout;
+ }
+ else
+ {
+ /* Emulate 7/1/3 on 7/1/2 using vendor-specific ECP channel-77. */
+ if (write_ecp_channel(&fd_table[fd], 77))
+ goto bugout;
+ }
+ }
+
+ if (pd->io_mode == HPMUD_DOT4_PHOENIX_MODE)
+ write_phoenix_setup(&fd_table[fd]);
+
+ unsigned int i;
+#if 0
+// Removed reverse drain LJ1015 can hang forever on read (FC5 64-bit). DES
+ unsigned char buf[255];
+ int len;
+
+ /* Drain any reverse data. */
+ for (i=0,len=1; len > 0 && i < sizeof(buf); i++)
+ len = (pd->vf.read)(fd, buf+i, 1, 0); /* no blocking */
+#endif
+ /* DOT4 initialize */
+ if (Dot4Init(pc, fd) != 0)
+ goto bugout;
+
+ /* Reset transport attributes for all channels. */
+ for (i=0; i<HPMUD_CHANNEL_MAX; i++)
+ memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
+
+ pd->mlc_fd = fd;
+ pd->mlc_up=1;
+
+ } /* if (pDev->ChannelCnt==1) */
+
+ if (Dot4GetSocket(pc, pd->mlc_fd))
+ goto bugout;
+
+ if (Dot4OpenChannel(pc, pd->mlc_fd))
+ goto bugout;
+
+ if (pd->io_mode == HPMUD_DOT4_PHOENIX_MODE)
+ {
+ /* Issue credit to peripheral. */
+ if (Dot4Credit(pc, pd->mlc_fd, 2))
+ {
+ BUG("invalid Dot4Credit to peripheral\n");
+ goto bugout;
+ }
+ }
+
+ pc->rcnt = pc->rindex = 0;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_close(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ if (pd->mlc_up)
+ {
+ if (Dot4CloseChannel(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+
+ /* Remove 1284.4 transport if this is the last 1284.4 channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (pd->mlc_up)
+ {
+ if (Dot4Exit(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+ pd->mlc_up=0;
+
+ if (pd->mlc_fd == FD_7_1_2)
+ {
+ if (pd->io_mode == HPMUD_DOT4_BRIDGE_MODE)
+ {
+ bridge_chip_down(&fd_table[pd->mlc_fd]);
+ }
+ else
+ {
+ write_ecp_channel(&fd_table[pd->mlc_fd], 78);
+ write_ecp_channel(&fd_table[pd->mlc_fd], 0);
+ }
+ }
+
+ release_interface(&fd_table[pd->mlc_fd]);
+
+ /* Delay for back-to-back scanning using scanimage (OJ 7110, OJ d135). */
+ sleep(1);
+ }
+
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_write(mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ int ret, len, size, dlen, total=0, cnt=0;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_wrote=0;
+ size = length;
+ dlen = pc->ta.h2psize - sizeof(DOT4Header);
+ while (size > 0)
+ {
+ len = (size > dlen) ? dlen : size;
+
+ if (pc->ta.h2pcredit == 0 && pd->io_mode == HPMUD_DOT4_PHOENIX_MODE)
+ {
+ /* Issue credit request to peripheral. */
+ if (Dot4CreditRequest(pc, pd->mlc_fd, 1))
+ {
+ BUG("invalid Dot4CreditRequest from peripheral\n");
+ goto bugout;
+ }
+ if (pc->ta.h2pcredit == 0)
+ {
+ if (cnt++ > HPMUD_EXCEPTION_SEC_TIMEOUT)
+ {
+ BUG("invalid Dot4CreditRequest from peripheral\n");
+ goto bugout;
+ }
+ sleep(1);
+ continue; /* Got a valid Dot4CreditRequest but no credit from peripheral, try again. */
+ }
+ }
+
+ if (pc->ta.h2pcredit == 0)
+ {
+ ret = Dot4ReverseCmd(pc, pd->mlc_fd);
+ if (pc->ta.h2pcredit == 0)
+ {
+ if (ret == 0)
+ continue; /* Got a reverse command, but no Dot4Credit, try again. */
+
+ BUG("invalid Dot4Credit from peripheral\n");
+ goto bugout;
+ }
+ }
+
+ if (Dot4ForwardData(pc, pd->mlc_fd, buf+total, len, sec_timeout*1000000))
+ {
+ goto bugout;
+ }
+
+ pc->ta.h2pcredit--;
+ size-=len;
+ total+=len;
+ *bytes_wrote+=len;
+ cnt=0;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+/*
+ * dot4_read_data() tries to read "length" bytes from the peripheral. Read_data() reads data in packet size chunks.
+ * The returned read count may be zero (timeout, no data available), less than "length" or equal "length".
+ *
+ * dot4_read_data() may read more the "length" if the data packet is greater than "length". For this case the
+ * return value will equal "length" and the left over data will be buffered for the next read_data() call.
+ *
+ * The "timeout" specifies how many seconds to wait for a data packet. Once the read of the data packet has
+ * started the "timeout" is no longer used.
+ *
+ * Note, if a "timeout" occurs one peripheral to host credit is left outstanding. Which means the peripheral
+ * can send unsolicited data later.
+ */
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_read(mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ *bytes_read=0;
+ if (pc->ta.p2hsize==0)
+ {
+ BUG("invalid channel_read state\n");
+ goto bugout;
+ }
+
+ if (pc->rcnt)
+ {
+ stat=HPMUD_R_OK;
+ *bytes_read = cut_buf(pc, buf, length);
+ goto bugout;
+ }
+
+ if (pc->ta.p2hcredit == 0)
+ {
+ /* Issue enough credit to the peripheral to read one data packet. */
+ if (Dot4Credit(pc, pd->mlc_fd, 1))
+ goto bugout;
+ }
+
+ stat=HPMUD_R_OK;
+ pc->rcnt = Dot4ReverseData(pc, pd->mlc_fd, pc->rbuf, sizeof(pc->rbuf), sec_timeout*1000000);
+ if (pc->rcnt)
+ pc->ta.p2hcredit--; /* one data packet was read, decrement credit count */
+
+ *bytes_read = cut_buf(pc, buf, length);
+
+bugout:
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * USB probe devices, walk the USB bus(s) looking for HP products.
+ */
+
+int __attribute__ ((visibility ("hidden"))) musb_probe_devices(char *lst, int lst_size, int *cnt)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+ usb_dev_handle *hd;
+ struct hpmud_model_attributes ma;
+ char rmodel[128];
+ char rserial[128];
+ char model[128];
+ char serial[128];
+ char mfg[128];
+ char sz[HPMUD_LINE_SIZE];
+ int r, size=0;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus=usb_busses; bus; bus=bus->next)
+ {
+ for (dev=bus->devices; dev; dev=dev->next)
+ {
+
+ model[0] = serial[0] = rmodel[0] = rserial[0] = sz[0] = mfg[0] = 0;
+
+ if (dev->descriptor.idVendor == 0x3f0 && is_interface(dev, 7))
+ {
+ if((hd = usb_open(dev)) == NULL)
+ {
+ BUG("Invalid usb_open: %m\n");
+ continue;
+ }
+ /* Found hp device. */
+ if ((r=get_string_descriptor(hd, dev->descriptor.iProduct, rmodel, sizeof(rmodel))) < 0)
+ BUG("invalid product id string ret=%d\n", r);
+ else
+ generalize_model(rmodel, model, sizeof(model));
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iSerialNumber, rserial, sizeof(rserial))) < 0)
+ BUG("invalid serial id string ret=%d\n", r);
+ else
+ generalize_serial(rserial, serial, sizeof(serial));
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iManufacturer, sz, sizeof(sz))) < 0)
+ BUG("invalid manufacturer string ret=%d\n", r);
+ else
+ generalize_serial(sz, mfg, sizeof(serial));
+
+ if (!serial[0])
+ strcpy(serial, "0"); /* no serial number, make it zero */
+
+ if (model[0])
+ {
+ snprintf(sz, sizeof(sz), "hp:/usb/%s?serial=%s", model, serial);
+
+ /* See if device is supported by hplip. */
+ hpmud_query_model(sz, &ma);
+ if (ma.support != HPMUD_SUPPORT_TYPE_HPLIP)
+ {
+ BUG("ignoring %s support=%d\n", sz, ma.support);
+ continue; /* ignor, not supported */
+ }
+
+ /*
+ * For Cups 1.2 we append a dummy deviceid. A valid deviceid would require us to claim the USB interface, thus removing usblp.
+ * This will allow us to do discovery and not disable other CUPS backend(s) who use /dev/usb/lpx instead of libusb.
+ */
+ if (strncasecmp(rmodel, "hp ", 3) == 0)
+ size += snprintf(lst+size, lst_size-size, "direct %s \"HP %s\" \"HP %s USB %s HPLIP\" \"MFG:%s;MDL:%s;CLS:PRINTER;DES:%s;SN:%s;\"\n",
+ sz, &rmodel[3], &rmodel[3], serial, mfg, rmodel, rmodel, rserial);
+ else
+ size += snprintf(lst+size, lst_size-size, "direct %s \"HP %s\" \"HP %s USB %s HPLIP\" \"MFG:%s;MDL:%s;CLS:PRINTER;DES:%s;SN:%s;\"\n",
+ sz, rmodel, rmodel, serial, mfg, rmodel, rmodel, rserial);
+
+ *cnt+=1;
+ }
+ usb_close(hd);
+ }
+ }
+ }
+
+ return size;
+}
+
+enum HPMUD_RESULT hpmud_make_usb_uri(const char *busnum, const char *devnum, char *uri, int uri_size, int *bytes_read)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev, *found_dev=NULL;
+ usb_dev_handle *hd=NULL;
+ char model[128];
+ char serial[128];
+ char sz[256];
+ int r;
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_DEVICE_NODE;
+
+ DBG("[%d] hpmud_make_usb_uri() bus=%s dev=%s\n", getpid(), busnum, devnum);
+
+ *bytes_read=0;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus=usb_busses; bus && !found_dev; bus=bus->next)
+ if (strcmp(bus->dirname, busnum) == 0)
+ for (dev=bus->devices; dev && !found_dev; dev=dev->next)
+ if (strcmp(dev->filename, devnum) == 0)
+ found_dev = dev; /* found usb device that matches bus:device */
+
+ if (found_dev == NULL)
+ {
+ BUG("invalid busnum:devnum %s:%s\n", busnum, devnum);
+ goto bugout;
+ }
+
+ dev = found_dev;
+ if ((hd = usb_open(dev)) == NULL)
+ {
+ BUG("invalid usb_open: %m\n");
+ goto bugout;
+ }
+
+ model[0] = serial[0] = sz[0] = 0;
+
+ if (dev->descriptor.idVendor == 0x3f0)
+ {
+ /* Found hp device. */
+ if ((r=get_string_descriptor(hd, dev->descriptor.iProduct, sz, sizeof(sz))) < 0)
+ BUG("invalid product id string ret=%d\n", r);
+ else
+ generalize_model(sz, model, sizeof(model));
+
+ if ((r=get_string_descriptor(hd, dev->descriptor.iSerialNumber, sz, sizeof(sz))) < 0)
+ BUG("invalid serial id string ret=%d\n", r);
+ else
+ generalize_serial(sz, serial, sizeof(serial));
+
+ if (!serial[0])
+ strcpy(serial, "0"); /* no serial number, make it zero */
+ }
+ else
+ {
+ BUG("invalid vendor id: %d\n", dev->descriptor.idVendor);
+ goto bugout;
+ }
+
+ if (!model[0] || !serial[0])
+ goto bugout;
+
+ *bytes_read = snprintf(uri, uri_size, "hp:/usb/%s?serial=%s", model, serial);
+ stat = HPMUD_R_OK;
+
+bugout:
+ if (hd != NULL)
+ usb_close(hd);
+
+ return stat;
+}
+
+enum HPMUD_RESULT hpmud_make_usb_serial_uri(const char *sn, char *uri, int uri_size, int *bytes_read)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev, *found_dev=NULL;
+ char model[128];
+ enum HPMUD_RESULT stat = HPMUD_R_INVALID_DEVICE_NODE;
+
+ DBG("[%d] hpmud_make_usb_serial_uri() sn=%s\n", getpid(), sn);
+
+ *bytes_read=0;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus=usb_busses; bus && !found_dev; bus=bus->next)
+ for (dev=bus->devices; dev && !found_dev; dev=dev->next)
+ if (is_serial(dev, sn, model, sizeof(model)))
+ found_dev = dev; /* found usb device that matches serial number */
+
+ if (found_dev == NULL)
+ {
+ BUG("invalid sn %s\n", sn);
+ goto bugout;
+ }
+
+ *bytes_read = snprintf(uri, uri_size, "hp:/usb/%s?serial=%s", model, sn);
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
diff --git a/io/hpmud/musb.h b/io/hpmud/musb.h
new file mode 100644
index 0000000..df4a8a6
--- /dev/null
+++ b/io/hpmud/musb.h
@@ -0,0 +1,121 @@
+/*****************************************************************************\
+
+ musb.h - USB support for multi-point transport driver
+
+ (c) 2010 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Author: Naga Samrat Chowdary Narla
+\*****************************************************************************/
+
+#ifndef _MUSB_H
+#define _MUSB_H
+
+#include <usb.h>
+#include "hpmud.h"
+#include "hpmudi.h"
+
+#define LIBUSB_TIMEOUT 30000 /* milliseconds */
+#define LIBUSB_CONTROL_REQ_TIMEOUT 5000
+
+enum FD_ID
+{
+ FD_NA=0,
+ FD_7_1_2, /* bi-di interface */
+ FD_7_1_3, /* 1284.4 interface */
+ FD_ff_1_1, /* HP EWS interface */
+ FD_ff_2_1, /* HP Soap Scan interface */
+ FD_ff_3_1, /* HP Soap Fax interface */
+ FD_ff_ff_ff, /* HP dot4 interface */
+ FD_ff_d4_0, /* HP dot4 interface */
+ FD_ff_4_1, /* orblite scan / rest scan interface */
+ FD_ff_1_0, /* Marvell fax support*/
+ FD_ff_cc_0,
+ FD_ff_2_10,
+ MAX_FD
+};
+
+enum BRIGE_REG_ID
+{
+ ECRR=2,
+ CCTR=3,
+ ATAA=8
+};
+
+/* USB file descriptor, one for each USB protocol. */
+typedef struct
+{
+ usb_dev_handle *hd;
+ enum FD_ID fd;
+ int config;
+ int interface;
+ int alt_setting;
+
+ /* Write thread definitions. */
+ int write_active; /* 0=no, 1=yes */
+ const void *write_buf;
+ int write_size;
+ int write_return; /* return value, normally number bytes written */
+ pthread_t tid;
+ pthread_mutex_t mutex;
+ pthread_cond_t write_done_cond;
+
+ unsigned char ubuf[HPMUD_BUFFER_SIZE]; /* usb read packet buffer */
+ int uindex;
+ int ucnt;
+} file_descriptor;
+
+struct _mud_device;
+struct _mud_channel;
+
+extern struct _mud_device_vf __attribute__ ((visibility ("hidden"))) musb_mud_device_vf;
+
+int __attribute__ ((visibility ("hidden"))) musb_write(int fd, const void *buf, int size, int usec_timout);
+int __attribute__ ((visibility ("hidden"))) musb_read(int fd, void *buf, int size, int usec_timout);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_open(struct _mud_device *pd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_close(struct _mud_device *pd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_get_device_id(struct _mud_device *pd, char *buf, int size, int *len);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_get_device_status(struct _mud_device *pd, unsigned int *status);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_open(struct _mud_device *pd, const char *sn, HPMUD_CHANNEL *cd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_close(struct _mud_device *pd, struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_write(struct _mud_device *pd, struct _mud_channel *pc, const void *buf, int length, int timeout, int *bytes_wrote);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_channel_read(struct _mud_device *pd, struct _mud_channel *pc, void *buf, int length, int timeout, int *bytes_read);
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_close(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_write(struct _mud_channel *pc, const void *buf, int length, int timeout, int *bytes_wrote);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_raw_channel_read(struct _mud_channel *pc, void *buf, int length, int timeout, int *bytes_wrote);
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_comp_channel_open(struct _mud_channel *pc);
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_close(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_write(struct _mud_channel *pc, const void *buf, int length, int timeout, int *bytes_wrote);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_mlc_channel_read(struct _mud_channel *pc, void *buf, int length, int timeout, int *bytes_wrote);
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_close(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_write(struct _mud_channel *pc, const void *buf, int length, int sec_timeout, int *bytes_wrote);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) musb_dot4_channel_read(struct _mud_channel *pc, void *buf, int length, int sec_timeout, int *bytes_read);
+
+int __attribute__ ((visibility ("hidden"))) musb_probe_devices(char *lst, int lst_size, int *cnt);
+int __attribute__ ((visibility ("hidden"))) power_up(struct _mud_device *pd, int fd);
+
+#endif // _MUSB_H
+
diff --git a/io/hpmud/pml.c b/io/hpmud/pml.c
new file mode 100644
index 0000000..a84a9a2
--- /dev/null
+++ b/io/hpmud/pml.c
@@ -0,0 +1,520 @@
+/*****************************************************************************\
+
+ pml.c - get/set pml api for hpmud
+
+ The get/set pml commands are a high level interface to hpmud. This hpmud system
+ interface sits on top of the hpmud core interface. The system interface does
+ not use the hpmud memory map file system.
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "hpmud.h"
+#include "hpmudi.h"
+
+#ifdef HAVE_LIBNETSNMP
+#ifdef HAVE_UCDSNMP
+#include <ucd-snmp/ucd-snmp-config.h>
+#include <ucd-snmp/ucd-snmp-includes.h>
+#else
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#endif
+static const char *SnmpPort[] = { "","public.1","public.2","public.3" };
+#endif
+
+static int PmlOidToHex(const char *szoid, unsigned char *oid, int oidSize)
+{
+ char *tail;
+ int i=0, val;
+
+ if (szoid[0] == 0)
+ goto bugout;
+
+ val = strtol(szoid, &tail, 10);
+
+ while (i < oidSize)
+ {
+ if (val > 128)
+ {
+ BUG("invalid oid size: oid=%s\n", szoid);
+ goto bugout;
+ }
+ oid[i++] = (unsigned char)val;
+
+ if (*tail == 0)
+ break; /* done */
+
+ val = strtol(tail+1, &tail, 10);
+ }
+
+bugout:
+ return i;
+}
+
+/* Convert ascii snmp oid to pml hex oid. */
+static int SnmpToPml(const char *snmp_oid, unsigned char *oid, int oidSize)
+{
+ static const char hp_pml_mib_prefix[] = "1.3.6.1.4.1.11.2.3.9.4.2";
+ static const char standard_printer_mib_prefix[] = "1.3.6.1.2.1.43";
+ static const char host_resource_mib_prefix[] = "1.3.6.1.2.1.25";
+ int len=0;
+
+ if (strncmp(snmp_oid, hp_pml_mib_prefix, sizeof(hp_pml_mib_prefix)-1) == 0)
+ {
+ /* Strip out snmp prefix and convert to hex. */
+ len = 0;
+ len += PmlOidToHex(&snmp_oid[sizeof(hp_pml_mib_prefix)], &oid[0], oidSize);
+ len--; /* remove trailing zero in pml mib */
+ }
+ else if (strncmp(snmp_oid, standard_printer_mib_prefix, sizeof(standard_printer_mib_prefix)-1) == 0)
+ {
+ /* Replace snmp prefix with 2 and convert to hex. */
+ len = 1;
+ oid[0] = 0x2;
+ len += PmlOidToHex(&snmp_oid[sizeof(standard_printer_mib_prefix)], &oid[1], oidSize);
+ }
+ else if (strncmp(snmp_oid, host_resource_mib_prefix, sizeof(host_resource_mib_prefix)-1) == 0)
+ {
+ /* Replace snmp prefix with 3 and convert to hex. */
+ len = 1;
+ oid[0] = 0x3;
+ len += PmlOidToHex(&snmp_oid[sizeof(host_resource_mib_prefix)], &oid[1], oidSize);
+ }
+ else
+ BUG("SnmpToPml failed snmp oid=%s\n", snmp_oid);
+
+ return len;
+}
+
+#ifdef HAVE_LIBNETSNMP
+
+static int SnmpErrorToPml(int snmp_error)
+{
+ int err;
+
+ switch (snmp_error)
+ {
+ case SNMP_ERR_NOERROR:
+ err = PML_EV_OK;
+ break;
+ case SNMP_ERR_TOOBIG:
+ err = PML_EV_ERROR_BUFFER_OVERFLOW;
+ break;
+ case SNMP_ERR_NOSUCHNAME:
+ err = PML_EV_ERROR_UNKNOWN_OBJECT_IDENTIFIER;
+ break;
+ case SNMP_ERR_BADVALUE:
+ err = PML_EV_ERROR_INVALID_OR_UNSUPPORTED_VALUE;
+ break;
+ case SNMP_ERR_READONLY:
+ err = PML_EV_ERROR_OBJECT_DOES_NOT_SUPPORT_REQUESTED_ACTION;
+ break;
+ case SNMP_ERR_GENERR:
+ default:
+ err = PML_EV_ERROR_UNKNOWN_REQUEST;
+ break;
+ }
+
+ return err;
+}
+
+static int SetSnmp(const char *ip, int port, const char *szoid, int type, void *buffer, unsigned int size, int *pml_result, int *result)
+{
+ struct snmp_session session, *ss=NULL;
+ struct snmp_pdu *pdu=NULL;
+ struct snmp_pdu *response=NULL;
+ oid anOID[MAX_OID_LEN];
+ size_t anOID_len = MAX_OID_LEN;
+ unsigned int i, len=0;
+ uint32_t val;
+
+ *result = HPMUD_R_IO_ERROR;
+ *pml_result = PML_EV_ERROR_UNKNOWN_REQUEST;
+
+ init_snmp("snmpapp");
+
+ snmp_sess_init(&session ); /* set up defaults */
+ session.peername = (char *)ip;
+ session.version = SNMP_VERSION_1;
+ session.community = (unsigned char *)SnmpPort[port];
+ session.community_len = strlen((const char *)session.community);
+ ss = snmp_open(&session); /* establish the session */
+ if (ss == NULL)
+ goto bugout;
+
+ pdu = snmp_pdu_create(SNMP_MSG_SET);
+ read_objid(szoid, anOID, &anOID_len);
+
+ switch (type)
+ {
+ case PML_DT_ENUMERATION:
+ case PML_DT_SIGNED_INTEGER:
+ /* Convert PML big-endian to SNMP little-endian byte stream. */
+ for(i=0, val=0; i<size && i<sizeof(val); i++)
+ val = ((val << 8) | ((unsigned char *)buffer)[i]);
+ snmp_pdu_add_variable(pdu, anOID, anOID_len, ASN_INTEGER, (unsigned char *)&val, sizeof(val));
+ break;
+ case PML_DT_REAL:
+ case PML_DT_STRING:
+ case PML_DT_BINARY:
+ case PML_DT_NULL_VALUE:
+ case PML_DT_COLLECTION:
+ default:
+ snmp_pdu_add_variable(pdu, anOID, anOID_len, ASN_OCTET_STR, buffer, size);
+ break;
+ }
+
+
+ /* Send the request and get response. */
+ if (snmp_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ goto bugout;
+
+ if (response->errstat == SNMP_ERR_NOERROR)
+ {
+ len = size;
+ }
+
+ *pml_result = SnmpErrorToPml(response->errstat);
+ *result = HPMUD_R_OK;
+
+bugout:
+ if (response != NULL)
+ snmp_free_pdu(response);
+ if (ss != NULL)
+ snmp_close(ss);
+ return len;
+}
+
+int __attribute__ ((visibility ("hidden"))) GetSnmp(const char *ip, int port, const char *szoid, void *buffer, unsigned int size, int *type, int *pml_result, int *result)
+{
+ struct snmp_session session, *ss=NULL;
+ struct snmp_pdu *pdu=NULL;
+ struct snmp_pdu *response=NULL;
+ unsigned int i, len=0;
+ oid anOID[MAX_OID_LEN];
+ size_t anOID_len = MAX_OID_LEN;
+ struct variable_list *vars;
+ uint32_t val;
+ unsigned char tmp[sizeof(uint32_t)];
+
+ *result = HPMUD_R_IO_ERROR;
+ *type = PML_DT_NULL_VALUE;
+ *pml_result = PML_EV_ERROR_UNKNOWN_REQUEST;
+
+ init_snmp("snmpapp");
+
+ snmp_sess_init(&session ); /* set up defaults */
+ session.peername = (char *)ip;
+ session.version = SNMP_VERSION_1;
+ session.community = (unsigned char *)SnmpPort[port];
+ session.community_len = strlen((const char *)session.community);
+ session.retries = 2;
+ session.timeout = 1000000; /* 1 second */
+ ss = snmp_open(&session); /* establish the session */
+ if (ss == NULL)
+ goto bugout;
+
+ pdu = snmp_pdu_create(SNMP_MSG_GET);
+ read_objid(szoid, anOID, &anOID_len);
+ snmp_add_null_var(pdu, anOID, anOID_len);
+
+ /* Send the request and get response. */
+ if (snmp_synch_response(ss, pdu, &response) != STAT_SUCCESS)
+ goto bugout;
+
+ if (response->errstat == SNMP_ERR_NOERROR)
+ {
+ vars = response->variables;
+ switch (vars->type)
+ {
+ case ASN_INTEGER:
+ *type = PML_DT_SIGNED_INTEGER;
+
+ /* Convert SNMP little-endian to PML big-endian byte stream. */
+ len = (sizeof(uint32_t) < size) ? sizeof(uint32_t) : size;
+ val = *vars->val.integer;
+ for(i=len; i>0; i--)
+ {
+ tmp[i-1] = val & 0xff;
+ val >>= 8;
+ }
+
+ /* Remove any in-significant bytes. */
+ for (; tmp[i]==0 && i<len; i++)
+ ;
+ len -= i;
+
+ memcpy(buffer, tmp+i, len);
+ break;
+ case ASN_NULL:
+ *type = PML_DT_NULL_VALUE;
+ break;
+ case ASN_OCTET_STR:
+ *type = PML_DT_STRING;
+ len = (vars->val_len < size) ? vars->val_len : size;
+ memcpy(buffer, vars->val.string, len);
+ break;
+ default:
+ BUG("unable to GetSnmp: data type=%d\n", vars->type);
+ goto bugout;
+ break;
+ }
+ }
+
+ *pml_result = SnmpErrorToPml(response->errstat);
+ *result = HPMUD_R_OK;
+
+bugout:
+ if (response != NULL)
+ snmp_free_pdu(response);
+ if (ss != NULL)
+ snmp_close(ss);
+ return len;
+}
+
+#else
+
+int __attribute__ ((visibility ("hidden"))) SetSnmp(const char *ip, int port, const char *szoid, int type, void *buffer, unsigned int size, int *pml_result, int *result)
+{
+ BUG("no JetDirect support enabled\n");
+ return 0;
+}
+
+int __attribute__ ((visibility ("hidden"))) GetSnmp(const char *ip, int port, const char *szoid, void *buffer, unsigned int size, int *type, int *pml_result, int *result)
+{
+ BUG("no JetDirect support enabled\n");
+ return 0;
+}
+
+#endif /* HAVE_LIBSNMP */
+
+/* Set a PML object in the hp device. */
+enum HPMUD_RESULT hpmud_set_pml(HPMUD_DEVICE device, HPMUD_CHANNEL channel, const char *snmp_oid, int type, void *data, int data_size, int *pml_result)
+{
+ unsigned char message[HPMUD_BUFFER_SIZE];
+ unsigned char oid[HPMUD_LINE_SIZE];
+ char ip[HPMUD_LINE_SIZE], *psz, *tail;
+ unsigned char *p=message;
+ int len, dLen, result, reply, status, port;
+ struct hpmud_dstat ds;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ DBG("[%d] hpmud_set_pml() dd=%d cd=%d oid=%s type=%d data=%p size=%d\n", getpid(), device, channel, snmp_oid, type, data, data_size);
+
+ if ((result = hpmud_get_dstat(device, &ds)) != HPMUD_R_OK)
+ {
+ stat = result;
+ goto bugout;
+ }
+
+ if (strcasestr(ds.uri, "net/") != NULL)
+ {
+ /* Process pml via snmp. */
+
+ hpmud_get_uri_datalink(ds.uri, ip, sizeof(ip));
+
+ if ((psz = strstr(ds.uri, "port=")) != NULL)
+ port = strtol(psz+5, &tail, 10);
+ else
+ port = 1;
+
+ SetSnmp(ip, port, snmp_oid, type, data, data_size, &status, &result);
+ if (result != HPMUD_R_OK)
+ {
+ BUG("SetPml failed ret=%d\n", result);
+ stat = result;
+ goto bugout;
+ }
+ }
+ else
+ {
+ /* Process pml via local transport. */
+
+ /* Convert snmp ascii oid to pml hex oid. */
+ dLen = SnmpToPml(snmp_oid, oid, sizeof(oid));
+
+ *p++ = PML_SET_REQUEST;
+ *p++ = PML_DT_OBJECT_IDENTIFIER;
+ *p++ = dLen; /* assume oid length is < 10 bits */
+ memcpy(p, oid, dLen);
+ p+=dLen;
+ *p = type;
+ *p |= data_size >> 8; /* assume data length is 10 bits */
+ *(p+1) = data_size & 0xff;
+ p += 2;
+ memcpy(p, data, data_size);
+
+ result = hpmud_write_channel(device, channel, message, dLen+data_size+3+2, HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
+ if (result != HPMUD_R_OK)
+ {
+ BUG("SetPml channel_write failed ret=%d\n", result);
+ stat = result;
+ goto bugout;
+ }
+
+ result = hpmud_read_channel(device, channel, message, sizeof(message), HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
+ if (result != HPMUD_R_OK || len == 0)
+ {
+ BUG("SetPml channel_read failed ret=%d len=%d\n", result, len);
+ goto bugout;
+ }
+
+ p = message;
+ reply = *p++; /* read command reply */
+ status = *p++; /* read execution outcome */
+
+ if (reply != (PML_SET_REQUEST | 0x80) && status & 0x80)
+ {
+ BUG("SetPml failed reply=%x outcome=%x\n", reply, status);
+ DBG_DUMP(p, len-2);
+ goto bugout;
+ }
+ }
+
+ *pml_result = status;
+ stat = HPMUD_R_OK;
+
+ DBG("set_pml result pmlresult=%x\n", status);
+
+bugout:
+ return stat;
+}
+
+/* Get a PML object from the hp device. */
+enum HPMUD_RESULT hpmud_get_pml(HPMUD_DEVICE device, HPMUD_CHANNEL channel, const char *snmp_oid, void *buf, int buf_size, int *bytes_read, int *type, int *pml_result)
+{
+ unsigned char message[HPMUD_BUFFER_SIZE];
+ unsigned char oid[HPMUD_LINE_SIZE];
+ char ip[HPMUD_LINE_SIZE], *psz, *tail;
+ unsigned char *p=message;
+ int len, dLen, result, reply, status, dt, port;
+ struct hpmud_dstat ds;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ DBG("[%d] hpmud_get_pml() dd=%d cd=%d oid=%s data=%p size=%d\n", getpid(), device, channel, snmp_oid, buf, buf_size);
+
+ if ((result = hpmud_get_dstat(device, &ds)) != HPMUD_R_OK)
+ {
+ stat = result;
+ goto bugout;
+ }
+
+ if (strcasestr(ds.uri, "net/") != NULL)
+ {
+ /* Process pml via snmp. */
+
+ hpmud_get_uri_datalink(ds.uri, ip, sizeof(ip));
+
+ if ((psz = strstr(ds.uri, "port=")) != NULL)
+ port = strtol(psz+5, &tail, 10);
+ else
+ port = 1;
+
+ dLen = GetSnmp(ip, port, snmp_oid, message, sizeof(message), &dt, &status, &result);
+ if (result != HPMUD_R_OK)
+ {
+ BUG("GetPml failed ret=%d\n", result);
+ stat = result;
+ goto bugout;
+ }
+ p = message;
+ }
+ else
+ {
+ /* Process pml via local transport. */
+
+ /* Convert snmp ascii oid to pml hex oid. */
+ dLen = SnmpToPml(snmp_oid, oid, sizeof(oid));
+
+ *p++ = PML_GET_REQUEST;
+ *p++ = PML_DT_OBJECT_IDENTIFIER;
+ *p++ = dLen; /* assume oid length is < 10 bits */
+ memcpy(p, oid, dLen);
+ result = hpmud_write_channel(device, channel, message, dLen+3, HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
+ if (result != HPMUD_R_OK)
+ {
+ BUG("GetPml channel_write failed ret=%d\n", result);
+ stat = result;
+ goto bugout;
+ }
+
+ result = hpmud_read_channel(device, channel, message, sizeof(message), HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
+ if (result != HPMUD_R_OK || len == 0)
+ {
+ BUG("GetPml channel_read failed ret=%d len=%d\n", result, len);
+ goto bugout;
+ }
+
+ p = message;
+ reply = *p++; /* read command reply */
+ status = *p++; /* read execution outcome */
+
+ if (reply != (PML_GET_REQUEST | 0x80) && status & 0x80)
+ {
+ BUG("GetPml failed reply=%x outcome=%x\n", reply, status);
+ DBG_DUMP(p, len-2);
+ goto bugout;
+ }
+
+ dt = *p++; /* read data type */
+
+ if (dt == PML_DT_ERROR_CODE)
+ {
+ /* Ok, but invalid data type requested, get new data type. */
+ p += 2; /* eat length and err code */
+ dt = *p++; /* read data type */
+ }
+
+ if (dt != PML_DT_OBJECT_IDENTIFIER)
+ {
+ BUG("GetPml failed data type=%x\n", dt);
+ goto bugout;
+ }
+
+ dLen = *p++; /* read oid length */
+ p += dLen; /* eat oid */
+
+ dt = *p; /* read data type. */
+ dLen = ((*p & 0x3) << 8 | *(p+1)); /* read 10 bit len from 2 byte field */
+ p += 2; /* eat type and length */
+ }
+
+ memcpy(buf, p, dLen);
+ *bytes_read = dLen;
+ *type = dt;
+ *pml_result = status;
+ stat = HPMUD_R_OK;
+
+ DBG("get_pml result len=%d datatype=%x pmlresult=%x\n", dLen, dt, status);
+ DBG_DUMP(buf, dLen);
+
+bugout:
+ return stat;
+}
+
+
diff --git a/io/hpmud/pml.h b/io/hpmud/pml.h
new file mode 100644
index 0000000..188d584
--- /dev/null
+++ b/io/hpmud/pml.h
@@ -0,0 +1,77 @@
+/*****************************************************************************\
+
+ pml.h - get/set pml api for hpmud
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ (c) 2003-2004 Copyright Hewlett-Packard Development Company, LP
+
+\*****************************************************************************/
+
+#ifndef _PML_H
+#define _PML_H
+
+/*
+ * PML definitions
+ */
+
+enum PML_REQUESTS
+{
+ PML_GET_REQUEST = 0,
+ PML_GET_NEXT_REQUEST = 0x1,
+ PML_BLOCK_REQUEST = 0x3,
+ PML_SET_REQUEST = 0x4,
+ PML_ENABLE_TRAP_REQUEST = 0x5,
+ PML_DISABLE_TRAP_REQUEST = 0x6,
+ PML_TRAP_REQUEST = 0x7
+};
+
+enum PML_ERROR_VALUES
+{
+ PML_EV_OK = 0,
+ PML_EV_OK_END_OF_SUPPORTED_OBJECTS = 0x1,
+ PML_EV_OK_NEAREST_LEGAL_VALUE_SUBSTITUTED = 0x2,
+ PML_EV_ERROR_UNKNOWN_REQUEST = 0x80,
+ PML_EV_ERROR_BUFFER_OVERFLOW = 0x81,
+ PML_EV_ERROR_COMMAND_EXECUTION_ERROR = 0x82,
+ PML_EV_ERROR_UNKNOWN_OBJECT_IDENTIFIER = 0x83,
+ PML_EV_ERROR_OBJECT_DOES_NOT_SUPPORT_REQUESTED_ACTION = 0x84,
+ PML_EV_ERROR_INVALID_OR_UNSUPPORTED_VALUE = 0x85,
+ PML_EV_ERROR_PAST_END_OF_SUPPORTED_OBJECTS = 0x86,
+ PML_EV_ERROR_ACTION_CAN_NOT_BE_PERFORMED_NOW = 0x87
+};
+
+enum PML_DATA_TYPES
+{
+ PML_DT_OBJECT_IDENTIFIER = 0,
+ PML_DT_ENUMERATION = 0x04,
+ PML_DT_SIGNED_INTEGER = 0x08,
+ PML_DT_REAL = 0x0C,
+ PML_DT_STRING = 0x10,
+ PML_DT_BINARY = 0x14,
+ PML_DT_ERROR_CODE = 0x18,
+ PML_DT_NULL_VALUE = 0x1C,
+ PML_DT_COLLECTION = 0x20,
+ PML_DT_UNKNOWN = 0xff
+};
+
+int __attribute__ ((visibility ("hidden"))) GetSnmp(const char *ip, int port, const char *szoid, void *buffer, unsigned int size, int *type, int *pml_result, int *result);
+
+#endif // _PML_H
+
diff --git a/io/hpmud/pp.c b/io/hpmud/pp.c
new file mode 100644
index 0000000..3b95ab7
--- /dev/null
+++ b/io/hpmud/pp.c
@@ -0,0 +1,1310 @@
+/*****************************************************************************\
+
+ pp.c - parallel port support for multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Client/Server generic message format (see messaging-protocol.doc):
+
+\*****************************************************************************/
+
+#ifdef HAVE_PPORT
+
+#include "hpmud.h"
+#include "hpmudi.h"
+
+mud_device_vf __attribute__ ((visibility ("hidden"))) pp_mud_device_vf =
+{
+ .read = pp_read,
+ .write = pp_write,
+ .open = pp_open,
+ .close = pp_close,
+ .get_device_id = pp_get_device_id,
+ .get_device_status = pp_get_device_status,
+ .channel_open = pp_channel_open,
+ .channel_close = pp_channel_close,
+ .channel_write = musb_channel_write,
+ .channel_read = musb_channel_read
+};
+
+static mud_channel_vf pp_raw_channel_vf =
+{
+ .open = pp_raw_channel_open,
+ .close = pp_raw_channel_close,
+ .channel_write = musb_raw_channel_write,
+ .channel_read = musb_raw_channel_read
+};
+
+static mud_channel_vf pp_mlc_channel_vf =
+{
+ .open = pp_mlc_channel_open,
+ .close = pp_mlc_channel_close,
+ .channel_write = musb_mlc_channel_write,
+ .channel_read = musb_mlc_channel_read
+};
+
+static mud_channel_vf pp_dot4_channel_vf =
+{
+ .open = pp_dot4_channel_open,
+ .close = pp_dot4_channel_close,
+ .channel_write = musb_dot4_channel_write,
+ .channel_read = musb_dot4_channel_read
+};
+
+static int frob_control(int fd, unsigned char mask, unsigned char val)
+{
+ struct ppdev_frob_struct frob;
+
+ /* Convert ieee1284 control values to PC-style (invert Strobe, AutoFd and Select) . */
+ frob.val = val ^ (mask & (PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT));
+
+ frob.mask = mask;
+ return ioctl(fd, PPFCONTROL, &frob);
+}
+
+static unsigned char read_status(int fd)
+{
+ unsigned char status;
+ if (ioctl(fd, PPRSTATUS, &status))
+ BUG("read_status error: %m\n");
+
+ /* Convert PC-style status values to ieee1284 (invert Busy). */
+ return (status ^ PARPORT_STATUS_BUSY);
+}
+
+static int wait_status(int fd, unsigned char mask, unsigned char val, int usec)
+{
+ struct timeval tmo, now;
+ struct timespec min;
+ unsigned char status;
+ int cnt=0;
+
+ gettimeofday (&tmo, NULL);
+ tmo.tv_usec += usec;
+ tmo.tv_sec += tmo.tv_usec / 1000000;
+ tmo.tv_usec %= 1000000;
+
+ min.tv_sec = 0;
+ min.tv_nsec = 5000000; /* 5ms */
+
+ while (1)
+ {
+ status = read_status(fd);
+ if ((status & mask) == val)
+ {
+ // bug("found status=%x mask=%x val=%x cnt=%d: %s %d\n", status, mask, val, cnt, __FILE__, __LINE__);
+ return 0;
+ }
+ cnt++;
+ // nanosleep(&min, NULL);
+ gettimeofday(&now, NULL);
+ if ((now.tv_sec > tmo.tv_sec) || (now.tv_sec == tmo.tv_sec && now.tv_usec > tmo.tv_usec))
+ {
+ DBG("wait_status timeout status=%x mask=%x val=%x us=%d\n", status, mask, val, usec);
+ return -1; /* timeout */
+ }
+ }
+}
+
+static int wait(int usec)
+{
+ struct timeval tmo, now;
+ int cnt=0;
+
+ gettimeofday (&tmo, NULL);
+ tmo.tv_usec += usec;
+ tmo.tv_sec += tmo.tv_usec / 1000000;
+ tmo.tv_usec %= 1000000;
+
+ while (1)
+ {
+ cnt++;
+ gettimeofday(&now, NULL);
+ if ((now.tv_sec > tmo.tv_sec) || (now.tv_sec == tmo.tv_sec && now.tv_usec > tmo.tv_usec))
+ {
+ return 0; /* timeout */
+ }
+ }
+}
+
+static int ecp_is_fwd(int fd)
+{
+ unsigned char status;
+
+ status = read_status(fd);
+ if ((status & PARPORT_STATUS_PAPEROUT) == PARPORT_STATUS_PAPEROUT)
+ return 1;
+ return 0;
+}
+
+static int ecp_is_rev(int fd)
+{
+ unsigned char status;
+
+ status = read_status(fd);
+ if ((status & PARPORT_STATUS_PAPEROUT) == 0)
+ return 1;
+ return 0;
+}
+
+static int ecp_rev_to_fwd(int fd)
+{
+ int dir=0;
+
+ if (ecp_is_fwd(fd))
+ return 0;
+
+ /* Event 47: write NReverseRequest/nInit=1 */
+ frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
+
+ /* Event 48: wait PeriphClk/nAck=1, PeriphAck/Busy=0 */
+ // wait_status(fd, PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_BUSY, PARPORT_STATUS_PAPEROUT, SIGNAL_TIMEOUT);
+
+ /* Event 49: wait nAckReverse/PError=1 */
+ wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
+
+ ioctl(fd, PPDATADIR, &dir);
+
+ return 0;
+}
+
+static int ecp_fwd_to_rev(int fd)
+{
+ int dir=1;
+
+ if (ecp_is_rev(fd))
+ return 0;
+
+ /* Event 33: NPeriphRequest/nFault=0, PeriphAck/Busy=0 */
+ wait_status(fd, PARPORT_STATUS_BUSY | PARPORT_STATUS_ERROR, 0, PP_DEVICE_TIMEOUT);
+
+ /* Event 38: write HostAck/nAutoFd=0 */
+ ioctl(fd, PPDATADIR, &dir);
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
+ wait(PP_SETUP_TIMEOUT);
+
+ /* Event 39: write NReverseRequest/nInit=0 (start bus reversal) */
+ frob_control(fd, PARPORT_CONTROL_INIT, 0);
+
+ /* Event 40: wait nAckReverse/PError=0 */
+ wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
+
+ return 0;
+}
+
+static int ecp_write_addr(int fd, unsigned char data)
+{
+ int cnt=0, len=0;
+ unsigned d=(data | 0x80); /* set channel address bit */
+
+ ecp_rev_to_fwd(fd);
+
+ /* Event 33: PeriphAck/Busy=0 */
+ if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_SIGNAL_TIMEOUT))
+ {
+ BUG("ecp_write_addr transfer stalled\n");
+ goto bugout;
+ }
+
+ while (1)
+ {
+ /* Event 34: write HostAck/nAutoFD=0 (channel command), data */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
+ ioctl(fd, PPWDATA, &d);
+
+ /* Event 35: write HostClk/NStrobe=0 */
+ frob_control(fd, PARPORT_CONTROL_STROBE, 0);
+
+ /* Event 36: wait PeriphAck/Busy=1 */
+ if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
+ {
+
+ /* Event 72: write NReverseRequest/nInit=0 (Host Transfer Recovery) */
+ frob_control(fd, PARPORT_CONTROL_INIT, 0);
+
+ /* Event 73: wait nAckReverse/PError=0 */
+ wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
+
+ /* Event 74: write NReverseRequest/nInit=1 */
+ frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
+
+ /* Event 75: wait nAckReverse/PError=1 */
+ wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
+
+ cnt++;
+ if (cnt > 4)
+ {
+ BUG("ecp_write_addr transfer stalled\n");
+ goto bugout;
+ }
+ BUG("ecp_write_addr host transfer recovery cnt=%d\n", cnt);
+ continue; /* retry */
+ }
+ break; /* done */
+ } /* while (1) */
+
+ len = 1;
+
+bugout:
+
+ /* Event 37: write HostClk/NStrobe=1 */
+ frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
+
+ return len;
+}
+
+static int ecp_write_data(int fd, unsigned char data)
+{
+ int cnt=0, len=0;
+
+ // ecp_rev_to_fwd(fd);
+
+ /* Event 33: check PeriphAck/Busy=0 */
+ if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_SIGNAL_TIMEOUT))
+ {
+ BUG("ecp_write_data transfer stalled\n");
+ goto bugout;
+ }
+
+ while (1)
+ {
+ /* Event 34: write HostAck/nAutoFD=1 (channel data), data */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
+ ioctl(fd, PPWDATA, &data);
+
+ /* Event 35: write HostClk/NStrobe=0 */
+ frob_control(fd, PARPORT_CONTROL_STROBE, 0);
+
+ /* Event 36: wait PeriphAck/Busy=1 */
+ if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
+ {
+
+ /* Event 72: write NReverseRequest/nInit=0 (Host Transfer Recovery) */
+ frob_control(fd, PARPORT_CONTROL_INIT, 0);
+
+ /* Event 73: wait nAckReverse/PError=0 */
+ wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
+
+ /* Event 74: write NReverseRequest/nInit=1 */
+ frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
+
+ /* Event 75: wait nAckReverse/PError=1 */
+ wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
+
+ cnt++;
+ if (cnt > 4)
+ {
+ BUG("ecp_write_data transfer stalled\n");
+ goto bugout;
+ }
+ BUG("ecp_write_data host transfer recovery cnt=%d\n", cnt);
+ continue; /* retry */
+ }
+ break; /* done */
+ } /* while (1) */
+
+ len = 1;
+
+bugout:
+
+ /* Event 37: write HostClk/NStrobe=1 */
+ frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
+
+ return len;
+}
+
+static int ecp_read_data(int fd, unsigned char *data)
+{
+ int len=0;
+
+ // ecp_fwd_to_rev(fd);
+
+ /* Event 43: wait PeriphClk/NAck=0 */
+ if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
+ {
+ len = -1;
+ goto bugout;
+ }
+ ioctl(fd, PPRDATA, data);
+
+ /* Event 44: write HostAck/nAutoFd=1 */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
+
+ /* Event 45: wait PeriphClk/NAck=1 */
+ wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
+
+ /* Event 46: write HostAck/nAutoFd=0 */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
+
+ len = 1;
+
+bugout:
+
+ return len;
+}
+
+static int ecp_read(int fd, void *buffer, int size, int usec)
+{
+ int i=0;
+ unsigned char *p = (unsigned char *)buffer;
+
+ ecp_fwd_to_rev(fd);
+
+ while (i < size)
+ {
+ if (ecp_read_data(fd, p+i) != 1)
+ {
+ usec-=PP_SIGNAL_TIMEOUT;
+ if (usec > 0)
+ continue;
+
+// return -1;
+ return -ETIMEDOUT; /* timeout */
+ }
+ i++;
+ }
+ return i;
+}
+
+static int ecp_write(int fd, const void *buffer, int size)
+{
+ int i;
+ unsigned char *p = (unsigned char *)buffer;
+ static int timeout=0;
+
+ if (timeout)
+ {
+ timeout=0;
+ return -1; /* report timeout */
+ }
+
+ ecp_rev_to_fwd(fd);
+
+ for (i=0; i < size; i++)
+ {
+ if (ecp_write_data(fd, p[i]) != 1)
+ {
+ if (i)
+ timeout=1; /* save timeout, report bytes written */
+ else
+ i=-1; /* report timeout */
+ break;
+ }
+ }
+ return i;
+}
+
+static int nibble_read_data(int fd, unsigned char *data)
+{
+ int len=0;
+ unsigned char nibble;
+
+ /* Event 7: write HostBusy/nAutoFd=0 */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 8: peripheral sets low-order nibble. */
+
+ /* Event 9: wait PtrClk/NAck=0 */
+ if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
+ {
+ len = -1;
+ goto bugout;
+ }
+ nibble = read_status(fd) >> 3;
+ nibble = ((nibble & 0x10) >> 1) | (nibble & 0x7);
+ *data = nibble;
+
+ /* Event 10: write HostBusy/nAutoFd=1 */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
+
+ /* Event 11: wait PtrClk/NAck=1 */
+ wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
+
+ /* Event 7: write HostBusy/nAutoFd=0 */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 8: peripheral sets high-order nibble. */
+
+ /* Event 9: wait PtrClk/NAck=0 */
+ if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
+ {
+ len = -1;
+ goto bugout;
+ }
+ nibble = read_status(fd) >> 3;
+ nibble = ((nibble & 0x10) >> 1) | (nibble & 0x7);
+ *data |= (nibble<<4);
+
+ /* Event 10: write HostBusy/nAutoFd=1 */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
+
+ /* Event 11: wait PtrClk/NAck=1 */
+ wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
+
+ len = 1;
+
+bugout:
+
+ return len;
+}
+
+static int nibble_read(int fd, int flag, void *buffer, int size, int usec)
+{
+ int i=0;
+ unsigned char *p = (unsigned char *)buffer;
+ int m = IEEE1284_MODE_NIBBLE | flag;
+ int mc = IEEE1284_MODE_COMPAT;
+ unsigned char status;
+
+ ioctl (fd, PPNEGOT, &mc);
+ if (ioctl (fd, PPNEGOT, &m))
+ {
+ DBG("nibble_read negotiation failed: %m\n");
+ return -1;
+ }
+
+ while (i < size)
+ {
+ if (nibble_read_data(fd, p+i) != 1)
+ {
+ usec-=PP_SIGNAL_TIMEOUT;
+ if (usec > 0)
+ continue;
+
+// return -1;
+ return -ETIMEDOUT; /* timeout */
+ }
+
+ i++;
+
+ /* More data? */
+ status = read_status(fd);
+ if (status & PARPORT_STATUS_ERROR)
+ {
+ /* Event 7: write HostBusy/nAutoFd=0, idle phase */
+ frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
+
+ break; /* done */
+ }
+ }
+
+ return i;
+}
+
+static int compat_write_data(int fd, unsigned char data)
+{
+ int len=0;
+
+ /* wait Busy=0 */
+ if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_DEVICE_TIMEOUT))
+ {
+ BUG("compat_write_data transfer stalled\n");
+ goto bugout;
+ }
+
+ ioctl(fd, PPWDATA, &data);
+ wait(PP_SETUP_TIMEOUT);
+
+ /* write NStrobe=0 */
+ frob_control(fd, PARPORT_CONTROL_STROBE, 0);
+
+ /* wait Busy=1 */
+ if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
+ {
+ BUG("compat_write_data transfer stalled\n");
+ goto bugout;
+ }
+
+ /* write nStrobe=1 */
+ frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
+
+ len = 1;
+
+bugout:
+ return len;
+}
+
+static int compat_write(int fd, const void *buffer, int size)
+{
+ int i=0;
+ unsigned char *p = (unsigned char *)buffer;
+ int m = IEEE1284_MODE_COMPAT;
+ static int timeout=0;
+
+ if (timeout)
+ {
+ timeout=0;
+ return -1; /* report timeout */
+ }
+
+ if (ioctl(fd, PPNEGOT, &m))
+ {
+ BUG("compat_write failed: %m\n");
+ goto bugout;
+ }
+
+ for (i=0; i < size; i++)
+ {
+ if (compat_write_data(fd, p[i]) != 1)
+ {
+ if (i)
+ timeout=1; /* save timeout, report bytes written */
+ else
+ i=-1; /* report timeout */
+ break;
+ }
+ }
+
+bugout:
+ return i;
+}
+
+static int claim_pp(int fd)
+{
+ int stat=1;
+
+ /* Claim parallel port (can block forever). */
+ if (ioctl(fd, PPCLAIM))
+ {
+ BUG("failed claim_pp fd=%d: %m\n", fd);
+ goto bugout;
+ }
+
+ DBG("claimed pp fd=%d\n", fd);
+
+ stat=0;
+
+bugout:
+ return stat;
+}
+
+static int release_pp(int fd)
+{
+ int stat=1, m=IEEE1284_MODE_COMPAT;
+
+ /* Restore compat_mode (default), otherwise close(fd) may block restoring compat_mode. */
+ if (ioctl(fd, PPNEGOT, &m))
+ {
+ BUG("failed release_pp fd=%d: %m\n", fd);
+ goto bugout;
+ }
+
+ ioctl(fd, PPRELEASE);
+
+ DBG("released pp fd=%d\n", fd);
+
+ stat=0;
+
+bugout:
+ return 0;
+}
+
+static int device_id(int fd, char *buffer, int size)
+{
+ int len=0, maxSize;
+
+ maxSize = (size > 1024) ? 1024 : size; /* RH8 has a size limit for device id */
+
+ len = nibble_read(fd, IEEE1284_DEVICEID, buffer, maxSize, 0);
+ if (len < 0)
+ {
+ BUG("unable to read device-id ret=%d\n", len);
+ len = 0;
+ goto bugout;
+ }
+ if (len > (size-1))
+ len = size-1; /* leave byte for zero termination */
+ if (len > 2)
+ len -= 2;
+ memcpy(buffer, buffer+2, len); /* remove length */
+ buffer[len]=0;
+
+ DBG("read actual device_id successfully fd=%d len=%d\n", fd, len);
+
+bugout:
+ return len; /* length does not include zero termination */
+}
+
+static int device_status(int fd, unsigned int *status)
+{
+ int m, stat=1;
+ unsigned char byte = NFAULT_BIT; /* set default */
+
+ m = IEEE1284_MODE_COMPAT;
+ if (ioctl (fd, PPNEGOT, &m))
+ {
+ BUG("unable to read device_status: %m\n");
+ stat = HPMUD_R_IO_ERROR;
+ goto bugout;
+ }
+ byte = read_status(fd);
+
+ *status = (unsigned int)byte;
+ stat = 0;
+ DBG("read actual device_status successfully fd=%d\n", fd);
+
+bugout:
+ return stat;
+}
+
+/* Create channel object given the requested socket id and service name. */
+static int new_channel(mud_device *pd, int index, const char *sn)
+{
+ int stat=1;
+
+ /* Check for existing name service already open. */
+ if (pd->channel[index].client_cnt)
+ {
+#if 0
+ if (index == HPMUD_EWS_CHANNEL)
+ {
+ pd->channel[index].client_cnt++; /* allow multiple clients for separate USB interfaces only */
+ stat = 0;
+ DBG("reused %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
+ }
+ else
+#endif
+ 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);
+ goto bugout;
+ }
+
+ if (pd->io_mode == HPMUD_RAW_MODE || pd->io_mode == HPMUD_UNI_MODE)
+ pd->channel[index].vf = pp_raw_channel_vf;
+ else if (pd->io_mode == HPMUD_MLC_GUSHER_MODE || pd->io_mode == HPMUD_MLC_MISER_MODE)
+ pd->channel[index].vf = pp_mlc_channel_vf;
+ else
+ pd->channel[index].vf = pp_dot4_channel_vf;
+
+ pd->channel[index].index = index;
+ pd->channel[index].client_cnt = 1;
+ pd->channel[index].sockid = index; /* static socket id is valid for MLC but not 1284.4 */
+ pd->channel[index].pid = getpid();
+ pd->channel[index].dindex = pd->index;
+ pd->channel[index].fd = -1;
+ strcpy(pd->channel[index].sn, sn);
+ pd->channel_cnt++;
+
+ stat = 0;
+ DBG("new %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
+
+bugout:
+ return stat;
+}
+
+/* Remove channel object given the channel decriptor. */
+static int del_channel(mud_device *pd, mud_channel *pc)
+{
+ pc->client_cnt--;
+
+ if (pc->client_cnt <= 0)
+ {
+ pd->channel_cnt--;
+ }
+ DBG("removed %s channel=%d clientCnt=%d channelCnt=%d\n", pc->sn, pc->index, pc->client_cnt, pd->channel_cnt);
+ return 0;
+}
+
+/*********************************************************************************************************************************
+ * Parallel port mud_device functions.
+ */
+
+int __attribute__ ((visibility ("hidden"))) pp_write(int fd, const void *buf, int size, int usec)
+{
+ int len=0, m;
+
+ ioctl(fd, PPGETMODE, &m);
+
+ if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
+ {
+ len = ecp_write(fd, buf, size);
+ }
+ else
+ {
+ len = compat_write(fd, buf, size);
+ }
+
+ DBG("write fd=%d len=%d size=%d\n", fd, len, size);
+ DBG_DUMP(buf, len < 32 ? len : 32);
+
+ return len;
+}
+
+int __attribute__ ((visibility ("hidden"))) pp_read(int fd, void *buf, int size, int usec)
+{
+ int len=0, m;
+// int sec = usec/1000000;
+
+ ioctl(fd, PPGETMODE, &m);
+
+ if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
+ {
+ len = ecp_read(fd, buf, size, usec);
+ }
+ else
+ {
+ len = nibble_read(fd, 0, buf, size, usec);
+ }
+
+ DBG("read fd=%d len=%d size=%d usec=%d\n", fd, len, size, usec);
+ DBG_DUMP(buf, len < 32 ? len : 32);
+
+ return len;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_open(mud_device *pd)
+{
+ char dev[255], uriModel[128], model[128];
+ int len, m, fd;
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ hpmud_get_uri_model(pd->uri, uriModel, sizeof(uriModel));
+
+ if (pd->id[0] == 0)
+ {
+ /* First client, open actual kernal device, use blocking i/o. */
+ hpmud_get_uri_datalink(pd->uri, dev, sizeof(dev));
+ if ((fd = open(dev, O_RDWR | O_NOCTTY)) < 0)
+ {
+ BUG("unable to open %s: %m\n", pd->uri);
+ goto bugout;
+ }
+
+ /* Open can succeed with no connected device, see if this is a valid device. */
+ if (ioctl(fd, PPGETMODES, &m))
+ {
+ BUG("unable to open %s: %m\n", pd->uri);
+ goto bugout;
+ }
+
+ /* Claim parallel port (can block forever). */
+ if (claim_pp(fd))
+ goto bugout;
+
+ len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy and cache it */
+
+ if (len > 0 && is_hp(pd->id))
+ power_up(pd, fd);
+
+ release_pp(fd);
+
+ if (len == 0)
+ goto bugout;
+
+ pd->open_fd = fd;
+ }
+
+ /* Make sure uri model matches device id model. */
+ hpmud_get_model(pd->id, model, sizeof(model));
+ if (strcmp(uriModel, model) != 0)
+ {
+ stat = HPMUD_R_INVALID_DEVICE_NODE; /* probably a laserjet, or different device plugged in */
+ BUG("invalid model %s != %s\n", uriModel, model);
+ goto bugout;
+ }
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_close(mud_device *pd)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (pd->open_fd >=0)
+ close(pd->open_fd);
+
+ pd->open_fd = -1;
+ pd->id[0] = 0;
+
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_id(mud_device *pd, char *buf, int size, int *len)
+{
+ int m, fd = pd->open_fd;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+
+ *len=0;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (fd < 0)
+ {
+ stat = HPMUD_R_INVALID_STATE;
+ BUG("invalid get_device_id state\n");
+ goto bugout;
+ }
+
+ if (pd->io_mode == HPMUD_UNI_MODE)
+ {
+ *len = strlen(pd->id); /* use cached copy */
+ DBG("using cached device_id io_mode=%d\n", pd->io_mode);
+ }
+ else
+ {
+ ioctl(fd, PPGETMODE, &m);
+ if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
+ {
+ *len = strlen(pd->id); /* channel is busy, return cached copy. */
+ DBG("using cached device_id m=%x\n", m);
+ }
+ else
+ {
+ if (pd->channel_cnt == 0)
+ {
+ /* Device not in use. Claim it, but release for other processes. */
+ if (claim_pp(fd))
+ goto bugout;
+ *len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy */
+ release_pp(fd);
+ }
+ else
+ {
+ /* Device already claimed by open_channel. */
+ *len = device_id(fd, pd->id, sizeof(pd->id)); /* get new copy */
+ }
+ }
+ }
+
+ if (*len)
+ {
+ memcpy(buf, pd->id, *len > size ? size : *len);
+ stat = HPMUD_R_OK;
+ }
+
+bugout:
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_status(mud_device *pd, unsigned int *status)
+{
+ int fd=pd->open_fd;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+ int m, r=0;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (fd < 0)
+ {
+ stat = HPMUD_R_INVALID_STATE;
+ BUG("invalid get_device_id state\n");
+ goto bugout;
+ }
+
+ if (pd->io_mode == HPMUD_UNI_MODE)
+ {
+ *status = NFAULT_BIT; /* fake status */
+ DBG("using cached device_status io_mode=%d\n", pd->io_mode);
+ }
+ else
+ {
+ ioctl(fd, PPGETMODE, &m);
+ if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
+ {
+ *status = NFAULT_BIT; /* channel is busy, fake 8-bit status */
+ DBG("using cached device_status m=%x\n", m);
+ }
+ else
+ {
+ if (pd->channel_cnt == 0)
+ {
+ /* Device not in use. Claim it, but release for other processes. */
+ if (claim_pp(fd))
+ goto bugout;
+ r = device_status(fd, status);
+ release_pp(fd);
+ }
+ else
+ {
+ /* Device already claimed by open_channel. */
+ r = device_status(fd, status);
+ }
+ }
+ }
+
+ if (r != 0)
+ goto bugout;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ pthread_mutex_unlock(&pd->mutex);
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_open(mud_device *pd, const char *sn, HPMUD_CHANNEL *cd)
+{
+ int index;
+ enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
+
+ /* Check for valid service requests. */
+ if ((stat = service_to_channel(pd, sn, &index)) != HPMUD_R_OK)
+ goto bugout;
+
+ pthread_mutex_lock(&pd->mutex);
+
+ if (new_channel(pd, index, sn))
+ {
+ stat = HPMUD_R_DEVICE_BUSY;
+ }
+ else
+ {
+ if ((stat = (pd->channel[index].vf.open)(&pd->channel[index])) != HPMUD_R_OK) /* call transport specific open */
+ del_channel(pd, &pd->channel[index]); /* open failed, cleanup */
+ else
+ *cd = index;
+ }
+
+ pthread_mutex_unlock(&pd->mutex);
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_close(mud_device *pd, mud_channel *pc)
+{
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+
+ pthread_mutex_lock(&pd->mutex);
+ stat = (pc->vf.close)(pc); /* call trasport specific close */
+ del_channel(pd, pc);
+ pthread_mutex_unlock(&pd->mutex);
+
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * Parallel port raw_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_open(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ if (claim_pp(pd->open_fd))
+ return HPMUD_R_IO_ERROR;
+ pc->fd = pd->open_fd;
+ return HPMUD_R_OK;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_close(mud_channel *pc)
+{
+ if (pc->fd >= 0)
+ release_pp(pc->fd);
+ pc->fd = -1;
+ return HPMUD_R_OK;
+}
+
+/*******************************************************************************************************************************
+ * Parallel port mlc_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_open(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+ int i, m;
+
+ /* Initialize MLC transport if this is the first MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (claim_pp(pd->open_fd))
+ goto bugout;
+
+ /* Negotiate ECP mode. */
+ m = IEEE1284_MODE_ECPSWE;
+ if (ioctl(pd->open_fd, PPNEGOT, &m))
+ {
+ BUG("unable to negotiate %s ECP mode: %m\n", pd->uri);
+ goto bugout;
+ }
+
+ /* Enable MLC mode with ECP channel-77. */
+ ecp_write_addr(pd->open_fd, 78);
+ ecp_write(pd->open_fd, "\0", 1);
+ ecp_write_addr(pd->open_fd, 77);
+
+ /* MLC initialize */
+ if (MlcInit(pc, pd->open_fd) != 0)
+ goto bugout;
+
+ /* Reset transport attributes for all channels. */
+ for (i=0; i<HPMUD_CHANNEL_MAX; i++)
+ memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
+
+ pd->mlc_fd = pd->open_fd;
+ pd->mlc_up=1;
+
+ } /* if (pDev->ChannelCnt==1) */
+
+ if (MlcConfigSocket(pc, pd->mlc_fd))
+ goto bugout;
+
+ if (MlcOpenChannel(pc, pd->mlc_fd))
+ goto bugout;
+
+ pc->rcnt = pc->rindex = 0;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_close(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+ int m;
+
+ if (pd->mlc_up)
+ {
+ if (MlcCloseChannel(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+
+ /* Remove MLC transport if this is the last MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (pd->mlc_up)
+ {
+ if (MlcExit(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+ pd->mlc_up=0;
+
+ ecp_write_addr(pd->mlc_fd, 78); /* disable MLC mode with ECP channel-78 */
+ ecp_write(pd->mlc_fd, "\0", 1);
+
+ m = IEEE1284_MODE_NIBBLE;
+ ioctl(pd->mlc_fd, PPNEGOT, &m);
+ release_pp(pd->mlc_fd);
+
+ /* Delay for batch scanning. */
+ sleep(1);
+ }
+
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * Parallel port dot4_channel functions.
+ */
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_open(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+ int i, m;
+
+ /* Initialize MLC transport if this is the first MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (claim_pp(pd->open_fd))
+ goto bugout;
+
+ /* Negotiate ECP mode. */
+ m = IEEE1284_MODE_ECPSWE;
+ if (ioctl(pd->open_fd, PPNEGOT, &m))
+ {
+ BUG("unable to negotiate %s ECP mode: %m\n", pd->uri);
+ goto bugout;
+ }
+
+ /* Enable MLC mode with ECP channel-77. */
+ ecp_write_addr(pd->open_fd, 78);
+ ecp_write(pd->open_fd, "\0", 1);
+ ecp_write_addr(pd->open_fd, 77);
+
+ /* DOT4 initialize */
+ if (Dot4Init(pc, pd->open_fd) != 0)
+ goto bugout;
+
+ /* Reset transport attributes for all channels. */
+ for (i=0; i<HPMUD_CHANNEL_MAX; i++)
+ memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
+
+ pd->mlc_fd = pd->open_fd;
+ pd->mlc_up=1;
+
+ } /* if (pDev->ChannelCnt==1) */
+
+ if (Dot4GetSocket(pc, pd->mlc_fd))
+ goto bugout;
+
+ if (Dot4OpenChannel(pc, pd->mlc_fd))
+ goto bugout;
+
+ pc->rcnt = pc->rindex = 0;
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ return stat;
+}
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_close(mud_channel *pc)
+{
+ mud_device *pd = &msp->device[pc->dindex];
+ enum HPMUD_RESULT stat = HPMUD_R_OK;
+ int m;
+
+ if (pd->mlc_up)
+ {
+ if (Dot4CloseChannel(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+
+ /* Remove MLC transport if this is the last MLC channel. */
+ if (pd->channel_cnt==1)
+ {
+ if (pd->mlc_up)
+ {
+ if (Dot4Exit(pc, pd->mlc_fd))
+ stat = HPMUD_R_IO_ERROR;
+ }
+ pd->mlc_up=0;
+
+ ecp_write_addr(pd->mlc_fd, 78); /* disable MLC mode with ECP channel-78 */
+ ecp_write(pd->mlc_fd, "\0", 1);
+
+ m = IEEE1284_MODE_NIBBLE;
+ ioctl(pd->mlc_fd, PPNEGOT, &m);
+ release_pp(pd->mlc_fd);
+
+ /* Delay for batch scanning. */
+ sleep(1);
+ }
+
+ return stat;
+}
+
+/*******************************************************************************************************************************
+ * Parallel port probe devices, walk the parallel port bus(s) looking for HP products.
+ */
+
+int __attribute__ ((visibility ("hidden"))) pp_probe_devices(char *lst, int lst_size, int *cnt)
+{
+ struct hpmud_model_attributes ma;
+ char dev[HPMUD_LINE_SIZE];
+ char rmodel[128];
+ char model[128];
+ char id[1024];
+ int i, size=0, fd, m;
+
+ for (i=0; i < 4; i++)
+ {
+ sprintf(dev, "/dev/parport%d", i);
+
+ if ((fd = open(dev, O_RDONLY | O_NOCTTY)) < 0)
+ continue;
+
+ /* Silently check the port for valid device (no syslog errors). */
+ if (ioctl(fd, PPGETMODES, &m) == 0)
+ {
+ if (claim_pp(fd) == 0)
+ {
+ if (device_id(fd, id, sizeof(id)) > 0 && is_hp(id))
+ {
+ hpmud_get_model(id, model, sizeof(model));
+ hpmud_get_raw_model(id, rmodel, sizeof(rmodel));
+ snprintf(dev, sizeof(dev), "hp:/par/%s?device=/dev/parport%d", model, i);
+
+ /* See if device is supported by hplip. */
+ hpmud_query_model(dev, &ma);
+ if (ma.support != HPMUD_SUPPORT_TYPE_HPLIP)
+ {
+ BUG("ignoring %s support=%d\n", dev, ma.support);
+ continue; /* ignor, not supported */
+ }
+
+ if (strncasecmp(rmodel, "hp ", 3) == 0)
+ size += sprintf(lst+size,"direct %s \"HP %s\" \"HP %s LPT parport%d HPLIP\" \"%s\"\n", dev, &rmodel[3], &rmodel[3], i, id);
+ else
+ size += sprintf(lst+size,"direct %s \"HP %s\" \"HP %s LPT parport%d HPLIP\" \"%s\"\n", dev, rmodel, rmodel, i, id);
+ *cnt+=1;
+ }
+ release_pp(fd);
+ }
+ else
+ {
+ BUG("unable to probe %s: %m\n", dev); /* device is busy */
+ }
+ }
+ close(fd);
+ }
+ return size;
+}
+
+enum HPMUD_RESULT hpmud_make_par_uri(const char *dnode, char *uri, int uri_size, int *bytes_read)
+{
+ char model[128];
+ char id[1024];
+ enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
+ int fd=-1, m;
+
+ DBG("[%d] hpmud_make_par_uri() dnode=%s\n", getpid(), dnode);
+
+ *bytes_read=0;
+
+ uri[0]=0;
+
+ if ((fd = open(dnode, O_RDONLY | O_NOCTTY)) < 0)
+ {
+ BUG("unable to open %s: %m\n", dnode);
+ goto bugout;
+ }
+
+ if (ioctl(fd, PPGETMODES, &m))
+ {
+ BUG("unable to make uri %s: %m\n", dnode);
+ goto bugout;
+ }
+
+ if (claim_pp(fd))
+ {
+ BUG("unable to make uri %s: %m\n", dnode); /* device is busy */
+ goto bugout;
+ }
+
+ if (device_id(fd, id, sizeof(id)) > 0 && is_hp(id))
+ {
+ hpmud_get_model(id, model, sizeof(model));
+ *bytes_read = snprintf(uri, uri_size, "hp:/par/%s?device=%s", model, dnode);
+ }
+ release_pp(fd);
+
+ stat = HPMUD_R_OK;
+
+bugout:
+ if (fd >= 0)
+ close(fd);
+ return stat;
+}
+
+#endif /* HAVE_PPORT */
diff --git a/io/hpmud/pp.h b/io/hpmud/pp.h
new file mode 100644
index 0000000..5a5198f
--- /dev/null
+++ b/io/hpmud/pp.h
@@ -0,0 +1,100 @@
+/*****************************************************************************\
+
+ pp.h - parallel port support for multi-point transport driver
+
+ (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*****************************************************************************/
+
+#ifndef _PP_H
+#define _PP_H
+
+#include <sys/ioctl.h>
+#include <linux/parport.h>
+#include <linux/ppdev.h>
+#include "hpmud.h"
+#include "hpmudi.h"
+
+/*
+ * PC-style parallel port bit definitions.
+ *
+ * Status
+ * bit
+ * 7 - Busy *
+ * 6 - NAck
+ * 5 - PError (PARPORT_STATUS_PAPEROUT)
+ * 4 - Select
+ *
+ * 3 - NFault (PARPORT_STATUS_ERROR)
+ * 2 -
+ * 1 -
+ * 0 -
+ *
+ * Control
+ * bit
+ * 7 -
+ * 6 -
+ * 5 -
+ * 4 -
+ *
+ * 3 - Select *
+ * 2 - Init
+ * 1 - AutoFD *
+ * 0 - Strobe *
+ *
+ * * inverted
+ *
+ * Notes:
+ * For ECP mode use low-level parport ioctl instead of high-level parport read/writes because its more reliable. High-level support
+ * for Compatible and Nibble modes are probably ok, but for consistency low-level parport ioctl is used.
+ *
+ */
+
+#define PP_DEVICE_TIMEOUT 30000000 /* device timeout (us) */
+//#define PP_SIGNAL_TIMEOUT 1000000 /* signal timeout (us), too long for 1ms timeout, DES 8/18/08 */
+//#define PP_SIGNAL_TIMEOUT 1000 /* signal timeout (us), too short for DJ540, DES 8/18/08 */
+#define PP_SIGNAL_TIMEOUT 100000 /* signal timeout (us), DES 8/18/08 */
+#define PP_SETUP_TIMEOUT 10 /* setup timeout (us) */
+
+struct _mud_device;
+struct _mud_channel;
+
+extern struct _mud_device_vf __attribute__ ((visibility ("hidden"))) pp_mud_device_vf;
+
+int __attribute__ ((visibility ("hidden"))) pp_write(int fd, const void *buf, int size, int usec);
+int __attribute__ ((visibility ("hidden"))) pp_read(int fd, void *buf, int size, int usec);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_open(struct _mud_device *pd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_close(struct _mud_device *pd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_id(struct _mud_device *pd, char *buf, int size, int *len);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_status(struct _mud_device *pd, unsigned int *status);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_open(struct _mud_device *pd, const char *sn, HPMUD_CHANNEL *cd);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_close(struct _mud_device *pd, struct _mud_channel *pc);
+
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_close(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_close(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_open(struct _mud_channel *pc);
+enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_close(struct _mud_channel *pc);
+
+int __attribute__ ((visibility ("hidden"))) pp_probe_devices(char *lst, int lst_size, int *cnt);
+
+#endif // _PP_H
+
diff --git a/io/mudext/hpmudext.c b/io/mudext/hpmudext.c
new file mode 100644
index 0000000..e387501
--- /dev/null
+++ b/io/mudext/hpmudext.c
@@ -0,0 +1,495 @@
+/*****************************************************************************\
+ hpmudext - Python extension for HP multi-point transport driver (HPMUD)
+
+ (c) Copyright 2010 Hewlett-Packard Development Company, L.P.
+
+ 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
+
+Requires:
+Python 2.2+
+
+Authors: Don Welch, David Suffield, Naga Samrat Chowdary Narla
+
+\*****************************************************************************/
+
+#include <Python.h>
+#include "hpmud.h"
+#include "hpmudi.h"
+
+/* Ref: PEP 353 (Python 2.5) */
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+/*
+HPMUDEXT API:
+
+result_code, dd = open_device(uri, io_mode)
+
+result_code = close_device(dd)
+
+result_code, data = get_device_id(dd)
+
+result_code, data = probe_devices(bus)
+
+result_code, cd = open_channel(dd, channel_name)
+
+result_code = close_channel(dd, cd)
+
+result_code, bytes_written = write_channel(dd, cd, data, [timeout])
+
+result_code, data = read_channel(dd, cd, bytes_to_read, [timeout])
+
+result_code, pml_result_code = set_pml(dd, cd, oid, type, data)
+
+result_code, data, pml_result_code = get_pml(dd, cd, oid, type)
+
+result_code, uri = make_usb_uri(busnum, devnum)
+
+result_code, uri = make_net_uri(ip, port)
+
+result_code, uri = make_zc_uri(ip, port)
+
+result_code, ip_address = get_zc_ip_address(hostname)
+
+result_code, uri = make_par_uri(devnode)
+
+*/
+
+
+ static PyObject *open_device(PyObject *self, PyObject *args)
+{
+ char * uri;
+ enum HPMUD_IO_MODE io_mode;
+ HPMUD_DEVICE dd;
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+
+ if (!PyArg_ParseTuple(args, "si", &uri, &io_mode))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_open_device(uri, io_mode, &dd);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(ii)", result, dd);
+}
+
+static PyObject *close_device(PyObject *self, PyObject *args)
+{
+ HPMUD_DEVICE dd;
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+
+ if (!PyArg_ParseTuple(args, "i", &dd))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_close_device(dd);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *get_device_id(PyObject *self, PyObject *args)
+{
+ HPMUD_DEVICE dd;
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ char buf[HPMUD_BUFFER_SIZE];
+ int bytes_read = 0;
+
+ if (!PyArg_ParseTuple(args, "i", &dd))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_get_device_id(dd, buf, HPMUD_BUFFER_SIZE, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, buf, bytes_read);
+
+}
+
+static PyObject *probe_devices(PyObject *self, PyObject *args)
+{
+ enum HPMUD_BUS_ID bus;
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ int cnt = 0;
+ int bytes_read = 0;
+ char buf[HPMUD_BUFFER_SIZE * 4];
+
+ if (!PyArg_ParseTuple(args, "i", &bus))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_probe_devices(bus, buf, HPMUD_BUFFER_SIZE * 4, &cnt, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, buf, bytes_read);
+}
+
+static PyObject *open_channel(PyObject *self, PyObject *args)
+{
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ HPMUD_DEVICE dd = -1;
+ char * channel_name;
+ HPMUD_CHANNEL cd = -1;
+
+ if (!PyArg_ParseTuple(args, "is", &dd, &channel_name))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_open_channel(dd, channel_name, &cd);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(ii)", result, cd);
+
+}
+
+static PyObject *close_channel(PyObject *self, PyObject *args)
+{
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ HPMUD_DEVICE dd;
+ HPMUD_CHANNEL cd;
+
+ if (!PyArg_ParseTuple(args, "ii", &dd, &cd))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_close_channel(dd, cd);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("i", result);
+}
+
+static PyObject *write_channel(PyObject *self, PyObject *args)
+{
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ HPMUD_DEVICE dd;
+ HPMUD_CHANNEL cd;
+ int timeout = 30;
+ char * buf;
+ int buf_size = 0;
+ int bytes_written = 0;
+
+ if (!PyArg_ParseTuple(args, "iis#|i", &dd, &cd, &buf, &buf_size, &timeout))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_write_channel(dd, cd, buf, buf_size, timeout, &bytes_written);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(ii)", result, bytes_written);
+}
+
+static PyObject *read_channel(PyObject *self, PyObject *args)
+{
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ HPMUD_DEVICE dd;
+ HPMUD_CHANNEL cd;
+ int timeout = 30;
+ char buf[HPMUD_BUFFER_SIZE];
+ int bytes_read = 0;
+ int bytes_to_read;
+
+ if (!PyArg_ParseTuple(args, "iii|i", &dd, &cd, &bytes_to_read, &timeout))
+ return NULL;
+
+ if (bytes_to_read > HPMUD_BUFFER_SIZE)
+ return Py_BuildValue("(is#)", HPMUD_R_INVALID_LENGTH, "", 0);
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_read_channel(dd, cd, (void *)buf, bytes_to_read, timeout, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, buf, bytes_read);
+}
+
+static PyObject *set_pml(PyObject *self, PyObject *args)
+{
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ HPMUD_DEVICE dd;
+ HPMUD_CHANNEL cd;
+ char * oid;
+ int type;
+ char * data;
+ int data_size;
+ int pml_result;
+
+ if (!PyArg_ParseTuple(args, "iisis#", &dd, &cd, &oid, &type, &data, &data_size))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_set_pml(dd, cd, oid, type, (void *)data, data_size, &pml_result);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(ii)", result, pml_result);
+}
+
+static PyObject *get_pml(PyObject *self, PyObject *args)
+{
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ HPMUD_DEVICE dd;
+ HPMUD_CHANNEL cd;
+ char * oid;
+ int type;
+ char buf[HPMUD_BUFFER_SIZE * 4];
+ int pml_result;
+ int bytes_read = 0;
+
+ if (!PyArg_ParseTuple(args, "iisi", &dd, &cd, &oid, &type))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_get_pml(dd, cd, oid, (void *)buf, HPMUD_BUFFER_SIZE * 4, &bytes_read, &type, &pml_result);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#ii)", result, buf, bytes_read, type, pml_result);
+}
+
+static PyObject *make_usb_uri(PyObject *self, PyObject *args)
+{
+ char * busnum;
+ char * devnum;
+ char uri[HPMUD_BUFFER_SIZE];
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ int bytes_read = 0;
+
+ if (!PyArg_ParseTuple(args, "ss", &busnum, &devnum))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_make_usb_uri(busnum, devnum, uri, HPMUD_BUFFER_SIZE, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, uri, bytes_read);
+}
+
+#ifdef HAVE_LIBNETSNMP
+static PyObject *make_net_uri(PyObject *self, PyObject *args)
+{
+ char * ip;
+ int port;
+ char uri[HPMUD_BUFFER_SIZE];
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ int bytes_read = 0;
+
+ if (!PyArg_ParseTuple(args, "si", &ip, &port))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_make_net_uri(ip, port, uri, HPMUD_BUFFER_SIZE, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, uri, bytes_read);
+}
+#else
+static PyObject *make_net_uri(PyObject *self, PyObject *args)
+{
+ return Py_BuildValue("(is#)", HPMUD_R_INVALID_URI, "", 0);
+}
+#endif /* HAVE_LIBSNMP */
+
+#ifdef HAVE_LIBNETSNMP
+static PyObject *make_zc_uri(PyObject *self, PyObject *args)
+{
+ char *hn;
+ int port;
+ char uri[HPMUD_BUFFER_SIZE];
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ int bytes_read = 0;
+
+ if (!PyArg_ParseTuple(args, "si", &hn, &port))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_make_mdns_uri(hn, port, uri, HPMUD_BUFFER_SIZE, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, uri, bytes_read);
+}
+#else
+static PyObject *make_zc_uri(PyObject *self, PyObject *args)
+{
+ return Py_BuildValue("(is#)", HPMUD_R_INVALID_URI, "", 0);
+}
+#endif /* HAVE_LIBSNMP */
+
+#ifdef HAVE_LIBNETSNMP
+static PyObject *get_zc_ip_address(PyObject *self, PyObject *args)
+{
+ char *hn;
+ char ip[HPMUD_BUFFER_SIZE];
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+
+ if (!PyArg_ParseTuple(args, "s", &hn))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_mdns_lookup(hn, HPMUD_MDNS_TIMEOUT, ip);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is)", result, ip);
+}
+#else
+static PyObject *get_zc_ip_address(PyObject *self, PyObject *args)
+{
+ return Py_BuildValue("(is)", HPMUD_R_INVALID_URI, "");
+}
+#endif /* HAVE_LIBSNMP */
+
+#ifdef HAVE_PPORT
+static PyObject *make_par_uri(PyObject *self, PyObject *args)
+{
+ char * devnode;
+ char uri[HPMUD_BUFFER_SIZE];
+ enum HPMUD_RESULT result = HPMUD_R_OK;
+ int bytes_read = 0;
+
+ if (!PyArg_ParseTuple(args, "s", &devnode))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ result = hpmud_make_par_uri(devnode, uri, HPMUD_BUFFER_SIZE, &bytes_read);
+ Py_END_ALLOW_THREADS
+
+ return Py_BuildValue("(is#)", result, uri, bytes_read);
+}
+#else
+static PyObject *make_par_uri(PyObject *self, PyObject *args)
+{
+ return Py_BuildValue("(is#)", HPMUD_R_INVALID_URI, "", 0);
+}
+#endif /* HAVE_PPORT */
+
+// Unwrapped MUD APIs:
+// int hpmud_get_model(const char *id, char *buf, int buf_size);
+// int hpmud_get_uri_model(const char *uri, char *buf, int buf_size);
+// int hpmud_get_uri_datalink(const char *uri, char *buf, int buf_size);
+// enum HPMUD_RESULT hpmud_get_model_attributes(char *uri, char *attr, int attrSize);
+// enum HPMUD_RESULT hpmud_model_query(char *uri, struct hpmud_model_attributes *ma);
+// enum HPMUD_RESULT hpmud_get_device_status(HPMUD_DEVICE dd, unsigned int *status);
+// enum HPMUD_RESULT hpmud_get_dstat(HPMUD_DEVICE dd, struct hpmud_dstat *ds);
+
+
+static PyMethodDef mudext_functions[] =
+{
+ {"open_device", (PyCFunction)open_device, METH_VARARGS },
+ {"close_device", (PyCFunction)close_device, METH_VARARGS },
+ {"get_device_id", (PyCFunction)get_device_id, METH_VARARGS },
+ {"probe_devices", (PyCFunction)probe_devices, METH_VARARGS },
+ {"open_channel", (PyCFunction)open_channel, METH_VARARGS },
+ {"write_channel", (PyCFunction)write_channel, METH_VARARGS },
+ {"read_channel", (PyCFunction)read_channel, METH_VARARGS },
+ {"close_channel", (PyCFunction)close_channel, METH_VARARGS },
+ {"set_pml", (PyCFunction)set_pml, METH_VARARGS },
+ {"get_pml", (PyCFunction)get_pml, METH_VARARGS },
+ {"make_usb_uri", (PyCFunction)make_usb_uri, METH_VARARGS },
+ {"make_net_uri", (PyCFunction)make_net_uri, METH_VARARGS },
+ {"make_zc_uri", (PyCFunction)make_zc_uri, METH_VARARGS },
+ {"get_zc_ip_address", (PyCFunction)get_zc_ip_address, METH_VARARGS },
+ {"make_par_uri", (PyCFunction)make_par_uri, METH_VARARGS },
+ { NULL, NULL }
+};
+
+
+static char mudext_documentation[] = "Python extension for HP multi-point transport driver";
+
+static void insint(PyObject *d, char *name, int value)
+{
+ PyObject *v = PyInt_FromLong((long) value);
+
+ if (!v || PyDict_SetItemString(d, name, v))
+ Py_FatalError("Initialization failed.");
+
+ Py_DECREF(v);
+}
+
+static void insstr(PyObject *d, char *name, char *value)
+{
+ PyObject *v = PyString_FromString(value);
+
+ if (!v || PyDict_SetItemString(d, name, v))
+ Py_FatalError("Initialization failed.");
+
+ Py_DECREF(v);
+}
+
+
+void inithpmudext(void)
+{
+ PyObject *mod = Py_InitModule3("hpmudext", mudext_functions, mudext_documentation);
+
+ if (mod == NULL)
+ return;
+
+ PyObject * d = PyModule_GetDict(mod);
+
+ // enum HPMUD_RESULT
+ insint(d, "HPMUD_R_OK", HPMUD_R_OK);
+ insint(d, "HPMUD_R_INVALID_DEVICE", HPMUD_R_INVALID_DEVICE);
+ insint(d, "HPMUD_R_INVALID_DESCRIPTOR", HPMUD_R_INVALID_DESCRIPTOR);
+ insint(d, "HPMUD_R_INVALID_URI", HPMUD_R_INVALID_URI);
+ insint(d, "HPMUD_R_INVALID_LENGTH", HPMUD_R_INVALID_LENGTH);
+ insint(d, "HPMUD_R_IO_ERROR", HPMUD_R_IO_ERROR);
+ insint(d, "HPMUD_R_DEVICE_BUSY", HPMUD_R_DEVICE_BUSY);
+ insint(d, "HPMUD_R_INVALID_SN", HPMUD_R_INVALID_SN);
+ insint(d, "HPMUD_R_INVALID_CHANNEL_ID", HPMUD_R_INVALID_CHANNEL_ID);
+ insint(d, "HPMUD_R_INVALID_STATE", HPMUD_R_INVALID_STATE);
+ insint(d, "HPMUD_R_INVALID_DEVICE_OPEN", HPMUD_R_INVALID_DEVICE_OPEN);
+ insint(d, "HPMUD_R_INVALID_DEVICE_NODE", HPMUD_R_INVALID_DEVICE_NODE);
+ insint(d, "HPMUD_R_INVALID_IP", HPMUD_R_INVALID_IP);
+ insint(d, "HPMUD_R_INVALID_IP_PORT", HPMUD_R_INVALID_IP_PORT);
+ insint(d, "HPMUD_R_INVALID_TIMEOUT", HPMUD_R_INVALID_TIMEOUT);
+ insint(d, "HPMUD_R_DATFILE_ERROR", HPMUD_R_DATFILE_ERROR);
+ insint(d, "HPMUD_R_IO_TIMEOUT", HPMUD_R_IO_TIMEOUT);
+
+ // enum HPMUD_IO_MODE
+ insint(d, "HPMUD_UNI_MODE", HPMUD_UNI_MODE);
+ insint(d, "HPMUD_RAW_MODE",HPMUD_RAW_MODE);
+ insint(d, "HPMUD_DOT4_MODE", HPMUD_DOT4_MODE);
+ insint(d, "HPMUD_DOT4_PHOENIX_MODE", HPMUD_DOT4_PHOENIX_MODE);
+ insint(d, "HPMUD_DOT4_BRIDGE_MODE", HPMUD_DOT4_BRIDGE_MODE);
+ insint(d, "HPMUD_MLC_GUSHER_MODE", HPMUD_MLC_GUSHER_MODE);
+ insint(d, "HPMUD_MLC_MISER_MODE", HPMUD_MLC_MISER_MODE);
+
+ // enum HPMUD_BUS_ID
+ insint(d, "HPMUD_BUS_NA", HPMUD_BUS_NA);
+ insint(d, "HPMUD_BUS_USB", HPMUD_BUS_USB);
+ insint(d, "HPMUD_BUS_PARALLEL", HPMUD_BUS_PARALLEL);
+ insint(d, "HPMUD_BUS_ALL", HPMUD_BUS_ALL);
+
+ // Channel names
+ insstr(d, "HPMUD_S_PRINT_CHANNEL", HPMUD_S_PRINT_CHANNEL);
+ insstr(d, "HPMUD_S_PML_CHANNEL", HPMUD_S_PML_CHANNEL);
+ insstr(d, "HPMUD_S_SCAN_CHANNEL", HPMUD_S_SCAN_CHANNEL);
+ insstr(d, "HPMUD_S_FAX_SEND_CHANNEL", HPMUD_S_FAX_SEND_CHANNEL);
+ insstr(d, "HPMUD_S_CONFIG_UPLOAD_CHANNEL", HPMUD_S_CONFIG_UPLOAD_CHANNEL);
+ insstr(d, "HPMUD_S_CONFIG_DOWNLOAD_CHANNEL", HPMUD_S_CONFIG_DOWNLOAD_CHANNEL);
+ insstr(d, "HPMUD_S_MEMORY_CARD_CHANNEL", HPMUD_S_MEMORY_CARD_CHANNEL);
+ insstr(d, "HPMUD_S_EWS_CHANNEL", HPMUD_S_EWS_CHANNEL);
+ insstr(d, "HPMUD_S_EWS_LEDM_CHANNEL", HPMUD_S_EWS_LEDM_CHANNEL);
+ insstr(d, "HPMUD_S_SOAP_SCAN", HPMUD_S_SOAP_SCAN);
+ insstr(d, "HPMUD_S_SOAP_FAX", HPMUD_S_SOAP_FAX);
+ insstr(d, "HPMUD_S_DEVMGMT_CHANNEL", HPMUD_S_DEVMGMT_CHANNEL);
+ insstr(d, "HPMUD_S_WIFI_CHANNEL", HPMUD_S_WIFI_CHANNEL);
+ insstr(d, "HPMUD_S_MARVELL_FAX_CHANNEL", HPMUD_S_MARVELL_FAX_CHANNEL);
+ insstr(d, "HPMUD_S_LEDM_SCAN", HPMUD_S_LEDM_SCAN);
+
+ // Max buffer size
+ insint(d, "HPMUD_BUFFER_SIZE", HPMUD_BUFFER_SIZE);
+
+}
+
+