Tizen 2.1 base
[platform/upstream/hplip.git] / io / hpmud / dot4.c
1 /*****************************************************************************\
2
3   dot4.c - 1284.4 support multi-point tranport driver  
4  
5   (c) 2005-2007 Copyright Hewlett-Packard Development Company, LP
6
7   Permission is hereby granted, free of charge, to any person obtaining a copy 
8   of this software and associated documentation files (the "Software"), to deal 
9   in the Software without restriction, including without limitation the rights 
10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
11   of the Software, and to permit persons to whom the Software is furnished to do 
12   so, subject to the following conditions:
13
14   The above copyright notice and this permission notice shall be included in all
15   copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
19   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
20   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
21   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 \*****************************************************************************/
25
26 #include "hpmud.h"
27 #include "hpmudi.h"
28
29 /*
30  * This 1284.4 implementation does not support "Multiple Outstanding Transactions" which is optional.
31  */
32
33 /* Write command reply back to peripheral. */
34 static int Dot4ForwardReply(mud_channel *pc, int fd, unsigned char *buf, int size)
35 {
36    mud_device *pd = &msp->device[pc->dindex];
37    int len=0;
38
39    if ((len = (pd->vf.write)(fd, buf, size, HPMUD_EXCEPTION_TIMEOUT)) != size)
40    {
41       BUG("unable to Dot4ForwarReply: %m\n");
42    }   
43    return len;
44 }
45
46 /* Execute command from peripheral. */
47 static int Dot4ExecReverseCmd(mud_channel *pc, int fd, unsigned char *buf)
48 {
49    mud_device *pd = &msp->device[pc->dindex];
50    mud_channel *out_of_bound_channel;
51    DOT4Cmd *pCmd;
52    DOT4Reply *pReply;
53    DOT4Credit *pCredit;
54    DOT4CreditReply *pCreditReply;
55    DOT4CreditRequest *pCreditReq;
56    DOT4CreditRequestReply *pCreditReqReply;
57    DOT4Error *pError;
58    int len, size;
59    unsigned char socket;
60    static int cnt;
61
62    pCmd = (DOT4Cmd *)buf;
63
64    /* See if this packet is a command packet. */
65    if (!(pCmd->h.psid == 0 && pCmd->h.ssid == 0))
66    {
67       if (pCmd->h.psid == pCmd->h.ssid)
68       {
69          /* Got a valid data packet handle it. This can happen when channel_read timeouts and p2hcredit=1. */
70          out_of_bound_channel = &pd->channel[pCmd->h.psid];
71
72          if (out_of_bound_channel->ta.p2hcredit <= 0)
73          {
74             BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
75             return 0;
76          }
77
78          size = ntohs(pCmd->h.length) - sizeof(DOT4Header);
79          if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
80          {
81             BUG("invalid data packet size=%d\n", size);
82             return 0;
83          }
84          memcpy(&out_of_bound_channel->rbuf[out_of_bound_channel->rcnt], buf+sizeof(MLCHeader), size);
85          out_of_bound_channel->rcnt += size;
86          if (pCmd->h.credit)
87             out_of_bound_channel->ta.h2pcredit += pCmd->h.credit;  /* note, piggy back credit is 1 byte wide */ 
88          out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
89       }
90       else
91       {
92          len = ntohs(pCmd->h.length);
93          BUG("unsolicited data packet: psid=%x, ssid=%x, length=%d, credit=%d, status=%x\n", pCmd->h.psid,
94                                      pCmd->h.ssid, len, pCmd->h.credit, pCmd->h.control);
95          DBG_DUMP(buf, len);
96       }
97       return 0;  
98    }
99
100    /* Process any command. */
101    switch (pCmd->cmd)
102    {
103       case DOT4_CREDIT:
104          pCredit = (DOT4Credit *)buf;
105          out_of_bound_channel = &pd->channel[pCredit->psocket];
106          out_of_bound_channel->ta.h2pcredit += ntohs(pCredit->credit);
107          pCreditReply = (DOT4CreditReply *)buf;
108          pCreditReply->h.length = htons(sizeof(DOT4CreditReply));
109          pCreditReply->h.credit = 1;       /* transaction credit for next command */
110          pCreditReply->h.control = 0;
111          pCreditReply->cmd |= 0x80;
112          pCreditReply->result = 0;
113          pCreditReply->psocket = out_of_bound_channel->sockid;
114          pCreditReply->ssocket = out_of_bound_channel->sockid;
115          Dot4ForwardReply(pc, fd, (unsigned char *)pCreditReply, sizeof(DOT4CreditReply)); 
116          break;
117       case DOT4_CREDIT_REQUEST:
118          pCreditReq = (DOT4CreditRequest *)buf;
119          if (cnt++ < 5)         
120             BUG("unexpected DOT4CreditRequest: cmd=%x, hid=%x, pid=%x, maxcredit=%d\n", pCreditReq->cmd,
121                                          pCreditReq->psocket, pCreditReq->ssocket, ntohs(pCreditReq->maxcredit));
122          socket = pCreditReq->ssocket;
123          pCreditReqReply = (DOT4CreditRequestReply *)buf;
124          pCreditReqReply->h.length = htons(sizeof(DOT4CreditRequestReply));
125          pCreditReqReply->h.credit = 1;       /* transaction credit for next command */
126          pCreditReqReply->h.control = 0;
127          pCreditReqReply->cmd |= 0x80;
128          pCreditReqReply->result = 0;
129          pCreditReqReply->psocket = socket;
130          pCreditReqReply->ssocket = socket;
131          pCreditReqReply->credit = 0;
132          Dot4ForwardReply(pc, fd, (unsigned char *)pCreditReqReply, sizeof(DOT4CreditRequestReply)); 
133          break;
134       case DOT4_ERROR:
135          pError = (DOT4Error *)buf;
136          BUG("unexpected DOT4Error: cmd=%x, psocket=%d, ssocket=%d, error=%x\n", pError->cmd, pError->psocket, pError->ssocket, pError->error);
137          return 1;
138       default:
139          pReply = (DOT4Reply *)buf;
140          BUG("unexpected command: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
141          pReply->h.length = htons(sizeof(DOT4Reply));
142          pReply->h.credit = 1;       /* transaction credit for next command */
143          pReply->h.control = 0;
144          pReply->cmd |= 0x80;
145          pReply->result = 1;
146          Dot4ForwardReply(pc, fd, (unsigned char *)pReply, sizeof(DOT4Reply)); 
147          break;
148    }
149    return 0;
150 }
151
152 /* Get command from peripheral and processes the reverse command. */
153 int __attribute__ ((visibility ("hidden"))) Dot4ReverseCmd(mud_channel *pc, int fd)
154 {
155    mud_device *pd = &msp->device[pc->dindex];
156    unsigned char buf[HPMUD_BUFFER_SIZE];   
157    int stat=0, len, size;
158    unsigned int pklen;
159    unsigned char *pBuf;
160    DOT4Reply *pPk;
161
162    pPk = (DOT4Reply *)buf;
163
164    pBuf = buf;
165
166    /* Read packet header. */
167    size = sizeof(DOT4Header);
168    while (size > 0)
169    {
170       if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
171       {
172          BUG("unable to read Dot4ReverseCmd header: %m\n");
173          stat = 1;
174          goto bugout;
175       }
176       size-=len;
177       pBuf+=len;
178    }
179
180    /* Determine packet size. */
181    if ((pklen = ntohs(pPk->h.length)) > sizeof(buf))
182    {
183       BUG("invalid Dot4ReverseCmd packet size: size=%d\n", pklen);
184       stat = 1;
185       goto bugout;
186    }
187
188    /* Read packet data field. */
189    size = pklen - sizeof(DOT4Header);
190    while (size > 0)
191    {
192       if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
193       {
194          BUG("unable to read Dot4ReverseCmd data: %m exp=%zd act=%zd\n", pklen-sizeof(DOT4Header), pklen-sizeof(DOT4Header)-size);
195          stat = 1;
196          goto bugout;
197       }
198       size-=len;
199       pBuf+=len;
200    }
201
202    stat = Dot4ExecReverseCmd(pc, fd, buf);
203
204 bugout:
205    return stat;
206 }
207
208 /*
209  * Get command reply from peripheral. Waits for reply then returns. Processes any reverse commands
210  * while waiting for a reply.
211  */
212 static int Dot4ReverseReply(mud_channel *pc, int fd, unsigned char *buf, int bufsize)
213 {
214    mud_device *pd = &msp->device[pc->dindex];
215    int stat=0, len, size, pklen;
216    unsigned char *pBuf;
217    DOT4Reply *pPk;
218
219    pPk = (DOT4Reply *)buf;
220    
221    while (1)
222    {
223       pBuf = buf;
224
225       /* Read packet header. */
226       size = sizeof(DOT4Header);
227       while (size > 0)
228       {
229          if ((len = (pd->vf.read)(fd, pBuf, size, 4000000)) < 0)   /* wait 4 seconds, 2 fails on PS2575 1200dpi uncompressed scanning  */
230          {
231             BUG("unable to read Dot4ReverseReply header: %m bytesRead=%zd\n", sizeof(DOT4Header)-size);
232             stat = 2;  /* short timeout */
233             goto bugout;
234          }
235          size-=len;
236          pBuf+=len;
237       }
238
239       /* Determine packet size. */
240       pklen = ntohs(pPk->h.length);
241       if (pklen <= 0 || pklen > bufsize)
242       {
243          BUG("invalid Dot4ReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
244          stat = 1;
245          goto bugout;
246       }
247
248       /* Read packet data field. */
249       size = pklen - sizeof(DOT4Header);
250       while (size > 0)
251       {
252          if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
253          {
254             BUG("unable to read Dot4ReverseReply data: %m exp=%zd act=%zd\n", pklen-sizeof(DOT4Header), pklen-sizeof(DOT4Header)-size);
255             stat = 1;
256             goto bugout;
257          }
258          size-=len;
259          pBuf+=len;
260       }
261
262       /* Check for reply. */
263       if (pPk->cmd & 0x80)
264          break;
265
266       stat = Dot4ExecReverseCmd(pc, fd, buf);
267
268       if (stat != 0)
269          break;
270
271    } /* while (1) */
272
273 bugout:
274    return stat;
275 }
276
277 int __attribute__ ((visibility ("hidden"))) Dot4Init(mud_channel *pc, int fd)
278 {
279    mud_device *pd = &msp->device[pc->dindex];
280    unsigned char buf[HPMUD_BUFFER_SIZE];
281    int stat=0, len, n, cnt;
282    DOT4Init *pCmd;
283    DOT4InitReply *pReply;
284
285    memset(buf, 0, sizeof(DOT4Init));
286    pCmd = (DOT4Init *)buf;
287    n = sizeof(DOT4Init);
288    pCmd->h.length = htons(n);
289    pCmd->h.credit = 1;       /* transaction credit for reply */
290    pCmd->cmd = DOT4_INIT;
291    pCmd->rev = 0x20;
292    
293    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
294    {
295       BUG("unable to write DOT4Init: %m\n");
296       stat = 1;
297       goto bugout;
298    }
299
300    cnt=0;
301    while(1)
302    {
303       stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
304       pReply = (DOT4InitReply *)buf;
305
306       if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_INIT)) || (pReply->result != 0))
307       {
308          if (errno == EIO && cnt<1)
309          {
310             /* hack for usblp.c 2.6.5 */
311             BUG("invalid DOT4InitReply retrying...\n");
312             sleep(1);   
313             cnt++;
314             continue;
315          }
316          if (stat == 2 && cnt<1)
317          {
318             /* hack for Fullhouse, Swami and Northstar */
319             BUG("invalid DOT4InitReply retrying command...\n");
320             memset(buf, 0, sizeof(DOT4Init));
321             n = sizeof(DOT4Init);
322             pCmd->h.length = htons(n);
323             pCmd->h.credit = 1;       /* transaction credit for reply */
324             pCmd->cmd = DOT4_INIT;
325             pCmd->rev = 0x20;
326             (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT);
327             cnt++;
328             continue;
329          }
330          BUG("invalid DOT4InitReply: cmd=%x, result=%x\n, revision=%x\n", pReply->cmd, pReply->result, pReply->rev);
331          stat = 1;
332          goto bugout;
333       }
334       break;
335    }
336
337 bugout:
338    return stat;
339 }
340
341 int __attribute__ ((visibility ("hidden"))) Dot4Exit(mud_channel *pc, int fd)
342 {
343    mud_device *pd = &msp->device[pc->dindex];
344    unsigned char buf[HPMUD_BUFFER_SIZE];
345    int stat=0, len, n;
346    DOT4Exit *pCmd;
347    DOT4ExitReply *pReply;
348
349    memset(buf, 0, sizeof(DOT4Exit));
350    pCmd = (DOT4Exit *)buf;
351    n = sizeof(DOT4Exit);
352    pCmd->h.length = htons(n);
353    pCmd->h.credit = 1;
354    pCmd->cmd = DOT4_EXIT;
355    
356    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
357    {
358       BUG("unable to write DOT4Exit: %m\n");
359       stat = 1;
360       goto bugout;
361    }
362
363    stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
364    pReply = (DOT4ExitReply *)buf;
365
366    if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_EXIT)) || (pReply->result != 0))
367    {
368       BUG("invalid DOT4ExitReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
369       stat = 1;
370       goto bugout;
371    }
372
373 bugout:
374    return stat;
375 }
376
377 int __attribute__ ((visibility ("hidden"))) Dot4GetSocket(mud_channel *pc, int fd)
378 {
379    mud_device *pd = &msp->device[pc->dindex];
380    unsigned char buf[HPMUD_BUFFER_SIZE];
381    int stat=0, len, n;
382    DOT4GetSocket *pCmd;
383    DOT4GetSocketReply *pReply;
384
385    memset(buf, 0, sizeof(DOT4GetSocket));
386    pCmd = (DOT4GetSocket *)buf;
387    n = sizeof(DOT4GetSocket);
388    len = strlen(pc->sn);
389    memcpy(buf+sizeof(DOT4GetSocket), pc->sn, len);
390    n += len;
391    pCmd->h.length = htons(n);
392    pCmd->h.credit = 1;
393    pCmd->cmd = DOT4_GET_SOCKET;
394    
395    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
396    {
397       BUG("unable to write DOT4GetSocket: %m\n");
398       stat = 1;
399       goto bugout;
400    }
401
402    stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
403    pReply = (DOT4GetSocketReply *)buf;
404
405    if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_GET_SOCKET)) || (pReply->result != 0))
406    {
407       BUG("invalid DOT4GetSocketReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
408       stat = 1;
409       goto bugout;
410    }
411
412    pc->sockid = pReply->socket;
413
414    if (pc->sockid != pc->index)
415       BUG("invalid sockid match sockid=%d index=%d\n", pc->sockid, pc->index);
416
417 bugout:
418    return stat;
419 }
420
421 /* Write data to peripheral. */
422 int __attribute__ ((visibility ("hidden"))) Dot4ForwardData(mud_channel *pc, int fd, const void *buf, int size, int usec_timeout)
423 {
424    mud_device *pd = &msp->device[pc->dindex];
425    int stat=0, len, n;
426    DOT4Header h;
427
428    memset(&h, 0, sizeof(h));
429    n = sizeof(DOT4Header) + size;
430    h.length = htons(n);
431    h.psid = pc->sockid;
432    h.ssid = pc->sockid;
433       
434    if ((len = (pd->vf.write)(fd, &h, sizeof(DOT4Header), usec_timeout)) != sizeof(DOT4Header))
435    {
436       BUG("unable to write Dot4ForwardData header: %m\n");
437       stat = 1;
438       goto bugout;
439    }
440
441    if ((len = (pd->vf.write)(fd, buf, size, usec_timeout)) != size)
442    {
443       BUG("unable to write Dot4ForwardData: %m\n");
444       stat = 1;
445       goto bugout;
446    }
447
448 bugout:
449    return stat;
450 }
451
452 /* Read data from peripheral. */
453 int __attribute__ ((visibility ("hidden"))) Dot4ReverseData(mud_channel *pc, int fd, void *buf, int length, int usec_timeout)
454 {
455    mud_device *pd = &msp->device[pc->dindex];
456    mud_channel *out_of_bound_channel;
457    int len, size, total;
458    DOT4Header *pPk;
459
460    pPk = (DOT4Header *)buf;
461
462    while (1)
463    {
464       total = 0;
465
466       /* Read packet header. */
467       size = sizeof(DOT4Header);
468       while (size > 0)
469       {
470          /* Use requested client timeout until we start reading. */
471          if (total == 0)
472             len = (pd->vf.read)(fd, buf+total, size, usec_timeout);
473          else
474             len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT);
475
476          if (len < 0)
477          {
478             /* Got a timeout, if exception timeout or timeout occured after read started thats an error. */
479             if (usec_timeout >= HPMUD_EXCEPTION_TIMEOUT || total > 0)
480                BUG("unable to read Dot4ReverseData header: %m %s\n", pd->uri);
481             goto bugout;
482          }
483          size-=len;
484          total+=len;
485       }
486
487       /* Determine data size. */
488       size = ntohs(pPk->length) - sizeof(DOT4Header);
489
490       if (size > length)
491       {
492          BUG("invalid Dot4ReverseData size: size=%d, buf=%d\n", size, length);
493          goto bugout;
494       } 
495
496       /* Make sure data packet is for this channel. */
497       if (pPk->psid != pc->sockid && pPk->ssid != pc->sockid)
498       {
499          if (pPk->psid == 0 && pPk->ssid == 0)
500          {
501             /* Ok, got a command channel packet instead of a data packet, handle it... */
502             while (size > 0)
503             {
504                if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
505                {
506                   BUG("unable to read Dot4ReverseData command: %m\n");
507                   goto bugout;
508                }
509                size-=len;
510                total=len;
511             }
512             Dot4ExecReverseCmd(pc, fd, buf);
513             continue;   /* try again for data packet */
514          }
515          else if (pPk->psid == pPk->ssid)
516          {
517             /* Got a valid data packet for another channel handle it. This can happen when ReadData timeouts and p2hcredit=1. */
518             out_of_bound_channel = &pd->channel[pPk->psid];
519             unsigned char *pBuf;
520
521             if (out_of_bound_channel->ta.p2hcredit <= 0)
522             {
523                BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
524                goto bugout;
525             }
526
527             if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
528             {
529                BUG("invalid data packet size=%d\n", size);
530                goto bugout;
531             }
532             
533             total = 0;
534             pBuf = &out_of_bound_channel->rbuf[out_of_bound_channel->rcnt];
535             while (size > 0)
536             {
537                if ((len = (pd->vf.read)(fd, pBuf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
538                {
539                   BUG("unable to read MlcReverseData: %m\n");
540                   goto bugout;
541                }
542                size-=len;
543                total+=len;
544             }
545
546             out_of_bound_channel->rcnt += total;
547             if (pPk->credit)
548                out_of_bound_channel->ta.h2pcredit += pPk->credit;  /* note, piggy back credit is 1 byte wide */ 
549             out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
550             continue;   /* try again for data packet */
551          }
552          else
553          {
554             DOT4Cmd *pCmd = (DOT4Cmd *)buf;
555             BUG("invalid Dot4ReverseData state: unexpected packet psid=%x, ssid=%x, cmd=%x\n", pPk->psid, pPk->ssid, pCmd->cmd);
556             goto bugout;
557          }
558       }
559
560       if (pPk->credit)
561       {
562          pc->ta.h2pcredit += pPk->credit;  /* note, piggy back credit is 1 byte wide */ 
563       }
564
565       total = 0;  /* eat packet header */
566    
567       /* Read packet data field with exception_timeout. */
568       while (size > 0)
569       {
570          if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
571          {
572             BUG("unable to read Dot4ReverseData: %m\n");
573             goto bugout;
574          }
575          size-=len;
576          total+=len;
577       }
578       break; /* done reading data packet */
579    }  /* while (1) */
580
581 bugout:
582    return total;
583 }
584
585 int __attribute__ ((visibility ("hidden"))) Dot4OpenChannel(mud_channel *pc, int fd)
586 {
587    mud_device *pd = &msp->device[pc->dindex];
588    unsigned char buf[HPMUD_BUFFER_SIZE];
589    int stat=0, len, n;
590    DOT4OpenChannel *pCmd;
591    DOT4OpenChannelReply *pReply;
592
593    memset(buf, 0, sizeof(DOT4OpenChannel));
594    pCmd = (DOT4OpenChannel *)buf;
595    n = sizeof(DOT4OpenChannel);
596    pCmd->h.length = htons(n);
597    pCmd->h.credit = 1;
598    pCmd->cmd = DOT4_OPEN_CHANNEL;
599    pCmd->psocket = pc->sockid;
600    pCmd->ssocket = pc->sockid;
601    pCmd->maxp2s = htons(HPMUD_BUFFER_SIZE);  /* max primary to secondary packet size in bytes */
602    pCmd->maxs2p = htons(HPMUD_BUFFER_SIZE);  /* max secondary to primary packet size in bytes */
603    pCmd->maxcredit = htons(0xffff);          /* "unlimited credit" mode, give primary (sender) as much credit as possible */
604    
605    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
606    {
607       BUG("unable to write Dot4OpenChannel: %m\n");
608       stat = 1;
609       goto bugout;
610    }
611
612    stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
613    pReply = (DOT4OpenChannelReply *)buf;
614
615    if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_OPEN_CHANNEL)) || (pReply->result != 0))
616    {
617       BUG("invalid Dot4OpenChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
618       stat = 1;
619       goto bugout;
620    }
621
622    pc->ta.h2psize = ntohs(pReply->maxp2s);
623    pc->ta.p2hsize = ntohs(pReply->maxs2p);
624    pc->ta.h2pcredit = ntohs(pReply->credit);
625
626 bugout:
627    return stat;
628 }
629
630 int __attribute__ ((visibility ("hidden"))) Dot4CloseChannel(mud_channel *pc, int fd)
631 {
632    mud_device *pd = &msp->device[pc->dindex];
633    unsigned char buf[HPMUD_BUFFER_SIZE];
634    int stat=0, len, n;
635    DOT4CloseChannel *pCmd;
636    DOT4CloseChannelReply *pReply;
637
638    memset(buf, 0, sizeof(DOT4CloseChannel));
639    pCmd = (DOT4CloseChannel *)buf;
640    n = sizeof(DOT4CloseChannel);
641    pCmd->h.length = htons(n);
642    pCmd->h.credit = 1;
643    pCmd->cmd = DOT4_CLOSE_CHANNEL;
644    pCmd->psocket = pc->sockid;
645    pCmd->ssocket = pc->sockid;
646
647    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
648    {
649       BUG("unable to write Dot4CloseChannel: %m\n");
650       stat = 1;
651       goto bugout;
652    }
653
654    stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
655    pReply = (DOT4CloseChannelReply *)buf;
656
657    if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_CLOSE_CHANNEL)) || (pReply->result != 0))
658    {
659       BUG("invalid Dot4CloseChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
660       stat = 1;
661       goto bugout;
662    }
663
664 bugout:
665    return stat;
666 }
667
668 int __attribute__ ((visibility ("hidden"))) Dot4Credit(mud_channel *pc, int fd, unsigned short credit)
669 {
670    mud_device *pd = &msp->device[pc->dindex];
671    unsigned char buf[HPMUD_BUFFER_SIZE];
672    int stat=0, len, n;
673    DOT4Credit *pCmd;
674    DOT4CreditReply *pReply;
675
676    memset(buf, 0, sizeof(DOT4Credit));
677    pCmd = (DOT4Credit *)buf;
678    n = sizeof(DOT4Credit);
679    pCmd->h.length = htons(n);
680    pCmd->h.credit = 1;
681    pCmd->cmd = DOT4_CREDIT;
682    pCmd->psocket = pc->sockid;
683    pCmd->ssocket = pc->sockid;
684    pCmd->credit = htons(credit);                /* set peripheral to host credit */
685    
686    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
687    {
688       BUG("unable to write Dot4Credit: %m\n");
689       stat = 1;
690       goto bugout;
691    }
692
693    stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
694    pReply = (DOT4CreditReply *)buf;
695
696    if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_CREDIT)) || (pReply->result != 0))
697    {
698       BUG("invalid Dot4CreditReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
699       stat = 1;
700       goto bugout;
701    }
702
703    pc->ta.p2hcredit += credit;
704
705 bugout:
706    return stat;
707 }
708
709 int __attribute__ ((visibility ("hidden"))) Dot4CreditRequest(mud_channel *pc, int fd, unsigned short credit)
710 {
711    mud_device *pd = &msp->device[pc->dindex];
712    unsigned char buf[HPMUD_BUFFER_SIZE];
713    int stat=0, len, n;
714    DOT4CreditRequest *pCmd;
715    DOT4CreditRequestReply *pReply;
716
717    memset(buf, 0, sizeof(DOT4CreditRequest));
718    pCmd = (DOT4CreditRequest *)buf;
719    n = sizeof(DOT4CreditRequest);
720    pCmd->h.length = htons(n);
721    pCmd->h.credit = 1;
722    pCmd->cmd = DOT4_CREDIT_REQUEST;
723    pCmd->psocket = pc->sockid;
724    pCmd->ssocket = pc->sockid;
725    //   pCmd->maxcredit = htons(credit);                /* request host to peripheral credit */
726    pCmd->maxcredit = htons(0xffff);                /* request host to peripheral credit */
727    
728    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
729    {
730       BUG("unable to write Dot4CreditRequest: %m\n");
731       stat = 1;
732       goto bugout;
733    }
734
735    stat = Dot4ReverseReply(pc, fd, buf, sizeof(buf));
736    pReply = (DOT4CreditRequestReply *)buf;
737
738    if ((stat != 0) || (pReply->cmd != (0x80 | DOT4_CREDIT_REQUEST)) || (pReply->result != 0))
739    {
740       BUG("invalid Dot4CreditRequestReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
741       stat = 1;
742       goto bugout;
743    }
744
745    pc->ta.h2pcredit += ntohs(pReply->credit);
746
747 bugout:
748    return stat;
749 }
750