Tizen 2.1 base
[platform/upstream/hplip.git] / io / hpmud / mlc.c
1 /*****************************************************************************\
2
3   mlc.c - MLC support for multi-point tranport driver
4  
5   (c) 2004-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 int __attribute__ ((visibility ("hidden"))) cut_buf(mud_channel *pc, char *buf, int size)
30 {
31    int len;
32
33    if (pc->rcnt > size)
34    {
35       /* Return part of rbuf. */
36       len = size;
37       memcpy(buf, &pc->rbuf[pc->rindex], len);
38       pc->rindex += len;
39       pc->rcnt -= len;
40    }
41    else
42    {
43       /* Return all of rbuf. */
44       len = pc->rcnt;
45       memcpy(buf, &pc->rbuf[pc->rindex], len);
46       pc->rindex = pc->rcnt = 0;
47    }
48
49    return len;
50
51
52 /* Write command reply back to peripheral. */
53 static int MlcForwardReply(mud_channel *pc, int fd, unsigned char *buf, int size)
54 {
55    mud_device *pd = &msp->device[pc->dindex];
56    int len=0;
57
58    if ((len = (pd->vf.write)(fd, buf, size, HPMUD_EXCEPTION_TIMEOUT)) != size)
59    {
60       BUG("unable to MlcForwarReply: %m\n");
61    }   
62    return len;
63 }
64
65 /* Execute command from peripheral. */
66 static int MlcExecReverseCmd(mud_channel *pc, int fd, unsigned char *buf)
67 {
68    mud_device *pd = &msp->device[pc->dindex];
69    mud_channel *out_of_bound_channel;
70    MLCCmd *pCmd;
71    MLCReply *pReply;
72    MLCCredit *pCredit;
73    MLCCreditReply *pCreditReply;
74    MLCCreditRequest *pCreditReq;
75    MLCCreditRequestReply *pCreditReqReply;
76    MLCError *pError;
77    int len, size;
78    static int cnt;
79
80    pCmd = (MLCCmd *)buf;
81
82    /* See if this packet is a command packet. */
83    if (!(pCmd->h.hsid == 0 && pCmd->h.psid == 0))
84    {
85       if (pCmd->h.hsid == pCmd->h.psid)
86       {
87          /* Got a valid data packet handle it. This can happen when channel_read timeouts and p2hcredit=1. */
88          out_of_bound_channel = &pd->channel[pCmd->h.hsid];
89
90          if (out_of_bound_channel->ta.p2hcredit <= 0)
91          {
92             BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
93             return 0;
94          }
95
96          size = ntohs(pCmd->h.length) - sizeof(MLCHeader);
97          if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
98          {
99             BUG("invalid data packet size=%d\n", size);
100             return 0;
101          }
102          memcpy(&out_of_bound_channel->rbuf[out_of_bound_channel->rcnt], buf+sizeof(MLCHeader), size);
103          out_of_bound_channel->rcnt += size;
104          if (pCmd->h.credit)
105             out_of_bound_channel->ta.h2pcredit += pCmd->h.credit;  /* note, piggy back credit is 1 byte wide */ 
106          out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
107       }
108       else
109       {
110          len = ntohs(pCmd->h.length);
111          BUG("unsolicited data packet: hsid=%x, psid=%x, length=%d, credit=%d, status=%x\n", pCmd->h.hsid,
112                                      pCmd->h.psid, len, pCmd->h.credit, pCmd->h.status);
113          DBG_DUMP(buf, len);
114       }
115       return 0;  
116    }
117
118    /* Process any command. */
119    switch (pCmd->cmd)
120    {
121       case MLC_CREDIT:
122          pCredit = (MLCCredit *)buf;
123          out_of_bound_channel = &pd->channel[pCredit->hsocket];
124          out_of_bound_channel->ta.h2pcredit += ntohs(pCredit->credit);
125          pCreditReply = (MLCCreditReply *)buf;
126          pCreditReply->h.length = htons(sizeof(MLCCreditReply));
127          pCreditReply->cmd |= 0x80;
128          pCreditReply->result = 0;
129          MlcForwardReply(pc, fd, (unsigned char *)pCreditReply, sizeof(MLCCreditReply)); 
130          break;
131       case MLC_CREDIT_REQUEST:
132          pCreditReq = (MLCCreditRequest *)buf;
133          if (cnt++ < 5)         
134             BUG("unexpected MLCCreditRequest: cmd=%x, hid=%x, pid=%x, credit=%d\n", pCreditReq->cmd,
135                                          pCreditReq->hsocket, pCreditReq->psocket, ntohs(pCreditReq->credit));
136          pCreditReqReply = (MLCCreditRequestReply *)buf;
137          pCreditReqReply->h.length = htons(sizeof(MLCCreditRequestReply));
138          pCreditReqReply->cmd |= 0x80;
139          pCreditReqReply->result = 0;
140          pCreditReqReply->credit = 0;
141          MlcForwardReply(pc, fd, (unsigned char *)pCreditReqReply, sizeof(MLCCreditRequestReply)); 
142          break;
143       case MLC_ERROR:
144          pError = (MLCError *)buf;
145          BUG("unexpected MLCError: cmd=%x, result=%x\n", pError->cmd, pError->result);
146          return 1;
147       default:
148          pReply = (MLCReply *)buf;
149          BUG("unexpected command: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
150          pReply->h.length = htons(sizeof(MLCReply));
151          pReply->cmd |= 0x80;
152          pReply->result = 1;
153          MlcForwardReply(pc, fd, (unsigned char *)pReply, sizeof(MLCReply)); 
154          break;
155    }
156    return 0;
157 }
158
159 /* Get command from peripheral and processes the reverse command. */
160 int __attribute__ ((visibility ("hidden"))) MlcReverseCmd(mud_channel *pc, int fd)
161 {
162    mud_device *pd = &msp->device[pc->dindex];
163    unsigned char buf[HPMUD_BUFFER_SIZE];   
164    int stat=0, len, size;
165    unsigned int pklen;
166    unsigned char *pBuf;
167    MLCReply *pPk;
168
169    pPk = (MLCReply *)buf;
170
171    pBuf = buf;
172
173    /* Read packet header. */
174    size = sizeof(MLCHeader);
175    while (size > 0)
176    {
177       if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
178       {
179          BUG("unable to read MlcReverseCmd header: %m\n");
180          stat = 1;
181          goto bugout;
182       }
183       size-=len;
184       pBuf+=len;
185    }
186
187    /* Determine packet size. */
188    if ((pklen = ntohs(pPk->h.length)) > sizeof(buf))
189    {
190       BUG("invalid MlcReverseCmd packet size: size=%d\n", pklen);
191       stat = 1;
192       goto bugout;
193    }
194
195    /* Read packet data field. */
196    size = pklen - sizeof(MLCHeader);
197    while (size > 0)
198    {
199       if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
200       {
201          BUG("unable to read MlcReverseCmd data: %m\n");
202          stat = 1;
203          goto bugout;
204       }
205       size-=len;
206       pBuf+=len;
207    }
208
209    stat = MlcExecReverseCmd(pc, fd, buf);
210
211 bugout:
212    return stat;
213 }
214
215 /*
216  * Get command reply from peripheral. Waits for reply then returns. Processes any reverse commands
217  * while waiting for a reply.
218  */
219 static int MlcReverseReply(mud_channel *pc, int fd, unsigned char *buf, int bufsize)
220 {
221    mud_device *pd = &msp->device[pc->dindex];
222    int stat=0, len, size, pklen;
223    unsigned char *pBuf;
224    MLCReply *pPk;
225
226    pPk = (MLCReply *)buf;
227    
228    while (1)
229    {
230       pBuf = buf;
231
232       /* Read packet header. */
233       size = sizeof(MLCHeader);
234       while (size > 0)
235       {
236          if ((len = (pd->vf.read)(fd, pBuf, size, 4000000)) < 0)   /* wait 4 seconds, same as dot4 */
237          {
238             BUG("unable to read MlcReverseReply header: %m bytesRead=%zd\n", sizeof(MLCHeader)-size);
239             stat = 2;  /* short timeout */
240             goto bugout;
241          }
242          size-=len;
243          pBuf+=len;
244       }
245
246       /* Determine packet size. */
247       pklen = ntohs(pPk->h.length);
248       if (pklen < 0 || pklen > bufsize)
249       {
250          BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
251          stat = 1;
252          goto bugout;
253       }
254
255       if (pklen == 0)
256       {
257          /* Got invalid MLC header from peripheral, try this "off-by-one" firmware hack (ie: OJ600). */
258          BUG("trying MlcReverseReply firmware hack\n");
259          memcpy(buf, &buf[1], sizeof(MLCHeader)-1);
260          pklen = ntohs(pPk->h.length);
261          if (pklen <= 0 || pklen > bufsize)
262          {
263             BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
264             stat = 1;
265             goto bugout;
266          }
267          if ((len = (pd->vf.read)(fd, --pBuf, 1, 1000000)) < 0)   /* wait 1 second */
268          {
269             BUG("unable to read MlcReverseReply header: %m\n");
270             stat = 1;
271             goto bugout;
272          }
273          pBuf++;
274          DBG_DUMP(buf, sizeof(MLCHeader));
275       }
276
277       /* Read packet data field. */
278       size = pklen - sizeof(MLCHeader);
279       while (size > 0)
280       {
281          if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
282          {
283             BUG("unable to read MlcReverseReply data: %m exp=%zd act=%zd\n", pklen-sizeof(MLCHeader), pklen-sizeof(MLCHeader)-size);
284             stat = 1;
285             goto bugout;
286          }
287          size-=len;
288          pBuf+=len;
289       }
290
291       /* Check for reply. */
292       if (pPk->cmd & 0x80)
293          break;
294
295       stat = MlcExecReverseCmd(pc, fd, buf);
296
297       if (stat != 0)
298          break;
299
300    } /* while (1) */
301
302 bugout:
303    return stat;
304 }
305
306 int __attribute__ ((visibility ("hidden"))) MlcInit(mud_channel *pc, int fd)
307 {
308    mud_device *pd = &msp->device[pc->dindex];
309    unsigned char buf[HPMUD_BUFFER_SIZE];
310    int stat=0, len, n, cnt;
311    MLCInit *pCmd;
312    MLCInitReply *pReply;
313
314    memset(buf, 0, sizeof(MLCInit));
315    pCmd = (MLCInit *)buf;
316    n = sizeof(MLCInit);
317    pCmd->h.length = htons(n);
318    pCmd->cmd = MLC_INIT;
319    pCmd->rev = 3;
320    
321    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
322    {
323       BUG("unable to write MLCInit: %m\n");
324       stat = 1;
325       goto bugout;
326    }
327
328    cnt=0;
329    while(1)
330    {
331       stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
332       pReply = (MLCInitReply *)buf;
333
334       if ((stat != 0) || (pReply->cmd != (0x80 | MLC_INIT)) || (pReply->result != 0))
335       {
336          if (errno == EIO && cnt<1)
337          {
338             /* hack for usblp.c 2.6.5 */
339             BUG("invalid MLCInitReply retrying...\n");
340             sleep(1);   
341             cnt++;
342             continue;
343          }
344          if (stat == 2 && cnt<1)
345          {
346             /* hack for Tahoe */
347             BUG("invalid MLCInitReply retrying command...\n");
348             memset(buf, 0, sizeof(MLCInit));
349             n = sizeof(MLCInit);
350             pCmd->h.length = htons(n);
351             pCmd->cmd = MLC_INIT;
352             pCmd->rev = 3;
353             (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT);
354             cnt++;
355             continue;
356          }
357          BUG("invalid MLCInitReply: cmd=%x, result=%x\n, revision=%x\n", pReply->cmd, pReply->result, pReply->rev);
358          stat = 1;
359          goto bugout;
360       }
361       break;
362    }
363
364 bugout:
365    return stat;
366 }
367
368 int __attribute__ ((visibility ("hidden"))) MlcExit(mud_channel *pc, int fd)
369 {
370    mud_device *pd = &msp->device[pc->dindex];
371    unsigned char buf[HPMUD_BUFFER_SIZE];
372    int stat=0, len, n;
373    MLCExit *pCmd;
374    MLCExitReply *pReply;
375
376    memset(buf, 0, sizeof(MLCExit));
377    pCmd = (MLCExit *)buf;
378    n = sizeof(MLCExit);
379    pCmd->h.length = htons(n);
380    pCmd->cmd = MLC_EXIT;
381    
382    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
383    {
384       BUG("unable to write MLCExit: %m\n");
385       stat = 1;
386       goto bugout;
387    }
388
389    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
390    pReply = (MLCExitReply *)buf;
391
392    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_EXIT)) || (pReply->result != 0))
393    {
394       BUG("invalid MLCExitReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
395       stat = 1;
396       goto bugout;
397    }
398
399 bugout:
400    return stat;
401 }
402
403 int __attribute__ ((visibility ("hidden"))) MlcConfigSocket(mud_channel *pc, int fd)
404 {
405    mud_device *pd = &msp->device[pc->dindex];
406    unsigned char buf[HPMUD_BUFFER_SIZE];
407    int stat=0, len, n;
408    MLCConfigSocket *pCmd;
409    MLCConfigSocketReply *pReply;
410
411    if (pc->ta.h2psize > 0)
412      return stat;   /* already got host/peripheral packet sizes */
413
414    memset(buf, 0, sizeof(MLCConfigSocket));
415    pCmd = (MLCConfigSocket *)buf;
416    n = sizeof(MLCConfigSocket);
417    pCmd->h.length = htons(n);
418    pCmd->cmd = MLC_CONFIG_SOCKET;
419    pCmd->socket = pc->sockid;
420    pCmd->h2psize = htons(HPMUD_BUFFER_SIZE);
421    pCmd->p2hsize = htons(HPMUD_BUFFER_SIZE);
422    pCmd->status = 0;   /* status level?? */
423    
424    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
425    {
426       BUG("unable to write MLCConfigSocket: %m\n");
427       stat = 1;
428       goto bugout;
429    }
430
431    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
432    pReply = (MLCConfigSocketReply *)buf;
433
434    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CONFIG_SOCKET)) || (pReply->result != 0))
435    {
436       BUG("invalid MLCConfigSocketReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
437       stat = 1;
438       goto bugout;
439    }
440
441    pc->ta.h2psize = ntohs(pReply->h2psize);
442    pc->ta.p2hsize = ntohs(pReply->p2hsize);
443
444 bugout:
445    return stat;
446 }
447
448 /* Write data to peripheral. */
449 int __attribute__ ((visibility ("hidden"))) MlcForwardData(mud_channel *pc, int fd, const void *buf, int size, int usec_timeout)
450 {
451    mud_device *pd = &msp->device[pc->dindex];
452    int stat=0, len, n;
453    MLCHeader h;
454
455    memset(&h, 0, sizeof(h));
456    n = sizeof(MLCHeader) + size;
457    h.length = htons(n);
458    h.hsid = pc->sockid;
459    h.psid = pc->sockid;
460       
461    if ((len = (pd->vf.write)(fd, &h, sizeof(MLCHeader),  usec_timeout)) != sizeof(MLCHeader))
462    {
463       BUG("unable to write MlcForwardData header: %m\n");
464       stat = 1;
465       goto bugout;
466    }
467
468    if ((len = (pd->vf.write)(fd, buf, size, usec_timeout)) != size)
469    {
470       BUG("unable to write MlcForwardData: %m\n");
471       stat = 1;
472       goto bugout;
473    }
474
475 bugout:
476    return stat;
477 }
478
479 /* Read data from peripheral. */
480 int __attribute__ ((visibility ("hidden"))) MlcReverseData(mud_channel *pc, int fd, void *buf, int length, int usec_timeout)
481 {
482    mud_device *pd = &msp->device[pc->dindex];
483    mud_channel *out_of_bound_channel;
484    int len, size, total;
485    MLCHeader *pPk;
486
487    pPk = (MLCHeader *)buf;
488
489    while (1)
490    {
491       total = 0;
492
493       /* Read packet header. */
494       size = sizeof(MLCHeader);
495       while (size > 0)
496       {
497          /* Use requested client timeout until we start reading. */
498          if (total == 0)
499             len = (pd->vf.read)(fd, buf+total, size, usec_timeout);
500          else
501             len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT);
502
503          if (len < 0)
504          {
505             /* Got a timeout, if exception timeout or timeout occured after read started thats an error. */
506             if (usec_timeout >= HPMUD_EXCEPTION_TIMEOUT || total > 0)
507                BUG("unable to read MlcReverseData header: %m %s\n", pd->uri);
508             goto bugout;
509          }
510          size-=len;
511          total+=len;
512       }
513
514       /* Determine data size. */
515       size = ntohs(pPk->length) - sizeof(MLCHeader);
516
517       if (size > length)
518       {
519          BUG("invalid MlcReverseData size: size=%d, buf=%d\n", size, length);
520          goto bugout;
521       } 
522
523       /* Make sure data packet is for this channel. */
524       if (pPk->hsid != pc->sockid && pPk->psid != pc->sockid)
525       {
526          if (pPk->hsid == 0 && pPk->psid == 0)
527          {
528             /* Ok, got a command channel packet instead of a data packet, handle it... */
529             while (size > 0)
530             {
531                if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
532                {
533                   BUG("unable to read MlcReverseData command: %m\n");
534                   goto bugout;
535                }
536                size-=len;
537                total=len;
538             }
539             MlcExecReverseCmd(pc, fd, buf);
540             continue;   /* try again for data packet */
541          }
542          else if (pPk->hsid == pPk->psid)
543          {
544             /* Got a valid data packet for another channel handle it. This can happen when ReadData timeouts and p2hcredit=1. */
545             out_of_bound_channel = &pd->channel[pPk->hsid];
546             unsigned char *pBuf;
547
548             if (out_of_bound_channel->ta.p2hcredit <= 0)
549             {
550                BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
551                goto bugout;
552             }
553
554             if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
555             {
556                BUG("invalid data packet size=%d\n", size);
557                goto bugout;
558             }
559             
560             total = 0;
561             pBuf = &out_of_bound_channel->rbuf[out_of_bound_channel->rcnt];
562             while (size > 0)
563             {
564                if ((len = (pd->vf.read)(fd, pBuf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
565                {
566                   BUG("unable to read MlcReverseData: %m\n");
567                   goto bugout;
568                }
569                size-=len;
570                total+=len;
571             }
572
573             out_of_bound_channel->rcnt += total;
574             if (pPk->credit)
575                out_of_bound_channel->ta.h2pcredit += pPk->credit;  /* note, piggy back credit is 1 byte wide */ 
576             out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
577             continue;   /* try again for data packet */
578          }
579          else
580          {
581             MLCCmd *pCmd = (MLCCmd *)buf;
582             BUG("invalid MlcReverseData state: exp hsid=%x, act hsid=%x, psid=%x, length=%d, credit=%d, status=%x, cmd=%x\n", pc->sockid, 
583                                                 pPk->hsid, pPk->psid, ntohs(pPk->length), pPk->credit, pPk->status, pCmd->cmd);
584             goto bugout;
585          }
586       }
587
588       if (pPk->credit)
589       {
590          pc->ta.h2pcredit += pPk->credit;  /* note, piggy back credit is 1 byte wide */ 
591       }
592
593       total = 0;  /* eat packet header */
594    
595       /* Read packet data field with exception_timeout. */
596       while (size > 0)
597       {
598          if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
599          {
600             BUG("unable to read MlcReverseData: %m\n");
601             goto bugout;
602          }
603          size-=len;
604          total+=len;
605       }
606       break; /* done reading data packet */
607    }  /* while (1) */
608
609 bugout:
610    return total;
611 }
612
613 int __attribute__ ((visibility ("hidden"))) MlcOpenChannel(mud_channel *pc, int fd)
614 {
615    mud_device *pd = &msp->device[pc->dindex];
616    unsigned char buf[HPMUD_BUFFER_SIZE];
617    int stat=0, len, n;
618    MLCOpenChannel *pCmd;
619    MLCOpenChannelReply *pReply;
620
621    memset(buf, 0, sizeof(MLCOpenChannel));
622    pCmd = (MLCOpenChannel *)buf;
623    n = sizeof(MLCOpenChannel);
624    pCmd->h.length = htons(n);
625    pCmd->cmd = MLC_OPEN_CHANNEL;
626    pCmd->hsocket = pc->sockid;   /* assume static socket ids */    
627    pCmd->psocket = pc->sockid;
628    pCmd->credit = htons(0);             /* credit sender will accept from receiver (set by MlcDevice::ReadData) */
629    //   SetH2PCredit(0);                    /* initialize sender to receiver credit */
630    
631    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
632    {
633       BUG("unable to write MlcOpenChannel: %m\n");
634       stat = 1;
635       goto bugout;
636    }
637
638    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
639    pReply = (MLCOpenChannelReply *)buf;
640
641    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_OPEN_CHANNEL)) || (pReply->result != 0))
642    {
643       BUG("invalid MlcOpenChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
644       stat = 1;
645       goto bugout;
646    }
647
648    pc->ta.h2pcredit = ntohs(pReply->credit);
649
650 bugout:
651    return stat;
652 }
653
654 int __attribute__ ((visibility ("hidden"))) MlcCloseChannel(mud_channel *pc, int fd)
655 {
656    mud_device *pd = &msp->device[pc->dindex];
657    unsigned char buf[HPMUD_BUFFER_SIZE];
658    int stat=0, len, n;
659    MLCCloseChannel *pCmd;
660    MLCCloseChannelReply *pReply;
661
662    memset(buf, 0, sizeof(MLCCloseChannel));
663    pCmd = (MLCCloseChannel *)buf;
664    n = sizeof(MLCCloseChannel);
665    pCmd->h.length = htons(n);
666    pCmd->cmd = MLC_CLOSE_CHANNEL;
667    pCmd->hsocket = pc->sockid;   /* assume static socket ids */    
668    pCmd->psocket = pc->sockid;
669    
670    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
671    {
672       BUG("unable to write MlcCloseChannel: %m\n");
673       stat = 1;
674       goto bugout;
675    }
676
677    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
678    pReply = (MLCCloseChannelReply *)buf;
679
680    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CLOSE_CHANNEL)) || (pReply->result != 0))
681    {
682       BUG("invalid MlcCloseChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
683       stat = 1;
684       goto bugout;
685    }
686
687 bugout:
688    return stat;
689 }
690
691 int __attribute__ ((visibility ("hidden"))) MlcCredit(mud_channel *pc, int fd, unsigned short credit)
692 {
693    mud_device *pd = &msp->device[pc->dindex];
694    unsigned char buf[HPMUD_BUFFER_SIZE];
695    int stat=0, len, n;
696    MLCCredit *pCmd;
697    MLCCreditReply *pReply;
698
699    memset(buf, 0, sizeof(MLCCredit));
700    pCmd = (MLCCredit *)buf;
701    n = sizeof(MLCCredit);
702    pCmd->h.length = htons(n);
703    pCmd->cmd = MLC_CREDIT;
704    pCmd->hsocket = pc->sockid;   /* assume static socket ids */    
705    pCmd->psocket = pc->sockid;
706    pCmd->credit = htons(credit);                /* set peripheral to host credit */
707    
708    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
709    {
710       BUG("unable to write MlcCredit: %m\n");
711       stat = 1;
712       goto bugout;
713    }
714
715    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
716    pReply = (MLCCreditReply *)buf;
717
718    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT)) || (pReply->result != 0))
719    {
720       BUG("invalid MlcCreditReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
721       stat = 1;
722       goto bugout;
723    }
724
725    pc->ta.p2hcredit += credit;
726
727 bugout:
728    return stat;
729 }
730
731 int __attribute__ ((visibility ("hidden"))) MlcCreditRequest(mud_channel *pc, int fd, unsigned short credit)
732 {
733    mud_device *pd = &msp->device[pc->dindex];
734    unsigned char buf[HPMUD_BUFFER_SIZE];
735    int stat=0, len, n;
736    MLCCreditRequest *pCmd;
737    MLCCreditRequestReply *pReply;
738
739    memset(buf, 0, sizeof(MLCCreditRequest));
740    pCmd = (MLCCreditRequest *)buf;
741    n = sizeof(MLCCreditRequest);
742    pCmd->h.length = htons(n);
743    pCmd->cmd = MLC_CREDIT_REQUEST;
744    pCmd->hsocket = pc->sockid;   /* assume static socket ids */    
745    pCmd->psocket = pc->sockid;
746    pCmd->credit = htons(credit);                /* request host to peripheral credit */
747    
748    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
749    {
750       BUG("unable to write MlcCreditRequest: %m\n");
751       stat = 1;
752       goto bugout;
753    }
754
755    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
756    pReply = (MLCCreditRequestReply *)buf;
757
758    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT_REQUEST)) || (pReply->result != 0))
759    {
760       BUG("invalid MlcCreditRequestReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
761       stat = 1;
762       goto bugout;
763    }
764
765    pc->ta.h2pcredit += ntohs(pReply->credit);
766
767 bugout:
768    return stat;
769 }
770
771
772