Clean up bitbanging layer. Add debug printfs.
[fw/altos] / ccdbg-io.c
1 /*
2  * Copyright © 2008 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ccdbg.h"
20
21 void
22 ccdbg_quarter_clock(struct ccdbg *dbg)
23 {
24         usleep(CC_CLOCK_US / 4);
25 }
26
27 void
28 ccdbg_half_clock(struct ccdbg *dbg)
29 {
30         usleep(CC_CLOCK_US / 2);
31 }
32
33 struct ccdbg *
34 ccdbg_open(char *file)
35 {
36         struct ccdbg *dbg;
37
38         dbg = calloc(sizeof (struct ccdbg), 1);
39         if (!dbg) {
40                 perror("calloc");
41                 return NULL;
42         }
43         dbg->clock = 1;
44 #ifdef USE_KERNEL
45         dbg->fd = open(file, 2);
46         if (dbg->fd < 0) {
47                 perror(file);
48                 free(dbg);
49                 return NULL;
50         }
51         cccp_init(dbg);
52         cccp_write(dbg, CC_CLOCK, CC_CLOCK);
53 #else
54         cp_usb_init(dbg);
55 #endif
56         dbg->clock = 1;
57         return dbg;
58 }
59
60 void
61 ccdbg_close(struct ccdbg *dbg)
62 {
63 #if USE_KERNEL
64         cccp_fini(dbg);
65         close (dbg->fd);
66 #else
67         cp_usb_fini(dbg);
68 #endif
69         free (dbg);
70 }
71
72 int
73 ccdbg_write(struct ccdbg *dbg, uint8_t mask, uint8_t value)
74 {
75 #if USE_KERNEL
76         return cccp_write(dbg, mask, value);
77 #else
78         cp_usb_write(dbg, mask, value);
79         return 0;
80 #endif
81 }
82
83 uint8_t
84 ccdbg_read(struct ccdbg *dbg)
85 {
86 #if USE_KERNEL
87         return cccp_read_all(dbg);
88 #else
89         return cp_usb_read(dbg);
90 #endif
91 }
92
93 static char
94 is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit)
95 {
96         if (mask&bit) {
97                 if (get&bit)
98                         return on;
99                 else
100                         return '.';
101         } else
102                 return '-';
103 }
104 void
105 ccdbg_print(char *format, uint8_t mask, uint8_t set)
106 {
107         ccdbg_debug (CC_DEBUG_BITBANG, format,
108                      is_bit(set, mask, 'C', CC_CLOCK),
109                      is_bit(set, mask, 'D', CC_DATA),
110                      is_bit(set, mask, 'R', CC_RESET_N));
111 }
112
113 void
114 ccdbg_send(struct ccdbg *dbg, uint8_t mask, uint8_t set)
115 {
116         ccdbg_write(dbg, mask, set);
117         ccdbg_print("%c %c %c\n", mask, set);
118         ccdbg_half_clock(dbg);
119 }
120
121 void
122 ccdbg_send_bit(struct ccdbg *dbg, uint8_t bit)
123 {
124         if (bit) bit = CC_DATA;
125         ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N);
126         ccdbg_send(dbg, CC_CLOCK|CC_DATA|CC_RESET_N,          bit|CC_RESET_N);
127 }
128
129 void
130 ccdbg_send_byte(struct ccdbg *dbg, uint8_t byte)
131 {
132         int bit;
133         ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte);
134         for (bit = 7; bit >= 0; bit--) {
135                 ccdbg_send_bit(dbg, (byte >> bit) & 1);
136                 if (bit == 3)
137                         ccdbg_debug(CC_DEBUG_BITBANG, "\n");
138         }
139 }
140
141 void
142 ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes)
143 {
144         while (nbytes--)
145                 ccdbg_send_byte(dbg, *bytes++);
146 }
147
148 uint8_t
149 ccdbg_recv_bit(struct ccdbg *dbg, int first)
150 {
151         uint8_t mask = first ? CC_DATA : 0;
152         uint8_t read;
153
154         ccdbg_send(dbg, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N);
155         read = ccdbg_read(dbg);
156         ccdbg_send(dbg, CC_CLOCK|     CC_RESET_N,                  CC_RESET_N);
157         return (read & CC_DATA) ? 1 : 0;
158 }
159
160 uint8_t
161 ccdbg_recv_byte(struct ccdbg *dbg, int first)
162 {
163         uint8_t byte = 0;
164         int     bit;
165
166         ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n");
167         for (bit = 0; bit < 8; bit++) {
168                 byte = byte << 1;
169                 byte |= ccdbg_recv_bit(dbg, first);
170                 if (bit == 3)
171                         ccdbg_debug(CC_DEBUG_BITBANG, "\n");
172                 first = 0;
173         }
174         ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte);
175         return byte;
176 }
177
178 void
179 ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes)
180 {
181         int first = 1;
182         while (nbytes--) {
183                 *bytes++ = ccdbg_recv_byte(dbg, first);
184                 first = 0;
185         }
186 }
187
188 void
189 ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len)
190 {
191         int     i;
192         ccdbg_send_byte(dbg, cmd);
193         for (i = 0; i < len; i++)
194                 ccdbg_send_byte(dbg, data[i]);
195 }
196
197 uint8_t
198 ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len)
199 {
200         uint8_t byte[1];
201         ccdbg_cmd_write(dbg, cmd, data, len);
202         ccdbg_recv_bytes(dbg, byte, 1);
203         return byte[0];
204 }
205
206 uint16_t
207 ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len)
208 {
209         uint8_t byte[2];
210         ccdbg_cmd_write(dbg, cmd, data, len);
211         ccdbg_recv_bytes(dbg, byte, 2);
212         return (byte[0] << 8) | byte[1];
213 }