5e3d963b |
1 | #include <stdio.h> |
2 | #include <fcntl.h> |
3 | #include <errno.h> |
4 | #include <string.h> |
5 | #include <unistd.h> |
6 | #include <inttypes.h> |
7 | #include <sys/types.h> |
8 | #include <sys/ioctl.h> |
9 | #include <linux/parport.h> |
10 | #include <linux/ppdev.h> |
11 | #include "usb-driver.h" |
12 | #include "parport.h" |
13 | |
14 | static int parportfd = -1; |
15 | |
25ba7a49 |
16 | int parport_transfer(WD_TRANSFER *tr, int fd, unsigned int request, int ppbase, int ecpbase, int num) { |
5e3d963b |
17 | int ret = 0; |
18 | int i; |
19 | unsigned long port; |
20 | unsigned char val; |
21 | static unsigned char last_pp_write = 0; |
22 | |
23 | for (i = 0; i < num; i++) { |
24 | DPRINTF("dwPort: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n", |
25 | (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes, |
26 | tr[i].fAutoinc, tr[i].dwOptions); |
27 | |
28 | port = (unsigned long)tr[i].dwPort; |
29 | val = tr[i].Data.Byte; |
30 | |
31 | #ifdef DEBUG |
32 | if (tr[i].cmdTrans == 13) |
33 | DPRINTF("write byte: %d\n", val); |
34 | #endif |
35 | |
36 | if (parportfd < 0) |
37 | return ret; |
38 | |
39 | if (port == ppbase + PP_DATA) { |
40 | DPRINTF("data port\n"); |
41 | switch(tr[i].cmdTrans) { |
42 | case PP_READ: |
43 | ret = 0; /* We don't support reading of the data port */ |
44 | break; |
45 | |
46 | case PP_WRITE: |
47 | ret = ioctl(parportfd, PPWDATA, &val); |
48 | last_pp_write = val; |
49 | break; |
50 | |
51 | default: |
52 | fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans); |
53 | ret = -1; |
54 | break; |
55 | } |
56 | } else if (port == ppbase + PP_STATUS) { |
57 | DPRINTF("status port (last write: %d)\n", last_pp_write); |
58 | switch(tr[i].cmdTrans) { |
59 | case PP_READ: |
60 | ret = ioctl(parportfd, PPRSTATUS, &val); |
61 | #ifdef FORCE_PC3_IDENT |
62 | val &= 0x5f; |
63 | if (last_pp_write & 0x40) |
64 | val |= 0x20; |
65 | else |
66 | val |= 0x80; |
67 | #endif |
68 | break; |
69 | |
70 | case PP_WRITE: |
71 | ret = 0; /* Status Port is readonly */ |
72 | break; |
73 | |
74 | default: |
75 | fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans); |
76 | ret = -1; |
77 | break; |
78 | } |
79 | } else if (port == ppbase + PP_CONTROL) { |
80 | DPRINTF("control port\n"); |
81 | switch(tr[i].cmdTrans) { |
82 | case PP_READ: |
83 | ret = ioctl(parportfd, PPRCONTROL, &val); |
84 | break; |
85 | |
86 | case PP_WRITE: |
87 | ret = ioctl(parportfd, PPWCONTROL, &val); |
88 | break; |
89 | |
90 | default: |
91 | fprintf(stderr,"!!!Unsupported TRANSFER command: %lu!!!\n", tr[i].cmdTrans); |
92 | ret = -1; |
93 | break; |
94 | } |
95 | } else if ((port == ecpbase + PP_ECP_CFGA) && ecpbase) { |
96 | DPRINTF("ECP_CFGA port\n"); |
97 | } else if ((port == ecpbase + PP_ECP_CFGB) && ecpbase) { |
98 | DPRINTF("ECP_CFGB port\n"); |
99 | } else if ((port == ecpbase + PP_ECP_ECR) && ecpbase) { |
100 | DPRINTF("ECP_ECR port\n"); |
101 | } else { |
102 | DPRINTF("access to unsupported address range!\n"); |
103 | ret = 0; |
104 | } |
105 | |
106 | tr[i].Data.Byte = val; |
107 | |
108 | DPRINTF("dwPortReturn: 0x%lx, cmdTrans: %lu, dwbytes: %ld, fautoinc: %ld, dwoptions: %ld\n", |
109 | (unsigned long)tr[i].dwPort, tr[i].cmdTrans, tr[i].dwBytes, |
110 | tr[i].fAutoinc, tr[i].dwOptions); |
111 | #ifdef DEBUG |
112 | if (tr[i].cmdTrans == 10) |
113 | DPRINTF("read byte: %d\n", tr[i].Data.Byte); |
114 | #endif |
115 | } |
116 | |
117 | return ret; |
118 | } |
119 | |
120 | int parport_open(int num) { |
121 | char ppdev[32]; |
122 | |
123 | if (parportfd < 0) { |
124 | snprintf(ppdev, sizeof(ppdev), "/dev/parport%u", num); |
125 | DPRINTF("opening %s\n", ppdev); |
126 | parportfd = open(ppdev, O_RDWR|O_EXCL); |
127 | |
128 | if (parportfd < 0) |
129 | fprintf(stderr,"Can't open %s: %s\n", ppdev, strerror(errno)); |
130 | } |
131 | |
132 | if (parportfd >= 0) { |
133 | int pmode; |
134 | |
135 | if (ioctl(parportfd, PPCLAIM) == -1) |
136 | return -1; |
137 | |
138 | pmode = IEEE1284_MODE_COMPAT; |
139 | if (ioctl(parportfd, PPNEGOT, &pmode) == -1) |
140 | return -1; |
141 | |
142 | #if 0 |
143 | if (cr->Card.dwItems > 1 && cr->Card.Item[1].I.IO.dwAddr) { |
144 | DPRINTF("ECP mode requested\n"); |
145 | ecpbase = (unsigned long)cr->Card.Item[1].I.IO.dwAddr; |
146 | /* TODO: Implement ECP mode */ |
147 | pmode = IEEE1284_MODE_ECP; |
148 | |
149 | if (ioctl(parportfd, PPNEGOT, &pmode) == -1) { |
150 | ecpbase = 0; |
151 | pmode = IEEE1284_MODE_COMPAT; |
152 | if (ioctl(parportfd, PPNEGOT, &pmode) == -1) |
153 | return ret; |
154 | } |
155 | } |
156 | #endif |
157 | } |
158 | |
159 | return parportfd; |
160 | } |
161 | |
162 | void parport_close(int handle) { |
163 | if (parportfd == handle && parportfd >= 0) { |
164 | ioctl(parportfd, PPRELEASE); |
165 | close(parportfd); |
166 | parportfd = -1; |
167 | } |
168 | } |