Tizen 2.1 base
[platform/upstream/hplip.git] / io / hpmud / pp.c
1 /*****************************************************************************\
2
3   pp.c - parallel port support for multi-point transport 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   Client/Server generic message format (see messaging-protocol.doc):
24
25 \*****************************************************************************/
26
27 #ifdef HAVE_PPORT
28
29 #include "hpmud.h"
30 #include "hpmudi.h"
31
32 mud_device_vf __attribute__ ((visibility ("hidden"))) pp_mud_device_vf = 
33 {
34    .read = pp_read,
35    .write = pp_write,
36    .open = pp_open,
37    .close = pp_close,
38    .get_device_id = pp_get_device_id,
39    .get_device_status = pp_get_device_status,
40    .channel_open = pp_channel_open,
41    .channel_close = pp_channel_close,
42    .channel_write = musb_channel_write,
43    .channel_read = musb_channel_read
44 };
45
46 static mud_channel_vf pp_raw_channel_vf =
47 {
48    .open = pp_raw_channel_open,
49    .close = pp_raw_channel_close,
50    .channel_write = musb_raw_channel_write,
51    .channel_read = musb_raw_channel_read
52 };
53
54 static mud_channel_vf pp_mlc_channel_vf =
55 {
56    .open = pp_mlc_channel_open,
57    .close = pp_mlc_channel_close,
58    .channel_write = musb_mlc_channel_write,
59    .channel_read = musb_mlc_channel_read
60 };
61
62 static mud_channel_vf pp_dot4_channel_vf =
63 {
64    .open = pp_dot4_channel_open,
65    .close = pp_dot4_channel_close,
66    .channel_write = musb_dot4_channel_write,
67    .channel_read = musb_dot4_channel_read
68 };
69
70 static int frob_control(int fd, unsigned char mask, unsigned char val)
71 {
72    struct ppdev_frob_struct frob;
73
74    /* Convert ieee1284 control values to PC-style (invert Strobe, AutoFd and Select) . */
75    frob.val = val ^ (mask & (PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT));
76
77    frob.mask = mask;
78    return ioctl(fd, PPFCONTROL, &frob);
79 }
80
81 static unsigned char read_status(int fd)
82 {
83    unsigned char status;
84    if (ioctl(fd, PPRSTATUS, &status))
85       BUG("read_status error: %m\n");
86    
87    /* Convert PC-style status values to ieee1284 (invert Busy). */
88    return (status ^ PARPORT_STATUS_BUSY); 
89
90
91 static int wait_status(int fd, unsigned char mask, unsigned char val, int usec)
92 {
93    struct timeval tmo, now;
94    struct timespec min;
95    unsigned char status;
96    int cnt=0;
97    
98    gettimeofday (&tmo, NULL);
99    tmo.tv_usec += usec;
100    tmo.tv_sec += tmo.tv_usec / 1000000;
101    tmo.tv_usec %= 1000000;
102
103    min.tv_sec = 0;
104    min.tv_nsec = 5000000;  /* 5ms */
105
106    while (1)
107    {
108       status = read_status(fd);
109       if ((status & mask) == val)
110       {
111         //         bug("found status=%x mask=%x val=%x cnt=%d: %s %d\n", status, mask, val, cnt, __FILE__, __LINE__);
112          return 0;
113       } 
114       cnt++;
115       //      nanosleep(&min, NULL);
116       gettimeofday(&now, NULL);
117       if ((now.tv_sec > tmo.tv_sec) || (now.tv_sec == tmo.tv_sec && now.tv_usec > tmo.tv_usec))
118       {
119          DBG("wait_status timeout status=%x mask=%x val=%x us=%d\n", status, mask, val, usec);
120          return -1;   /* timeout */
121       }
122    }
123 }
124
125 static int wait(int usec)
126 {
127    struct timeval tmo, now;
128    int cnt=0;
129    
130    gettimeofday (&tmo, NULL);
131    tmo.tv_usec += usec;
132    tmo.tv_sec += tmo.tv_usec / 1000000;
133    tmo.tv_usec %= 1000000;
134
135    while (1)
136    {
137       cnt++;
138       gettimeofday(&now, NULL);
139       if ((now.tv_sec > tmo.tv_sec) || (now.tv_sec == tmo.tv_sec && now.tv_usec > tmo.tv_usec))
140       {
141          return 0;   /* timeout */
142       }
143    }
144 }
145
146 static int ecp_is_fwd(int fd)
147 {
148    unsigned char status;
149
150    status = read_status(fd);
151    if ((status & PARPORT_STATUS_PAPEROUT) == PARPORT_STATUS_PAPEROUT)
152       return 1;
153    return 0;
154 }
155
156 static int ecp_is_rev(int fd)
157 {
158    unsigned char status;
159
160    status = read_status(fd);
161    if ((status & PARPORT_STATUS_PAPEROUT) == 0)
162       return 1;
163    return 0;
164 }
165
166 static int ecp_rev_to_fwd(int fd)
167 {
168    int dir=0;
169
170    if (ecp_is_fwd(fd))
171       return 0;
172
173    /* Event 47: write NReverseRequest/nInit=1 */
174    frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
175
176    /* Event 48: wait PeriphClk/nAck=1, PeriphAck/Busy=0 */
177    //   wait_status(fd, PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_BUSY, PARPORT_STATUS_PAPEROUT, SIGNAL_TIMEOUT);
178
179    /* Event 49: wait nAckReverse/PError=1 */
180    wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
181
182    ioctl(fd, PPDATADIR, &dir);
183
184    return 0;
185 }
186
187 static int ecp_fwd_to_rev(int fd)
188 {
189    int dir=1;
190
191    if (ecp_is_rev(fd))
192       return 0;
193
194    /* Event 33: NPeriphRequest/nFault=0, PeriphAck/Busy=0 */
195    wait_status(fd, PARPORT_STATUS_BUSY | PARPORT_STATUS_ERROR, 0, PP_DEVICE_TIMEOUT);
196
197    /* Event 38: write HostAck/nAutoFd=0 */
198    ioctl(fd, PPDATADIR, &dir);
199    frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
200    wait(PP_SETUP_TIMEOUT);
201    
202    /* Event 39: write NReverseRequest/nInit=0 (start bus reversal) */
203    frob_control(fd, PARPORT_CONTROL_INIT, 0);
204
205    /* Event 40: wait nAckReverse/PError=0 */
206    wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
207
208    return 0;
209 }
210
211 static int ecp_write_addr(int fd, unsigned char data)
212 {
213    int cnt=0, len=0;
214    unsigned d=(data | 0x80); /* set channel address bit */
215
216    ecp_rev_to_fwd(fd);
217
218    /* Event 33: PeriphAck/Busy=0 */
219    if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_SIGNAL_TIMEOUT))
220    {
221       BUG("ecp_write_addr transfer stalled\n"); 
222       goto bugout;
223    }
224
225    while (1)
226    {   
227       /* Event 34: write HostAck/nAutoFD=0 (channel command), data */
228       frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
229       ioctl(fd, PPWDATA, &d);
230
231       /* Event 35: write HostClk/NStrobe=0 */
232       frob_control(fd, PARPORT_CONTROL_STROBE, 0);
233
234       /* Event 36: wait PeriphAck/Busy=1 */
235       if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
236       {
237
238          /* Event 72: write NReverseRequest/nInit=0 (Host Transfer Recovery) */
239          frob_control(fd, PARPORT_CONTROL_INIT, 0);
240
241          /* Event 73: wait nAckReverse/PError=0 */
242          wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
243
244          /* Event 74: write NReverseRequest/nInit=1 */
245          frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
246
247          /* Event 75: wait nAckReverse/PError=1 */
248          wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
249
250          cnt++;
251          if (cnt > 4)
252          {
253             BUG("ecp_write_addr transfer stalled\n"); 
254             goto bugout;
255          }
256          BUG("ecp_write_addr host transfer recovery cnt=%d\n", cnt); 
257          continue;  /* retry */
258       }
259       break;  /* done */
260    } /* while (1) */
261
262    len = 1;
263       
264 bugout:
265
266    /* Event 37: write HostClk/NStrobe=1 */
267    frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
268
269    return len;
270 }
271
272 static int ecp_write_data(int fd, unsigned char data)
273 {
274    int cnt=0, len=0;
275
276    //   ecp_rev_to_fwd(fd);
277
278    /* Event 33: check PeriphAck/Busy=0 */
279    if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_SIGNAL_TIMEOUT))
280    {
281       BUG("ecp_write_data transfer stalled\n"); 
282       goto bugout;
283    }
284
285    while (1)
286    {   
287       /* Event 34: write HostAck/nAutoFD=1 (channel data), data */
288       frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
289       ioctl(fd, PPWDATA, &data);
290
291       /* Event 35: write HostClk/NStrobe=0 */
292       frob_control(fd, PARPORT_CONTROL_STROBE, 0);
293
294       /* Event 36: wait PeriphAck/Busy=1 */
295       if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
296       {
297
298          /* Event 72: write NReverseRequest/nInit=0 (Host Transfer Recovery) */
299          frob_control(fd, PARPORT_CONTROL_INIT, 0);
300
301          /* Event 73: wait nAckReverse/PError=0 */
302          wait_status(fd, PARPORT_STATUS_PAPEROUT, 0, PP_SIGNAL_TIMEOUT);
303
304          /* Event 74: write NReverseRequest/nInit=1 */
305          frob_control(fd, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
306
307          /* Event 75: wait nAckReverse/PError=1 */
308          wait_status(fd, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT, PP_SIGNAL_TIMEOUT);
309
310          cnt++;
311          if (cnt > 4)
312          {
313             BUG("ecp_write_data transfer stalled\n"); 
314             goto bugout;
315          }
316          BUG("ecp_write_data host transfer recovery cnt=%d\n", cnt); 
317          continue;  /* retry */
318       }
319       break;  /* done */
320    } /* while (1) */
321
322    len = 1;
323       
324 bugout:
325
326    /* Event 37: write HostClk/NStrobe=1 */
327    frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
328
329    return len;
330 }
331
332 static int ecp_read_data(int fd, unsigned char *data)
333 {
334    int len=0;
335
336    //   ecp_fwd_to_rev(fd);
337
338    /* Event 43: wait PeriphClk/NAck=0 */
339    if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
340    {
341       len = -1;
342       goto bugout;
343    }
344    ioctl(fd, PPRDATA, data);
345
346    /* Event 44: write HostAck/nAutoFd=1 */
347    frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
348
349    /* Event 45: wait PeriphClk/NAck=1 */
350    wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
351
352    /* Event 46: write HostAck/nAutoFd=0 */
353    frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
354
355    len = 1;
356       
357 bugout:
358
359    return len;
360 }
361
362 static int ecp_read(int fd, void *buffer, int size, int usec)
363 {
364    int i=0;
365    unsigned char *p = (unsigned char *)buffer;
366    
367    ecp_fwd_to_rev(fd);
368
369    while (i < size)
370    {
371       if (ecp_read_data(fd, p+i) != 1)
372       {
373          usec-=PP_SIGNAL_TIMEOUT;
374          if (usec > 0)
375             continue;
376
377 //         return -1;
378          return -ETIMEDOUT;   /* timeout */
379       }
380       i++;
381    }
382    return i;
383 }
384
385 static int ecp_write(int fd, const void *buffer, int size)
386 {
387    int i;
388    unsigned char *p = (unsigned char *)buffer;
389    static int timeout=0;
390
391    if (timeout)
392    {
393       timeout=0;
394       return -1;        /* report timeout */
395    }
396    
397    ecp_rev_to_fwd(fd);
398
399    for (i=0; i < size; i++)
400    {
401       if (ecp_write_data(fd, p[i]) != 1)
402       {
403          if (i)
404             timeout=1;  /* save timeout, report bytes written */
405          else
406             i=-1;       /* report timeout */
407          break;
408       }
409    }
410    return i;
411 }
412
413 static int nibble_read_data(int fd, unsigned char *data)
414 {
415    int len=0;
416    unsigned char nibble;   
417
418    /* Event 7: write HostBusy/nAutoFd=0 */
419    frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
420
421    /* Event 8: peripheral sets low-order nibble. */
422
423    /* Event 9: wait PtrClk/NAck=0 */
424    if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
425    {
426       len = -1;
427       goto bugout;
428    }
429    nibble = read_status(fd) >> 3;
430    nibble = ((nibble & 0x10) >> 1) | (nibble & 0x7);
431    *data = nibble;
432
433    /* Event 10: write HostBusy/nAutoFd=1 */
434    frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
435
436    /* Event 11: wait PtrClk/NAck=1 */
437    wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
438
439    /* Event 7: write HostBusy/nAutoFd=0 */
440    frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
441
442    /* Event 8: peripheral sets high-order nibble. */
443
444    /* Event 9: wait PtrClk/NAck=0 */
445    if (wait_status(fd, PARPORT_STATUS_ACK, 0, PP_SIGNAL_TIMEOUT))
446    {
447       len = -1;
448       goto bugout;
449    }
450    nibble = read_status(fd) >> 3;
451    nibble = ((nibble & 0x10) >> 1) | (nibble & 0x7);
452    *data |= (nibble<<4);
453
454    /* Event 10: write HostBusy/nAutoFd=1 */
455    frob_control(fd, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD);
456
457    /* Event 11: wait PtrClk/NAck=1 */
458    wait_status(fd, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK, PP_SIGNAL_TIMEOUT);
459
460    len = 1;
461       
462 bugout:
463
464    return len;
465 }
466
467 static int nibble_read(int fd, int flag, void *buffer, int size, int usec)
468 {
469    int i=0;
470    unsigned char *p = (unsigned char *)buffer;
471    int m = IEEE1284_MODE_NIBBLE | flag;
472    int mc = IEEE1284_MODE_COMPAT;
473    unsigned char status;
474
475    ioctl (fd, PPNEGOT, &mc);
476    if (ioctl (fd, PPNEGOT, &m))
477    {
478       DBG("nibble_read negotiation failed: %m\n");
479       return -1;
480    }
481
482    while (i < size)
483    {
484       if (nibble_read_data(fd, p+i) != 1)
485       {
486          usec-=PP_SIGNAL_TIMEOUT;
487          if (usec > 0)
488             continue;
489
490 //         return -1;
491          return -ETIMEDOUT;   /* timeout */
492       }
493
494       i++;
495
496       /* More data? */
497       status = read_status(fd);
498       if (status & PARPORT_STATUS_ERROR)
499       {
500          /* Event 7: write HostBusy/nAutoFd=0, idle phase */
501          frob_control(fd, PARPORT_CONTROL_AUTOFD, 0);
502          
503          break;  /* done */
504       }
505    }
506
507    return i;
508 }
509
510 static int compat_write_data(int fd, unsigned char data)
511 {
512    int len=0;
513
514    /* wait Busy=0 */
515    if (wait_status(fd, PARPORT_STATUS_BUSY, 0, PP_DEVICE_TIMEOUT))
516    {
517       BUG("compat_write_data transfer stalled\n"); 
518       goto bugout;
519    }
520
521    ioctl(fd, PPWDATA, &data);
522    wait(PP_SETUP_TIMEOUT);
523
524    /* write NStrobe=0 */
525    frob_control(fd, PARPORT_CONTROL_STROBE, 0);
526
527    /* wait Busy=1 */
528    if (wait_status(fd, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, PP_SIGNAL_TIMEOUT))
529    {
530       BUG("compat_write_data transfer stalled\n"); 
531       goto bugout;
532    }
533
534    /* write nStrobe=1 */
535    frob_control(fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
536
537    len = 1;
538       
539 bugout:
540    return len;
541 }
542
543 static int compat_write(int fd, const void *buffer, int size)
544 {
545    int i=0;
546    unsigned char *p = (unsigned char *)buffer;
547    int m = IEEE1284_MODE_COMPAT;
548    static int timeout=0;
549
550    if (timeout)
551    {
552       timeout=0;
553       return -1;        /* report timeout */
554    }
555
556    if (ioctl(fd, PPNEGOT, &m))
557    {
558       BUG("compat_write failed: %m\n");
559       goto bugout;
560    }
561
562    for (i=0; i < size; i++)
563    {
564       if (compat_write_data(fd, p[i]) != 1)
565       {
566          if (i)
567             timeout=1;  /* save timeout, report bytes written */
568          else
569             i=-1;       /* report timeout */
570          break;
571       }
572    }
573
574 bugout:
575    return i;
576 }
577
578 static int claim_pp(int fd)
579 {
580    int stat=1;
581
582    /* Claim parallel port (can block forever). */
583    if (ioctl(fd, PPCLAIM))
584    {
585       BUG("failed claim_pp fd=%d: %m\n", fd);
586       goto bugout;
587    }
588
589    DBG("claimed pp fd=%d\n", fd);
590
591    stat=0;
592
593 bugout:
594    return stat;   
595 }
596
597 static int release_pp(int fd)
598 {
599    int stat=1, m=IEEE1284_MODE_COMPAT;
600
601    /* Restore compat_mode (default), otherwise close(fd) may block restoring compat_mode. */
602    if (ioctl(fd, PPNEGOT, &m))
603    {
604       BUG("failed release_pp fd=%d: %m\n", fd);
605       goto bugout;
606    }
607
608    ioctl(fd, PPRELEASE);
609
610    DBG("released pp fd=%d\n", fd);
611
612    stat=0;
613
614 bugout:
615    return 0;
616 }
617
618 static int device_id(int fd, char *buffer, int size)
619 {
620    int len=0, maxSize;
621
622    maxSize = (size > 1024) ? 1024 : size;   /* RH8 has a size limit for device id */
623
624    len = nibble_read(fd, IEEE1284_DEVICEID, buffer, maxSize, 0);
625    if (len < 0)
626    {
627       BUG("unable to read device-id ret=%d\n", len);
628       len = 0;
629       goto bugout;
630    }
631    if (len > (size-1))
632       len = size-1;   /* leave byte for zero termination */
633    if (len > 2)
634       len -= 2;
635    memcpy(buffer, buffer+2, len);    /* remove length */
636    buffer[len]=0;
637
638    DBG("read actual device_id successfully fd=%d len=%d\n", fd, len);
639
640 bugout:
641    return len; /* length does not include zero termination */
642 }
643
644 static int device_status(int fd, unsigned int *status)
645 {
646    int m, stat=1;
647    unsigned char byte = NFAULT_BIT;        /* set default */
648
649    m = IEEE1284_MODE_COMPAT;
650    if (ioctl (fd, PPNEGOT, &m))
651    {
652       BUG("unable to read device_status: %m\n");
653       stat = HPMUD_R_IO_ERROR;
654       goto bugout;
655    }
656    byte = read_status(fd);
657
658    *status = (unsigned int)byte;
659    stat = 0;
660    DBG("read actual device_status successfully fd=%d\n", fd);
661
662 bugout:
663    return stat; 
664 }
665
666 /* Create channel object given the requested socket id and service name. */
667 static int new_channel(mud_device *pd, int index, const char *sn)
668 {
669    int stat=1;
670
671    /* Check for existing name service already open. */
672    if (pd->channel[index].client_cnt)
673    {
674 #if 0
675       if (index == HPMUD_EWS_CHANNEL)
676       {
677          pd->channel[index].client_cnt++;  /* allow multiple clients for separate USB interfaces only */
678          stat = 0;
679          DBG("reused %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
680       }
681       else
682 #endif
683          BUG("%s channel=%d is busy, used by [%d], clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].pid, pd->channel[index].client_cnt, pd->channel_cnt);
684       goto bugout; 
685    }
686
687    if (pd->io_mode == HPMUD_RAW_MODE || pd->io_mode == HPMUD_UNI_MODE)
688       pd->channel[index].vf = pp_raw_channel_vf;
689    else if (pd->io_mode == HPMUD_MLC_GUSHER_MODE || pd->io_mode == HPMUD_MLC_MISER_MODE)
690       pd->channel[index].vf = pp_mlc_channel_vf;
691    else
692       pd->channel[index].vf = pp_dot4_channel_vf;
693
694    pd->channel[index].index = index;
695    pd->channel[index].client_cnt = 1;
696    pd->channel[index].sockid = index;   /* static socket id is valid for MLC but not 1284.4 */
697    pd->channel[index].pid = getpid();
698    pd->channel[index].dindex = pd->index;
699    pd->channel[index].fd = -1;
700    strcpy(pd->channel[index].sn, sn);
701    pd->channel_cnt++;
702
703    stat = 0;
704    DBG("new %s channel=%d clientCnt=%d channelCnt=%d\n", sn, index, pd->channel[index].client_cnt, pd->channel_cnt);
705
706 bugout:
707    return stat;
708 }
709
710 /* Remove channel object given the channel decriptor. */
711 static int del_channel(mud_device *pd, mud_channel *pc)
712 {
713    pc->client_cnt--;
714
715    if (pc->client_cnt <= 0)
716    {
717       pd->channel_cnt--;
718    }
719    DBG("removed %s channel=%d clientCnt=%d channelCnt=%d\n", pc->sn, pc->index, pc->client_cnt, pd->channel_cnt);
720    return 0;
721 }
722
723 /*********************************************************************************************************************************
724  * Parallel port mud_device functions.
725  */
726
727 int __attribute__ ((visibility ("hidden"))) pp_write(int fd, const void *buf, int size, int usec)
728 {
729    int len=0, m;
730
731    ioctl(fd, PPGETMODE, &m);
732
733    if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
734    {
735       len = ecp_write(fd, buf, size);
736    }
737    else
738    {  
739       len = compat_write(fd, buf, size);
740    }
741
742    DBG("write fd=%d len=%d size=%d\n", fd, len, size);
743    DBG_DUMP(buf, len < 32 ? len : 32);
744
745    return len;
746 }
747
748 int __attribute__ ((visibility ("hidden"))) pp_read(int fd, void *buf, int size, int usec)
749 {
750    int len=0, m;
751 //   int sec = usec/1000000;
752
753    ioctl(fd, PPGETMODE, &m);
754
755    if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
756    {  
757       len = ecp_read(fd, buf, size, usec);
758    }
759    else
760    {
761       len = nibble_read(fd, 0, buf, size, usec);
762    }
763
764    DBG("read fd=%d len=%d size=%d usec=%d\n", fd, len, size, usec);
765    DBG_DUMP(buf, len < 32 ? len : 32);
766
767    return len;
768 }
769
770 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_open(mud_device *pd)
771 {
772    char dev[255], uriModel[128], model[128];
773    int len, m, fd;
774    enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
775
776    pthread_mutex_lock(&pd->mutex);
777
778    hpmud_get_uri_model(pd->uri, uriModel, sizeof(uriModel));
779
780    if (pd->id[0] == 0)
781    {
782       /* First client, open actual kernal device, use blocking i/o. */
783       hpmud_get_uri_datalink(pd->uri, dev, sizeof(dev));
784       if ((fd = open(dev, O_RDWR | O_NOCTTY)) < 0)            
785       {
786          BUG("unable to open %s: %m\n", pd->uri);
787          goto bugout;
788       }
789
790       /* Open can succeed with no connected device, see if this is a valid device. */
791       if (ioctl(fd, PPGETMODES, &m))
792       {
793          BUG("unable to open %s: %m\n", pd->uri);
794          goto bugout;
795       }
796
797       /* Claim parallel port (can block forever). */
798       if (claim_pp(fd))
799          goto bugout;
800
801       len = device_id(fd, pd->id, sizeof(pd->id));  /* get new copy and cache it  */ 
802
803       if (len > 0 && is_hp(pd->id))
804          power_up(pd, fd);
805
806       release_pp(fd);
807
808       if (len == 0)
809          goto bugout;
810
811       pd->open_fd = fd;
812    }
813
814    /* Make sure uri model matches device id model. */
815    hpmud_get_model(pd->id, model, sizeof(model));
816    if (strcmp(uriModel, model) != 0)
817    {
818       stat = HPMUD_R_INVALID_DEVICE_NODE;  /* probably a laserjet, or different device plugged in */  
819       BUG("invalid model %s != %s\n", uriModel, model);
820       goto bugout;
821    }
822
823    stat = HPMUD_R_OK;
824
825 bugout:
826    pthread_mutex_unlock(&pd->mutex);
827    return stat;
828 }
829
830 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_close(mud_device *pd)
831 {
832    enum HPMUD_RESULT stat = HPMUD_R_OK;
833
834    pthread_mutex_lock(&pd->mutex);
835
836    if (pd->open_fd >=0)
837       close(pd->open_fd);
838
839    pd->open_fd = -1;
840    pd->id[0] = 0;
841
842    pthread_mutex_unlock(&pd->mutex);
843
844    return stat;
845 }
846
847 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_id(mud_device *pd, char *buf, int size, int *len)
848 {
849    int m, fd = pd->open_fd;
850    enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
851    
852    *len=0;
853
854    pthread_mutex_lock(&pd->mutex);
855
856    if (fd < 0)
857    {
858       stat = HPMUD_R_INVALID_STATE;
859       BUG("invalid get_device_id state\n");
860       goto bugout;
861    }
862
863    if (pd->io_mode == HPMUD_UNI_MODE)
864    {
865       *len = strlen(pd->id);  /* use cached copy */
866       DBG("using cached device_id io_mode=%d\n", pd->io_mode);
867    }
868    else
869    {
870       ioctl(fd, PPGETMODE, &m);
871       if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
872       {
873          *len = strlen(pd->id);  /* channel is busy, return cached copy. */
874          DBG("using cached device_id m=%x\n", m);
875       }
876       else
877       {
878          if (pd->channel_cnt == 0)
879          {
880             /* Device not in use. Claim it, but release for other processes. */
881             if (claim_pp(fd))
882                goto bugout;
883             *len = device_id(fd, pd->id, sizeof(pd->id));  /* get new copy */
884             release_pp(fd);
885          }
886          else
887          {
888             /* Device already claimed by open_channel. */
889             *len = device_id(fd, pd->id, sizeof(pd->id));  /* get new copy */
890          }
891       }
892    }
893
894    if (*len)
895    {
896       memcpy(buf, pd->id, *len > size ? size : *len); 
897       stat = HPMUD_R_OK;
898    }
899
900 bugout:
901    pthread_mutex_unlock(&pd->mutex);
902    return stat;
903 }
904
905 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_get_device_status(mud_device *pd, unsigned int *status)
906 {
907    int fd=pd->open_fd;
908    enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
909    int m, r=0;
910
911    pthread_mutex_lock(&pd->mutex);
912
913    if (fd < 0)
914    {
915       stat = HPMUD_R_INVALID_STATE;
916       BUG("invalid get_device_id state\n");
917       goto bugout;
918    }
919
920    if (pd->io_mode == HPMUD_UNI_MODE)
921    {
922       *status = NFAULT_BIT;   /* fake status */
923       DBG("using cached device_status io_mode=%d\n", pd->io_mode);
924    }
925    else
926    {
927       ioctl(fd, PPGETMODE, &m);
928       if (m & (IEEE1284_MODE_ECPSWE | IEEE1284_MODE_ECP))
929       {
930          *status = NFAULT_BIT;        /* channel is busy, fake 8-bit status */
931          DBG("using cached device_status m=%x\n", m);
932       }
933       else
934       {
935          if (pd->channel_cnt == 0)
936          {
937             /* Device not in use. Claim it, but release for other processes. */
938             if (claim_pp(fd))
939                goto bugout;
940             r = device_status(fd, status);
941             release_pp(fd);
942          }
943          else
944          {
945             /* Device already claimed by open_channel. */
946             r = device_status(fd, status);
947          }
948       }
949    }
950
951    if (r != 0)
952       goto bugout;
953     
954    stat = HPMUD_R_OK;
955
956 bugout:
957    pthread_mutex_unlock(&pd->mutex);
958    return stat;
959 }
960
961 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_open(mud_device *pd, const char *sn, HPMUD_CHANNEL *cd)
962 {
963    int index;
964    enum HPMUD_RESULT stat = HPMUD_R_DEVICE_BUSY;
965
966    /* Check for valid service requests. */
967    if ((stat = service_to_channel(pd, sn, &index)) != HPMUD_R_OK)
968       goto bugout;
969
970    pthread_mutex_lock(&pd->mutex);
971
972    if (new_channel(pd, index, sn))
973    {
974       stat = HPMUD_R_DEVICE_BUSY;
975    }
976    else
977    {
978       if ((stat = (pd->channel[index].vf.open)(&pd->channel[index])) != HPMUD_R_OK)  /* call transport specific open */
979          del_channel(pd, &pd->channel[index]);   /* open failed, cleanup */
980       else
981          *cd = index;
982    }
983
984    pthread_mutex_unlock(&pd->mutex);
985
986 bugout:
987    return stat;
988 }
989
990 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_channel_close(mud_device *pd, mud_channel *pc)
991 {
992    enum HPMUD_RESULT stat = HPMUD_R_OK;
993
994    pthread_mutex_lock(&pd->mutex);
995    stat = (pc->vf.close)(pc);      /* call trasport specific close */
996    del_channel(pd, pc);
997    pthread_mutex_unlock(&pd->mutex);
998
999    return stat;
1000 }
1001
1002 /*******************************************************************************************************************************
1003  * Parallel port raw_channel functions.
1004  */
1005
1006 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_open(mud_channel *pc)
1007 {
1008    mud_device *pd = &msp->device[pc->dindex];
1009    if (claim_pp(pd->open_fd))
1010       return HPMUD_R_IO_ERROR;
1011    pc->fd = pd->open_fd;
1012    return HPMUD_R_OK;
1013 }
1014
1015 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_raw_channel_close(mud_channel *pc)
1016 {
1017    if (pc->fd >= 0)
1018       release_pp(pc->fd);
1019    pc->fd = -1;
1020    return HPMUD_R_OK;
1021 }
1022
1023 /*******************************************************************************************************************************
1024  * Parallel port mlc_channel functions.
1025  */
1026
1027 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_open(mud_channel *pc)
1028 {
1029    mud_device *pd = &msp->device[pc->dindex];
1030    enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
1031    int i, m;
1032
1033    /* Initialize MLC transport if this is the first MLC channel. */
1034    if (pd->channel_cnt==1)
1035    {
1036       if (claim_pp(pd->open_fd))
1037          goto bugout;
1038
1039       /* Negotiate ECP mode. */
1040       m = IEEE1284_MODE_ECPSWE;
1041       if (ioctl(pd->open_fd, PPNEGOT, &m)) 
1042       {
1043          BUG("unable to negotiate %s ECP mode: %m\n", pd->uri);
1044          goto bugout;
1045       }
1046
1047       /* Enable MLC mode with ECP channel-77. */
1048       ecp_write_addr(pd->open_fd, 78);
1049       ecp_write(pd->open_fd, "\0", 1);
1050       ecp_write_addr(pd->open_fd, 77);
1051
1052       /* MLC initialize */
1053       if (MlcInit(pc, pd->open_fd) != 0)
1054          goto bugout;
1055
1056       /* Reset transport attributes for all channels. */
1057       for (i=0; i<HPMUD_CHANNEL_MAX; i++)
1058          memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
1059
1060       pd->mlc_fd = pd->open_fd;
1061       pd->mlc_up=1;
1062
1063    } /* if (pDev->ChannelCnt==1) */
1064  
1065    if (MlcConfigSocket(pc, pd->mlc_fd))
1066       goto bugout;
1067
1068    if (MlcOpenChannel(pc, pd->mlc_fd))
1069       goto bugout;
1070
1071    pc->rcnt = pc->rindex = 0;
1072
1073    stat = HPMUD_R_OK;
1074
1075 bugout:
1076    return stat;  
1077 }
1078
1079 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_mlc_channel_close(mud_channel *pc)
1080 {
1081    mud_device *pd = &msp->device[pc->dindex];
1082    enum HPMUD_RESULT stat = HPMUD_R_OK;
1083    int m;
1084
1085    if (pd->mlc_up)
1086    {
1087       if (MlcCloseChannel(pc, pd->mlc_fd))
1088          stat = HPMUD_R_IO_ERROR;
1089    }
1090
1091    /* Remove MLC transport if this is the last MLC channel. */
1092    if (pd->channel_cnt==1)
1093    {
1094       if (pd->mlc_up)
1095       {
1096          if (MlcExit(pc, pd->mlc_fd))
1097             stat = HPMUD_R_IO_ERROR;
1098       }
1099       pd->mlc_up=0;
1100
1101       ecp_write_addr(pd->mlc_fd, 78);     /* disable MLC mode with ECP channel-78 */
1102       ecp_write(pd->mlc_fd, "\0", 1);
1103
1104       m = IEEE1284_MODE_NIBBLE;
1105       ioctl(pd->mlc_fd, PPNEGOT, &m);
1106       release_pp(pd->mlc_fd);
1107
1108       /* Delay for batch scanning. */
1109       sleep(1);
1110    }
1111
1112    return stat;
1113 }
1114
1115 /*******************************************************************************************************************************
1116  * Parallel port dot4_channel functions.
1117  */
1118
1119 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_open(mud_channel *pc)
1120 {
1121    mud_device *pd = &msp->device[pc->dindex];
1122    enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
1123    int i, m;
1124
1125    /* Initialize MLC transport if this is the first MLC channel. */
1126    if (pd->channel_cnt==1)
1127    {
1128       if (claim_pp(pd->open_fd))
1129          goto bugout;
1130
1131       /* Negotiate ECP mode. */
1132       m = IEEE1284_MODE_ECPSWE;
1133       if (ioctl(pd->open_fd, PPNEGOT, &m)) 
1134       {
1135          BUG("unable to negotiate %s ECP mode: %m\n", pd->uri);
1136          goto bugout;
1137       }
1138
1139       /* Enable MLC mode with ECP channel-77. */
1140       ecp_write_addr(pd->open_fd, 78);
1141       ecp_write(pd->open_fd, "\0", 1);
1142       ecp_write_addr(pd->open_fd, 77);
1143
1144       /* DOT4 initialize */
1145       if (Dot4Init(pc, pd->open_fd) != 0)
1146          goto bugout;
1147
1148       /* Reset transport attributes for all channels. */
1149       for (i=0; i<HPMUD_CHANNEL_MAX; i++)
1150          memset(&pd->channel[i].ta, 0 , sizeof(transport_attributes));
1151
1152       pd->mlc_fd = pd->open_fd;
1153       pd->mlc_up=1;
1154
1155    } /* if (pDev->ChannelCnt==1) */
1156
1157    if (Dot4GetSocket(pc, pd->mlc_fd))
1158       goto bugout;
1159
1160    if (Dot4OpenChannel(pc, pd->mlc_fd))
1161       goto bugout;
1162
1163    pc->rcnt = pc->rindex = 0;
1164
1165    stat = HPMUD_R_OK;
1166
1167 bugout:
1168    return stat;  
1169 }
1170
1171 enum HPMUD_RESULT __attribute__ ((visibility ("hidden"))) pp_dot4_channel_close(mud_channel *pc)
1172 {
1173    mud_device *pd = &msp->device[pc->dindex];
1174    enum HPMUD_RESULT stat = HPMUD_R_OK;
1175    int m;
1176
1177    if (pd->mlc_up)
1178    {
1179       if (Dot4CloseChannel(pc, pd->mlc_fd))
1180          stat = HPMUD_R_IO_ERROR;
1181    }
1182
1183    /* Remove MLC transport if this is the last MLC channel. */
1184    if (pd->channel_cnt==1)
1185    {
1186       if (pd->mlc_up)
1187       {
1188          if (Dot4Exit(pc, pd->mlc_fd))
1189             stat = HPMUD_R_IO_ERROR;
1190       }
1191       pd->mlc_up=0;
1192
1193       ecp_write_addr(pd->mlc_fd, 78);     /* disable MLC mode with ECP channel-78 */
1194       ecp_write(pd->mlc_fd, "\0", 1);
1195
1196       m = IEEE1284_MODE_NIBBLE;
1197       ioctl(pd->mlc_fd, PPNEGOT, &m);
1198       release_pp(pd->mlc_fd);
1199
1200       /* Delay for batch scanning. */
1201       sleep(1);
1202    }
1203
1204    return stat;
1205 }
1206
1207 /*******************************************************************************************************************************
1208  * Parallel port probe devices, walk the parallel port bus(s) looking for HP products.
1209  */
1210
1211 int __attribute__ ((visibility ("hidden"))) pp_probe_devices(char *lst, int lst_size, int *cnt)
1212 {
1213    struct hpmud_model_attributes ma;
1214    char dev[HPMUD_LINE_SIZE];
1215    char rmodel[128];
1216    char model[128];
1217    char id[1024];
1218    int i, size=0, fd, m;
1219
1220    for (i=0; i < 4; i++)
1221    {
1222       sprintf(dev, "/dev/parport%d", i);
1223
1224       if ((fd = open(dev, O_RDONLY | O_NOCTTY)) < 0)            
1225          continue;
1226
1227       /* Silently check the port for valid device (no syslog errors). */
1228       if (ioctl(fd, PPGETMODES, &m) == 0)
1229       {
1230          if (claim_pp(fd) == 0)
1231          {
1232             if (device_id(fd, id, sizeof(id)) > 0 && is_hp(id))
1233             {
1234                hpmud_get_model(id, model, sizeof(model));
1235                hpmud_get_raw_model(id, rmodel, sizeof(rmodel));
1236                snprintf(dev, sizeof(dev), "hp:/par/%s?device=/dev/parport%d", model, i);
1237
1238                /* See if device is supported by hplip. */
1239                hpmud_query_model(dev, &ma); 
1240                if (ma.support != HPMUD_SUPPORT_TYPE_HPLIP)
1241                {
1242                   BUG("ignoring %s support=%d\n", dev, ma.support);
1243                   continue;           /* ignor, not supported */
1244                }
1245
1246                if (strncasecmp(rmodel, "hp ", 3) == 0)
1247                   size += sprintf(lst+size,"direct %s \"HP %s\" \"HP %s LPT parport%d HPLIP\" \"%s\"\n", dev, &rmodel[3], &rmodel[3], i, id);
1248                else
1249                   size += sprintf(lst+size,"direct %s \"HP %s\" \"HP %s LPT parport%d HPLIP\" \"%s\"\n", dev, rmodel, rmodel, i, id);
1250                *cnt+=1;
1251             }
1252             release_pp(fd);
1253          }
1254          else
1255          {
1256             BUG("unable to probe %s: %m\n", dev);  /* device is busy */
1257          }
1258       }
1259       close(fd);
1260    }
1261    return size;
1262 }
1263
1264 enum HPMUD_RESULT hpmud_make_par_uri(const char *dnode, char *uri, int uri_size, int *bytes_read)
1265 {
1266    char model[128];
1267    char id[1024];
1268    enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
1269    int fd=-1, m;
1270
1271    DBG("[%d] hpmud_make_par_uri() dnode=%s\n", getpid(), dnode);
1272
1273    *bytes_read=0;
1274
1275    uri[0]=0;
1276
1277    if ((fd = open(dnode, O_RDONLY | O_NOCTTY)) < 0) 
1278    {
1279       BUG("unable to open %s: %m\n", dnode);           
1280       goto bugout;
1281    }
1282
1283    if (ioctl(fd, PPGETMODES, &m))
1284    {
1285       BUG("unable to make uri %s: %m\n", dnode);
1286       goto bugout;
1287    }
1288
1289    if (claim_pp(fd))
1290    {
1291       BUG("unable to make uri %s: %m\n", dnode);  /* device is busy */
1292       goto bugout;
1293    }
1294
1295    if (device_id(fd, id, sizeof(id)) > 0 && is_hp(id))
1296    {
1297       hpmud_get_model(id, model, sizeof(model));
1298       *bytes_read = snprintf(uri, uri_size, "hp:/par/%s?device=%s", model, dnode);
1299    }
1300    release_pp(fd);
1301
1302    stat = HPMUD_R_OK;
1303
1304 bugout:
1305    if (fd >= 0)
1306       close(fd);
1307    return stat;
1308 }
1309
1310 #endif /* HAVE_PPORT */