Typos. Mostly by Lintian
[dahdi/tools.git] / xpp / xtalk / xtalk_sync.c
1 /*
2  * Written by Oron Peled <oron@actcom.co.il>
3  * Copyright (C) 2009, Xorcom
4  *
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <arpa/inet.h>
29 #include <xtalk/debug.h>
30 #include <xtalk/proto_sync.h>
31 #include <autoconfig.h>
32 #include "xtalk_base.h"
33
34 #define DBG_MASK        0x02
35
36 /*
37  * Base XTALK device. A pointer to this struct
38  * should be included in the struct representing
39  * the dialect.
40  */
41 struct xtalk_sync {
42         struct xtalk_base       *xtalk_base;
43 };
44
45 CMD_DEF(XTALK, ACK,
46         uint8_t stat;
47         );
48
49 CMD_DEF(XTALK, PROTO_GET,
50         uint8_t proto_version;
51         uint8_t reserved;
52         );
53
54 CMD_DEF(XTALK, PROTO_GET_REPLY,
55         uint8_t proto_version;
56         uint8_t reserved;
57         );
58
59 union XTALK_PDATA(XTALK) {
60         MEMBER(XTALK, ACK);
61         MEMBER(XTALK, PROTO_GET);
62         MEMBER(XTALK, PROTO_GET_REPLY);
63 } PACKED members;
64
65 const struct xtalk_protocol     xtalk_sync_proto = {
66         .name   = "XTALK-SYNC",
67         .proto_version = 0,
68         .commands = {
69                 CMD_RECV(XTALK, ACK),
70                 CMD_SEND(XTALK, PROTO_GET),
71                 CMD_RECV(XTALK, PROTO_GET_REPLY),
72         },
73         .ack_statuses = {
74                 ACK_STAT(OK, "Acknowledges previous command"),
75                 ACK_STAT(FAIL, "Last command failed"),
76                 ACK_STAT(RESET_FAIL, "reset failed"),
77                 ACK_STAT(NODEST, "No destination is selected"),
78                 ACK_STAT(MISMATCH, "Data mismatch"),
79                 ACK_STAT(NOACCESS, "No access"),
80                 ACK_STAT(BAD_CMD, "Bad command"),
81                 ACK_STAT(TOO_SHORT, "Packet is too short"),
82                 ACK_STAT(ERROFFS, "Offset error (not used)"),
83                 ACK_STAT(NO_LEEPROM, "Large EEPROM was not found"),
84                 ACK_STAT(NO_EEPROM, "No EEPROM was found"),
85                 ACK_STAT(WRITE_FAIL, "Writing to device failed"),
86                 ACK_STAT(NOPWR_ERR, "No power on USB connector"),
87         }
88 };
89
90 struct xtalk_sync *xtalk_sync_new(struct xtalk_base *xtalk_base)
91 {
92         struct xtalk_sync *xtalk_sync;
93         int ret;
94
95         assert(xtalk_base);
96         xtalk_sync = calloc(1, sizeof(*xtalk_sync));
97         if (!xtalk_sync) {
98                 ERR("Allocating XTALK device memory failed\n");
99                 return NULL;
100         }
101         xtalk_sync->xtalk_base = xtalk_base;
102         ret = xtalk_set_protocol(xtalk_sync->xtalk_base, &xtalk_sync_proto, NULL);
103         if (ret < 0) {
104                 ERR("GLOBAL Protocol registration failed: %d\n", ret);
105                 goto err;
106         }
107         DBG("%s: xtalk_sync=%p\n", __func__, xtalk_sync);
108         return xtalk_sync;
109 err:
110         xtalk_sync_delete(xtalk_sync);
111         return NULL;
112 }
113
114 void xtalk_sync_delete(struct xtalk_sync *xtalk_sync)
115 {
116         if (xtalk_sync) {
117                 memset(xtalk_sync, 0, sizeof(*xtalk_sync));
118                 free(xtalk_sync);
119         }
120 }
121
122 int xtalk_sync_set_protocol(struct xtalk_sync *xtalk_sync,
123                 const struct xtalk_protocol *xproto)
124 {
125         return xtalk_set_protocol(xtalk_sync->xtalk_base, &xtalk_sync_proto, xproto);
126 }
127
128 __attribute__((warn_unused_result))
129 int process_command(
130         struct xtalk_sync *xtalk_sync,
131         struct xtalk_command *cmd,
132         struct xtalk_command **reply_ref,
133         uint16_t *tx_seq)
134 {
135         struct xtalk_base *xtalk_base;
136         const struct xtalk_protocol     *xproto;
137         struct xtalk_command            *reply = NULL;
138         const struct xtalk_command_desc *reply_desc;
139         const struct xtalk_command_desc *expected;
140         const struct xtalk_command_desc *cmd_desc;
141         uint8_t                         reply_op;
142         const char                      *protoname;
143         int                             ret;
144         xtalk_cmd_callback_t            callback;
145
146         xtalk_base = xtalk_sync->xtalk_base;
147         xproto = &xtalk_base->xproto;
148         protoname = (xproto) ? xproto->name : "GLOBAL";
149         /* So the caller knows if a reply was received */
150         if (reply_ref)
151                 *reply_ref = NULL;
152         reply_op = cmd->header.op | XTALK_REPLY_MASK;
153         cmd_desc = get_command_desc(xproto, cmd->header.op);
154         expected = get_command_desc(xproto, reply_op);
155         ret = send_command(xtalk_base, cmd, tx_seq);
156         if (ret < 0) {
157                 ERR("send_command failed: %d\n", ret);
158                 goto out;
159         }
160         if (!reply_ref) {
161                 DBG("No reply requested\n");
162                 goto out;
163         }
164         ret = recv_command(xtalk_base, &reply);
165         if (ret <= 0) {
166                 DBG("recv_command failed (ret = %d)\n", ret);
167                 goto out;
168         }
169         *reply_ref = reply;
170         if ((reply->header.op & 0x80) != 0x80) {
171                 ERR("Unexpected reply op=0x%02X, should have MSB set.\n",
172                         reply->header.op);
173                 ret = -EPROTO;
174                 goto out;
175         }
176         reply_desc = get_command_desc(xproto, reply->header.op);
177         if (!reply_desc) {
178                 ERR("Unknown reply (proto=%s) op=0x%02X\n",
179                         protoname, reply->header.op);
180                 dump_packet(LOG_ERR, 0, __func__, (const char *)reply, ret);
181                 ret = -EPROTO;
182                 goto out;
183         }
184         DBG("REPLY OP: 0x%X [%s]\n", reply->header.op, reply_desc->name);
185         if (reply->header.op == XTALK_ACK) {
186                 uint8_t status = CMD_FIELD(reply, XTALK, ACK, stat);
187
188                 if (expected) {
189                         ERR("Expected OP=0x%02X: Got ACK(%d): %s\n",
190                                 reply_op,
191                                 status,
192                                 ack_status_msg(xproto, status));
193                         ret = -EPROTO;
194                         goto out;
195                 } else if (status != STAT_OK) {
196
197                         ERR("Got ACK (for OP=0x%X [%s]): %d %s\n",
198                                 cmd->header.op,
199                                 cmd_desc->name,
200                                 status, ack_status_msg(xproto, status));
201                         ret = -EPROTO;
202                         goto out;
203                 }
204                 /* Good expected ACK ... */
205         } else if (reply->header.op != reply_op) {
206                         ERR("Expected OP=0x%02X: Got OP=0x%02X\n",
207                                 reply_op, reply->header.op);
208                         ret = -EPROTO;
209                         goto out;
210         }
211         if (expected && expected->len > reply->header.len) {
212                         ERR("Expected len=%d: Got len=%d\n",
213                                 expected->len, reply->header.len);
214                         ret = -EPROTO;
215                         goto out;
216         }
217         if (cmd->header.seq != reply->header.seq) {
218                         ERR("Expected seq=%d: Got seq=%d\n",
219                                 cmd->header.seq, reply->header.seq);
220                         ret = -EPROTO;
221                         goto out;
222         }
223         /* Find if there is associated callback */
224         ret = xtalk_cmd_callback(xtalk_base, reply->header.op, NULL, &callback);
225         if (ret < 0) {
226                 ERR("Failed getting callback for op=0x%X\n", reply->header.op);
227                 goto out;
228         }
229         ret = reply->header.len;        /* All good, return the length */
230         DBG("got reply op 0x%X (%d bytes)\n", reply->header.op, ret);
231         if (callback) {
232                 /* Override return value with callback return value */
233                 ret = callback(xtalk_base, reply_desc, reply);
234                 DBG("%s: callback for 0x%X returned %d\n", __func__,
235                         reply->header.op, ret);
236         }
237 out:
238         free_command(cmd);
239         if (!reply_ref && reply)
240                 free_command(reply);
241         return ret;
242 }
243
244 /*
245  * Protocol Commands
246  */
247
248 int xtalk_proto_query(struct xtalk_sync *xtalk_sync)
249 {
250         struct xtalk_base *xtalk_base;
251         struct xtalk_command            *cmd;
252         struct xtalk_command            *reply;
253         uint8_t                         proto_version;
254         int                             ret;
255         uint16_t                        tx_seq;
256
257         DBG("\n");
258         assert(xtalk_sync != NULL);
259         xtalk_base = xtalk_sync->xtalk_base;
260         proto_version = xtalk_base->xproto.proto_version;
261         cmd = new_command(xtalk_base, XTALK_OP(XTALK, PROTO_GET), 0);
262         if (!cmd) {
263                 ERR("new_command failed\n");
264                 return -ENOMEM;
265         }
266         /* Protocol Version */
267         CMD_FIELD(cmd, XTALK, PROTO_GET, proto_version) = proto_version;
268         CMD_FIELD(cmd, XTALK, PROTO_GET, reserved) = 0; /* RESERVED */
269         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
270         if (ret < 0) {
271                 ERR("process_command failed: %d\n", ret);
272                 goto out;
273         }
274         xtalk_base->xtalk_proto_version =
275                 CMD_FIELD(reply, XTALK, PROTO_GET_REPLY, proto_version);
276         if (xtalk_base->xtalk_proto_version != proto_version) {
277                 DBG("Got %s protocol version: 0x%02x (expected 0x%02x)\n",
278                         xtalk_base->xproto.name,
279                         xtalk_base->xtalk_proto_version,
280                         proto_version);
281                 ret = xtalk_base->xtalk_proto_version;
282                 goto out;
283         }
284         DBG("Protocol version: %02x (tx_seq = %d)\n",
285                 xtalk_base->xtalk_proto_version, tx_seq);
286         ret = xtalk_base->xtalk_proto_version;
287 out:
288         free_command(reply);
289         return ret;
290 }